Java tutorial
/* * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.anyframe.iam.core.intercept.web; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import org.anyframe.exception.BaseException; import org.anyframe.iam.core.securedobject.ISecuredObjectService; import org.apache.commons.collections.ListUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.MessageSource; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.security.web.util.AntUrlPathMatcher; import org.springframework.security.web.util.UrlMatcher; /** * This class extends objectDefinitionSource of Spring Security. It offers a * function to treat role mapping of resources related with registered * Restricted Times * * @author Byunghun Woo * */ public class ReloadableRestrictedTimesFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource, InitializingBean, ApplicationContextAware { protected final Log logger = LogFactory.getLog(getClass()); private MessageSource messageSource; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.messageSource = (MessageSource) applicationContext.getBean("messageSource"); } protected MessageSource getMessageSource() { return messageSource; } private UrlMatcher urlMatcher; private boolean stripQueryStringFromUrls; public boolean isStripQueryStringFromUrls() { return stripQueryStringFromUrls; } public void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) { this.stripQueryStringFromUrls = stripQueryStringFromUrls; } public UrlMatcher getUrlMatcher() { return urlMatcher; } public void setUrlMatcher(UrlMatcher urlMatcher) { this.urlMatcher = urlMatcher; setStripQueryStringFromUrls(urlMatcher instanceof AntUrlPathMatcher); } private ISecuredObjectService securedObjectService; public void setSecuredObjectService(ISecuredObjectService securedObjectService) { this.securedObjectService = securedObjectService; } private List alwaysTimeRoleCheck; private List alwaysTimeResourceCheck; private Map dailyFilteredTimeRoleCheck; private Map dailyFilteredTimeResourceCheck; public List getAlwaysTimeRoleCheck() { return Collections.unmodifiableList(alwaysTimeRoleCheck); } public List getAlwaysTimeResourceCheck() { return Collections.unmodifiableList(alwaysTimeResourceCheck); } public Map getDailyFilteredTimeRoleCheck() { return Collections.unmodifiableMap(dailyFilteredTimeRoleCheck); } public Map getDailyFilteredTimeResourceCheck() { return Collections.unmodifiableMap(dailyFilteredTimeResourceCheck); } /** * This method is InitializingBean and executed as soon as this class runs. * This method only calls reloadRestrictedTimes. */ public void afterPropertiesSet() throws Exception { reloadRestrictedTimes(); } /** * Get restriction information of roles related time. crash/daily types will * be set alwaysTimeRoleCheck, other types will be * dailyFilteredTimeRoleCheck. * * @return Object[] Array of mapping information about restricted time and * role * @throws Exception fail to make list */ public Object[] getRestrictedTimesRoles() throws Exception { List alwaysTimeRoleCheck = new ArrayList(); Map dailyFilteredTimeRoleCheck = new LinkedHashMap(); List resultList = securedObjectService.getRestrictedTimesRoles(); Iterator itr = resultList.iterator(); Map tempMap = null; Map beforeMap = null; String beforeTimeId = null; String presentTimeType = null; String presentTimeId = null; boolean sameFlag = false; while (itr.hasNext()) { tempMap = (Map) itr.next(); presentTimeId = (String) tempMap.get("time_id"); sameFlag = (presentTimeId.equals(beforeTimeId) ? true : false); presentTimeType = (String) tempMap.get("time_type"); if ("crash".equals(presentTimeType) || "daily".equals(presentTimeType)) { // time_id ? role_id ??? if (sameFlag) { beforeMap = (Map) alwaysTimeRoleCheck.get(alwaysTimeRoleCheck.size() - 1); ((List) beforeMap.get("restrictedRoleIds")) .add(new SecurityConfig((String) tempMap.get("role_id"))); } else { List configList = new LinkedList(); configList.add(new SecurityConfig((String) tempMap.get("role_id"))); tempMap.put("restrictedRoleIds", configList); alwaysTimeRoleCheck.add(tempMap); } } else { String startDate = (String) tempMap.get("start_date"); String endDate = (String) tempMap.get("end_date"); String[] betweenDays = getBetweenDays(startDate, endDate); // ? time ? ??? ? ?? filtered ?? // ? for (int i = 0; i < betweenDays.length; i++) { // ? filtered ? ? ?? ? if (dailyFilteredTimeRoleCheck.containsKey(betweenDays[i])) { // ? time_id ? - Role add if (sameFlag) { List beforeFilteredList = (List) dailyFilteredTimeRoleCheck.get(betweenDays[i]); beforeMap = (Map) beforeFilteredList.get(beforeFilteredList.size() - 1); ((List) beforeMap.get("restrictedRoleIds")) .add(new SecurityConfig((String) tempMap.get("role_id"))); } else { // filtered ?? ? ? tempMap ? // List beforeFilteredList = (List) dailyFilteredTimeRoleCheck.get(betweenDays[i]); List configList = new LinkedList(); configList.add(new SecurityConfig((String) tempMap.get("role_id"))); tempMap.put("restrictedRoleIds", configList); beforeFilteredList.add(tempMap); } } else { // ? filtered List ? List filteredList = new ArrayList(); List configList = new LinkedList(); configList.add(new SecurityConfig((String) tempMap.get("role_id"))); tempMap.put("restrictedRoleIds", configList); filteredList.add(tempMap); dailyFilteredTimeRoleCheck.put(betweenDays[i], filteredList); } } } beforeTimeId = presentTimeId; } return new Object[] { alwaysTimeRoleCheck, dailyFilteredTimeRoleCheck }; } /** * Get restriction information of resources related with time. crash/daily * types will be set alwayTimeResourceCheck, other types will be set * dailyFilteredTimeResourceCheck * * @return Object[] Array of mapping information about restricted time and * role * @throws Exception fail to make list */ public Object[] getRestrictedTimesResources() throws Exception { List alwaysTimeResourceCheck = new ArrayList(); Map dailyFilteredTimeResourceCheck = new LinkedHashMap(); List resultList = securedObjectService.getRestrictedTimesResources(); Iterator itr = resultList.iterator(); Map tempMap = null; Map beforeMap = null; String beforeTimeResourceId = null; String presentTimeType = null; String presentTimeResourceId = null; boolean sameFlag = false; while (itr.hasNext()) { tempMap = (Map) itr.next(); presentTimeResourceId = (String) tempMap.get("time_id") + (String) tempMap.get("resource_id"); sameFlag = (presentTimeResourceId.equals(beforeTimeResourceId) ? true : false); presentTimeType = (String) tempMap.get("time_type"); if ("crash".equals(presentTimeType) || "daily".equals(presentTimeType)) { // ? id ? role_id ??? if (sameFlag) { if (tempMap.get("exclusion_role_id") != null) { beforeMap = (Map) alwaysTimeResourceCheck.get(alwaysTimeResourceCheck.size() - 1); ((List) beforeMap.get("unrestrictedRoleIds")) .add(new SecurityConfig((String) tempMap.get("exclusion_role_id"))); } } else { List configList = new LinkedList(); // ? ? Restricted Times ROLE ? ? - ?? // ROLE ? ? . configList .add(new SecurityConfig(RestrictedResourceHolder.RESTRICTED_TIMES_RESERVED_ROLE_NAME)); // Role ROLE ? Role ? // ? if (tempMap.get("exclusion_role_id") != null) { configList.add(new SecurityConfig((String) tempMap.get("exclusion_role_id"))); } tempMap.put("unrestrictedRoleIds", configList); tempMap.put("compiledResourcePattern", urlMatcher.compile((String) tempMap.get("resource_pattern"))); alwaysTimeResourceCheck.add(tempMap); } } else { String startDate = (String) tempMap.get("start_date"); String endDate = (String) tempMap.get("end_date"); String[] betweenDays = getBetweenDays(startDate, endDate); // ? time ? ??? ? ?? filtered ?? // ? for (int i = 0; i < betweenDays.length; i++) { // ? filtered ? ? ?? ? if (dailyFilteredTimeResourceCheck.containsKey(betweenDays[i])) { // ? id ? - Role add if (sameFlag) { if (tempMap.get("exclusion_role_id") != null) { List beforeFilteredList = (List) dailyFilteredTimeResourceCheck.get(betweenDays[i]); beforeMap = (Map) beforeFilteredList.get(beforeFilteredList.size() - 1); ((List) beforeMap.get("unrestrictedRoleIds")) .add(new SecurityConfig((String) tempMap.get("exclusion_role_id"))); } } else { // filtered ?? ? ? tempMap ? // List beforeFilteredList = (List) dailyFilteredTimeResourceCheck.get(betweenDays[i]); List configList = new LinkedList(); // ? ? Restricted Times ROLE ? ? - // ?? ROLE ? ? . configList.add(new SecurityConfig( RestrictedResourceHolder.RESTRICTED_TIMES_RESERVED_ROLE_NAME)); // Role ROLE ? Role ? // ? if (tempMap.get("exclusion_role_id") != null) { configList.add(new SecurityConfig((String) tempMap.get("exclusion_role_id"))); } tempMap.put("unrestrictedRoleIds", configList); tempMap.put("compiledResourcePattern", urlMatcher.compile((String) tempMap.get("resource_pattern"))); beforeFilteredList.add(tempMap); } } else { // ? filtered List ? List filteredList = new ArrayList(); List configList = new LinkedList(); // ? ? Restricted Times ROLE ? ? - // ?? ROLE ? ? . configList.add( new SecurityConfig(RestrictedResourceHolder.RESTRICTED_TIMES_RESERVED_ROLE_NAME)); // Role ROLE ? Role ? // ? if (tempMap.get("exclusion_role_id") != null) { configList.add(new SecurityConfig((String) tempMap.get("exclusion_role_id"))); } tempMap.put("unrestrictedRoleIds", configList); tempMap.put("compiledResourcePattern", urlMatcher.compile((String) tempMap.get("resource_pattern"))); filteredList.add(tempMap); dailyFilteredTimeResourceCheck.put(betweenDays[i], filteredList); } } } beforeTimeResourceId = presentTimeResourceId; } return new Object[] { alwaysTimeResourceCheck, dailyFilteredTimeResourceCheck }; } /** * Reset data into ConfigAttribute of Spring security * * @param timeCheckList List of Map includes information of always time * Check * @param configKey Map key about role that will be changed * ConfigAttribute */ public void listToConfig(List timeCheckList, String configKey) { Iterator iter = timeCheckList.iterator(); while (iter.hasNext()) { Map tempMap = (Map) iter.next(); // ?? Map ? betweendays ? ? day key ? ? ?. ? // ConfigAttribute ? skip if (!(tempMap.get(configKey) instanceof List<?>)) { tempMap.put(configKey, (List<ConfigAttribute>) tempMap.get(configKey)); } } } /** * Reset data into ConfigAttribute of Spring security * * @param dailyFilteredMap Map object that contains information of daily * filtered time Check * @param configKey Map key about role that will be changed * ConfigAttribute */ public void listToConfig(Map dailyFilteredMap, String configKey) { Iterator iter = dailyFilteredMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); List filteredList = (List) entry.getValue(); listToConfig(filteredList, configKey); } } /** * Reload mapping information of restricted times * * @throws BaseException fail to reload data */ public void reloadRestrictedTimes() throws BaseException { try { Object[] restrictedTimesRoles = getRestrictedTimesRoles(); Object[] restrictedTimesResources = getRestrictedTimesResources(); alwaysTimeRoleCheck = (List) restrictedTimesRoles[0]; dailyFilteredTimeRoleCheck = (Map) restrictedTimesRoles[1]; alwaysTimeResourceCheck = (List) restrictedTimesResources[0]; dailyFilteredTimeResourceCheck = (Map) restrictedTimesResources[1]; // ConfigAttribute - Collections.unmodifiableList // ( ) ? ? ? ? ? . listToConfig(alwaysTimeRoleCheck, "restrictedRoleIds"); listToConfig(dailyFilteredTimeRoleCheck, "restrictedRoleIds"); listToConfig(alwaysTimeResourceCheck, "unrestrictedRoleIds"); listToConfig(dailyFilteredTimeResourceCheck, "unrestrictedRoleIds"); if (logger.isInfoEnabled()) logger.info("reloadRestrictedTimes completed."); if (logger.isDebugEnabled()) { logger.debug("alwaysTimeRoleCheck : " + alwaysTimeRoleCheck); logger.debug("dailyFilteredTimeRoleCheck : " + dailyFilteredTimeRoleCheck); logger.debug("alwaysTimeResourceCheck : " + alwaysTimeResourceCheck); logger.debug("dailyFilteredTimeResourceCheck : " + dailyFilteredTimeResourceCheck); } } catch (Exception e) { logger.error(getMessageSource().getMessage( "[SecuredObject Service] SecuredObject Service [" + "Reload RestrictedTimes" + "]: Fail to get SecuredObject Data from Database.", new Object[] {}, Locale.getDefault()), e); if (e instanceof BaseException) { throw (BaseException) e; } else { throw new BaseException(getMessageSource(), "[SecuredObject Service] SecuredObject Service [" + e.getMessage() + "]: Fail to get SecuredObject Data from Database.", new Object[] {}, e); } } } /** * Return matched Role if current request URL matches mapping information of * restricted times resource * * @param map Map object that contains mapping information of restricted * times resource * @param url current request URL * @return null if url does not matches, List<ConfigAttribute> about * exclusion Role if URL matches */ private List<ConfigAttribute> checkUrlMatching(Map map, String url) { Object p = map.get("compiledResourcePattern"); boolean matched = urlMatcher.pathMatchesUrl(p, url); if (logger.isDebugEnabled()) { logger.debug("Restricted Times Candidate is: '" + url + "'; pattern is " + p + "; matched=" + matched); } if (matched) { return (List<ConfigAttribute>) map.get("unrestrictedRoleIds"); } return null; } /** * Get ConfigAttribute about Restricted/Allowed role list that * matches current date/time from Role/Resource mapping information of * restricted times * * @param compareCandidateList mapping information of restricted time - all * list if always checking mapping list about today date if dailyfiltered * checking * @param url request url * @param currentDateTime current date * @param currentTime current time * @param isTimeOnlyCheck true if only time checking * @param isRoleCheck (role or resource) true if role checking * @return List<ConfigAttribute> ConfigAttribute List */ public List<ConfigAttribute> lookupRoleOrUrlInCandidateListCheck(List compareCandidateList, String url, DateTime currentDateTime, DateTime currentTime, boolean isTimeOnlyCheck, boolean isRoleCheck) { List candidateFoundCadList = new ArrayList(); List<ConfigAttribute> foundCad = null; if (compareCandidateList == null) { if (logger.isDebugEnabled()) logger.debug("compareCandidateList is null"); return foundCad; } String beforeResourceId = null; String presentResourceId = null; Iterator iter = compareCandidateList.iterator(); while (iter.hasNext()) { Map map = (Map) iter.next(); String startDate = (String) map.get("start_date"); String endDate = (String) map.get("end_date"); String startTime = (String) map.get("start_time"); String endTime = (String) map.get("end_time"); DateTime startJodaTime = DateTimeFormat.forPattern("HHmmss").parseDateTime(startTime); DateTime endJodaTime = DateTimeFormat.forPattern("HHmmss").parseDateTime(endTime); DateTime startDateTime = null; DateTime endDateTime = null; boolean dailyExceed = false; boolean dailyExceedMatched = false; if (isTimeOnlyCheck) { if ("daily".equals((String) map.get("time_type"))) { // daily ? ?? if (startJodaTime.isAfter(endJodaTime.getMillis())) { dailyExceed = true; // dailyExceed ? ? <= currentTime <= ? // match ? if (!((endJodaTime.isBefore(currentTime.getMillis()) || endJodaTime.isEqual(currentTime.getMillis())) && (currentTime.isBefore(startJodaTime.getMillis()) || currentTime.isEqual(startJodaTime.getMillis())))) { dailyExceedMatched = true; } } else { startDateTime = DateTimeFormat.forPattern("yyyyMMddHHmmss") .parseDateTime(currentDateTime.toString("yyyyMMdd") + startTime); endDateTime = DateTimeFormat.forPattern("yyyyMMddHHmmss") .parseDateTime(currentDateTime.toString("yyyyMMdd") + endTime); } } else { // ?? always(crash) check ? ? ?? / ? // ? ??. startDateTime = DateTimeFormat.forPattern("yyyyMMddHHmmss") .parseDateTime(RestrictedResourceHolder.RESTRICTED_MIN_DATE + startTime); endDateTime = DateTimeFormat.forPattern("yyyyMMddHHmmss") .parseDateTime(RestrictedResourceHolder.RESTRICTED_MAX_DATE + endTime); } } else { // daily filtered check ? +? ? ? startDateTime = DateTimeFormat.forPattern("yyyyMMddHHmmss").parseDateTime(startDate + startTime); endDateTime = DateTimeFormat.forPattern("yyyyMMddHHmmss").parseDateTime(endDate + endTime); } // ? time_id ? ?? // dailyExceed ? ? ? ? ?. if ((dailyExceed && dailyExceedMatched) || (!dailyExceed && currentDateTime.isAfter(startDateTime.getMillis()) && endDateTime.isAfter(currentDateTime.getMillis()))) { presentResourceId = (String) map.get("resource_id"); // resource ? ? ? ? resource ? foundCad // resource ? ? ? foundCad ?? if (!isRoleCheck && foundCad != null && beforeResourceId != null && !presentResourceId.equals(beforeResourceId)) { // if (candidateFoundCadList.size() > 1) { return recalculateCandidate(isRoleCheck, candidateFoundCadList); } else { return foundCad; } } foundCad = (isRoleCheck ? (List<ConfigAttribute>) map.get("restrictedRoleIds") : checkUrlMatching(map, url)); if (foundCad != null) { // role check ? ?? role ? ? . // resource check ? ? resource ? time_id ? // ? // if (isRoleCheck || (beforeResourceId == null || presentResourceId.equals(beforeResourceId))) { candidateFoundCadList.add(foundCad); } } } else { // ? restricted data ? ? continue; } } // end while // best ? url ? ? time_id ? ? - // if (candidateFoundCadList.size() > 0) { foundCad = recalculateCandidate(isRoleCheck, candidateFoundCadList); } if (logger.isDebugEnabled()) logger.debug((isRoleCheck ? "Time Role Check" : "Time Resource Check") + " found ConfigAttribute : " + foundCad); return foundCad; } /** * in case of roleCheck, return sum of restricted roles in case of * resourceCheck, return result of re-operation with Intersection of allowed * roles * * @param isRoleCheck true if roleCheck * @param candidateFoundCadList list of candidate permissions that matches * the given time * @return List<ConfigAttribute> ConfigAttribute List */ private List<ConfigAttribute> recalculateCandidate(boolean isRoleCheck, List candidateFoundCadList) { List<ConfigAttribute> foundCad = new ArrayList<ConfigAttribute>(); List configList = null; List presentList = null; List nextList = null; for (int i = 0; i < candidateFoundCadList.size(); i++) { presentList = (List<ConfigAttribute>) candidateFoundCadList.get(i); if (i == 0) { configList = presentList; } if (i + 1 < candidateFoundCadList.size()) { nextList = (List<ConfigAttribute>) candidateFoundCadList.get(i + 1); // Role Check ? restricted Role ? add . if (isRoleCheck) { configList = ListUtils.sum(configList, nextList); } else { // Resource Check ? unrestricted Role ? // intersection configList = ListUtils.intersection(configList, nextList); } } } foundCad.addAll(configList); if (logger.isDebugEnabled()) logger.debug("candidateFoundCadList : " + candidateFoundCadList + (isRoleCheck ? ", summed List : " : ", intersected List : ") + foundCad); return foundCad; } /** * In case of FilterInvocation, compare current time with mapping * information of restricted times. in pair of * RestrictedTimesFilterSecurityInterceptor, it calls alwaysTimeRoleCheck, * dailyFilteredTimeRoleCheck, alwaysTimeResourceCheck and * dailyFilteredTimeResourceCheck sequentially. * * @see anyframe.iam.core.intercept.web.RestrictedTimesFilterSecurityInterceptor#invoke(FilterInvocation) * @see org.springframework.security.intercept.ObjectDefinitionSource#getAttributes(java.lang.Object) */ public List<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { if ((object == null) || !this.supports(object.getClass())) { throw new IllegalArgumentException("Object must be a FilterInvocation"); } String url = ((FilterInvocation) object).getRequestUrl(); // urlMatcher ? queryString if (stripQueryStringFromUrls) { int firstQuestionMarkIndex = url.indexOf("?"); if (firstQuestionMarkIndex != -1) { url = url.substring(0, firstQuestionMarkIndex); } } // lowercase ? ? if (urlMatcher.requiresLowerCaseUrl()) { url = url.toLowerCase(); } // ? DateTime currentDateTime = new DateTime(); DateTime currentTime = DateTimeFormat.forPattern("HHmmss") .parseDateTime(currentDateTime.toString("HHmmss")); String currentDay = DateTimeFormat.forPattern("yyyyMMdd").print(currentDateTime); // alwaysTimeRoleCheck if (RestrictedResourceHolder.RESTRICTED_RESOURCE_TYPE[0] .equals(RestrictedResourceHolder.getPresentResource())) { return lookupRoleOrUrlInCandidateListCheck(alwaysTimeRoleCheck, url, currentDateTime, currentTime, true, true); } // dailyFilteredTimeRoleCheck if (RestrictedResourceHolder.RESTRICTED_RESOURCE_TYPE[1] .equals(RestrictedResourceHolder.getPresentResource())) { List todayRoleList = (List) dailyFilteredTimeRoleCheck.get(currentDay); return lookupRoleOrUrlInCandidateListCheck(todayRoleList, url, currentDateTime, currentTime, false, true); } // alwaysTimeResourceCheck if (RestrictedResourceHolder.RESTRICTED_RESOURCE_TYPE[2] .equals(RestrictedResourceHolder.getPresentResource())) { return lookupRoleOrUrlInCandidateListCheck(alwaysTimeResourceCheck, url, currentDateTime, currentTime, true, false); } // dailyFilteredTimeResourceCheck if (RestrictedResourceHolder.RESTRICTED_RESOURCE_TYPE[3] .equals(RestrictedResourceHolder.getPresentResource())) { List todayUrlList = (List) dailyFilteredTimeResourceCheck.get(currentDay); return lookupRoleOrUrlInCandidateListCheck(todayUrlList, url, currentDateTime, currentTime, false, false); } return null; } /** * Get the String Array of Days between startDate and endDate. * @param startDate * @param endDate * @return String Array. The Days between startDate and endDate. */ public String[] getBetweenDays(String startDate, String endDate) { List betweenDays = new ArrayList(); DateTime tempDate = DateTimeFormat.forPattern("yyyyMMdd").parseDateTime(startDate); DateTime endJodaDate = DateTimeFormat.forPattern("yyyyMMdd").parseDateTime(endDate); betweenDays.add(DateTimeFormat.forPattern("yyyyMMdd").print(tempDate)); while (tempDate.isBefore(endJodaDate.getMillis())) { tempDate = tempDate.plusDays(1); betweenDays.add(DateTimeFormat.forPattern("yyyyMMdd").print(tempDate)); } return (String[]) betweenDays.toArray(new String[0]); } /** * validateConfigAttributes not supported */ public Collection<ConfigAttribute> getAllConfigAttributes() { // validateConfigAttributes ? ? return null; } /** * */ public boolean supports(Class clazz) { return FilterInvocation.class.isAssignableFrom(clazz); } }