/* * Copyright 2002-2013 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.springframework.security.config.annotation; import java.util.ArrayList; import java.util.List; import org.springframework.core.GenericTypeResolver; /** * A base class for {@link SecurityConfigurer} that allows subclasses to only * implement the methods they are interested in. It also provides a mechanism * for using the {@link SecurityConfigurer} and when done gaining access to the * {@link SecurityBuilder} that is being configured. * * @author Rob Winch * * @param <O> * The Object being built by B * @param <B> * The Builder that is building O and is configured by {@link SecurityConfigurerAdapter} */ public abstract class SecurityConfigurerAdapter<O,B extends SecurityBuilder<O>> implements SecurityConfigurer<O,B> { private B securityBuilder; private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor(); @Override public void init(B builder) throws Exception {} @Override public void configure(B builder) throws Exception {} /** * Return the {@link SecurityBuilder} when done using the * {@link SecurityConfigurer}. This is useful for method chaining. * * @return */ public B and() { return getBuilder(); } /** * Gets the {@link SecurityBuilder}. Cannot be null. * * @return the {@link SecurityBuilder} * @throw {@link IllegalStateException} if {@link SecurityBuilder} is null */ protected final B getBuilder() { if(securityBuilder == null) { throw new IllegalStateException("securityBuilder cannot be null"); } return securityBuilder; } /** * Performs post processing of an object. The default is to delegate to the * {@link ObjectPostProcessor}. * * @param object the Object to post process * @return the possibly modified Object to use */ @SuppressWarnings("unchecked") protected <T> T postProcess(T object) { return (T) this.objectPostProcessor.postProcess(object); } /** * Adds an {@link ObjectPostProcessor} to be used for this * {@link SecurityConfigurerAdapter}. The default implementation does * nothing to the object. * * @param objectPostProcessor the {@link ObjectPostProcessor} to use */ public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) { this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor); } /** * Sets the {@link SecurityBuilder} to be used. This is automatically set * when using * {@link AbstractConfiguredSecurityBuilder#apply(SecurityConfigurerAdapter)} * * @param builder the {@link SecurityBuilder} to set */ public void setBuilder(B builder) { this.securityBuilder = builder; } /** * An {@link ObjectPostProcessor} that delegates work to numerous * {@link ObjectPostProcessor} implementations. * * @author Rob Winch */ private static final class CompositeObjectPostProcessor implements ObjectPostProcessor<Object> { private List<ObjectPostProcessor<? extends Object>> postProcessors = new ArrayList<ObjectPostProcessor<?>>(); @Override @SuppressWarnings({ "rawtypes", "unchecked" }) public Object postProcess(Object object) { for(ObjectPostProcessor opp : postProcessors) { Class<?> oppClass = opp.getClass(); Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,ObjectPostProcessor.class); if(oppType == null || oppType.isAssignableFrom(object.getClass())) { object = opp.postProcess(object); } } return object; } /** * Adds an {@link ObjectPostProcessor} to use * @param objectPostProcessor the {@link ObjectPostProcessor} to add * @return true if the {@link ObjectPostProcessor} was added, else false */ private boolean addObjectPostProcessor(ObjectPostProcessor<?extends Object> objectPostProcessor) { return this.postProcessors.add(objectPostProcessor); } } }