Initial version of context module
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@118 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
dd285fd71c
commit
0803d7d0e2
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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.springframework.context;
|
||||
|
||||
import org.springframework.beans.factory.HierarchicalBeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
/**
|
||||
* Central interface to provide configuration for an application.
|
||||
* This is read-only while the application is running, but may be
|
||||
* reloaded if the implementation supports this.
|
||||
*
|
||||
* <p>An ApplicationContext provides:
|
||||
* <ul>
|
||||
* <li>Bean factory methods for accessing application components.
|
||||
* Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}.
|
||||
* <li>The ability to load file resources in a generic fashion.
|
||||
* Inherited from the {@link org.springframework.core.io.ResourceLoader} interface.
|
||||
* <li>The ability to publish events to registered listeners.
|
||||
* Inherited from the {@link ApplicationEventPublisher} interface.
|
||||
* <li>The ability to resolve messages, supporting internationalization.
|
||||
* Inherited from the {@link MessageSource} interface.
|
||||
* <li>Inheritance from a parent context. Definitions in a descendant context
|
||||
* will always take priority. This means, for example, that a single parent
|
||||
* context can be used by an entire web application, while each servlet has
|
||||
* its own child context that is independent of that of any other servlet.
|
||||
* </ul>
|
||||
*
|
||||
* <p>In addition to standard {@link org.springframework.beans.factory.BeanFactory}
|
||||
* lifecycle capabilities, ApplicationContext implementations detect and invoke
|
||||
* {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware},
|
||||
* {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see ConfigurableApplicationContext
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @see org.springframework.core.io.ResourceLoader
|
||||
*/
|
||||
public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory,
|
||||
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
|
||||
|
||||
/**
|
||||
* Return the unique id of this application context.
|
||||
* @return the unique id of the context
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Return a friendly name for this context.
|
||||
* @return a display name for this context
|
||||
*/
|
||||
String getDisplayName();
|
||||
|
||||
/**
|
||||
* Return the timestamp when this context was first loaded.
|
||||
* @return the timestamp (ms) when this context was first loaded
|
||||
*/
|
||||
long getStartupDate();
|
||||
|
||||
/**
|
||||
* Return the parent context, or <code>null</code> if there is no parent
|
||||
* and this is the root of the context hierarchy.
|
||||
* @return the parent context, or <code>null</code> if there is no parent
|
||||
*/
|
||||
ApplicationContext getParent();
|
||||
|
||||
/**
|
||||
* Expose AutowireCapableBeanFactory functionality for this context.
|
||||
* <p>This is not typically used by application code, except for the purpose
|
||||
* of initializing bean instances that live outside the application context,
|
||||
* applying the Spring bean lifecycle (fully or partly) to them.
|
||||
* <p>Alternatively, the internal BeanFactory exposed by the
|
||||
* {@link ConfigurableApplicationContext} interface offers access to the
|
||||
* AutowireCapableBeanFactory interface too. The present method mainly
|
||||
* serves as convenient, specific facility on the ApplicationContext
|
||||
* interface itself.
|
||||
* @return the AutowireCapableBeanFactory for this context
|
||||
* @throws IllegalStateException if the context does not support
|
||||
* the AutowireCapableBeanFactory interface or does not hold an autowire-capable
|
||||
* bean factory yet (usually if <code>refresh()</code> has never been called)
|
||||
* @see ConfigurableApplicationContext#refresh()
|
||||
* @see ConfigurableApplicationContext#getBeanFactory()
|
||||
*/
|
||||
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any object that wishes to be notified
|
||||
* of the {@link ApplicationContext} that it runs in.
|
||||
*
|
||||
* <p>Implementing this interface makes sense for example when an object
|
||||
* requires access to a set of collaborating beans. Note that configuration
|
||||
* via bean references is preferable to implementing this interface just
|
||||
* for bean lookup purposes.
|
||||
*
|
||||
* <p>This interface can also be implemented if an object needs access to file
|
||||
* resources, i.e. wants to call <code>getResource</code>, wants to publish
|
||||
* an application event, or requires access to the MessageSource. However,
|
||||
* it is preferable to implement the more specific {@link ResourceLoaderAware},
|
||||
* {@link ApplicationEventPublisherAware} or {@link MessageSourceAware} interface
|
||||
* in such a specific scenario.
|
||||
*
|
||||
* <p>Note that file resource dependencies can also be exposed as bean properties
|
||||
* of type {@link org.springframework.core.io.Resource}, populated via Strings
|
||||
* with automatic type conversion by the bean factory. This removes the need
|
||||
* for implementing any callback interface just for the purpose of accessing
|
||||
* a specific file resource.
|
||||
*
|
||||
* <p>{@link org.springframework.context.support.ApplicationObjectSupport} is a
|
||||
* convenience base class for application objects, implementing this interface.
|
||||
*
|
||||
* <p>For a list of all bean lifecycle methods, see the
|
||||
* {@link org.springframework.beans.factory.BeanFactory BeanFactory javadocs}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see ResourceLoaderAware
|
||||
* @see ApplicationEventPublisherAware
|
||||
* @see MessageSourceAware
|
||||
* @see org.springframework.context.support.ApplicationObjectSupport
|
||||
* @see org.springframework.beans.factory.BeanFactoryAware
|
||||
*/
|
||||
public interface ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Set the ApplicationContext that this object runs in.
|
||||
* Normally this call will be used to initialize the object.
|
||||
* <p>Invoked after population of normal bean properties but before an init callback such
|
||||
* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
|
||||
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
|
||||
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
|
||||
* {@link MessageSourceAware}, if applicable.
|
||||
* @param applicationContext the ApplicationContext object to be used by this object
|
||||
* @throws ApplicationContextException in case of context initialization errors
|
||||
* @throws BeansException if thrown by application context methods
|
||||
* @see org.springframework.beans.factory.BeanInitializationException
|
||||
*/
|
||||
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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.context;
|
||||
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
|
||||
/**
|
||||
* Exception thrown during application context initialization.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public class ApplicationContextException extends FatalBeanException {
|
||||
|
||||
/**
|
||||
* Create a new <code>ApplicationContextException</code>
|
||||
* with the specified detail message and no root cause.
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public ApplicationContextException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>ApplicationContextException</code>
|
||||
* with the specified detail message and the given root cause.
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause
|
||||
*/
|
||||
public ApplicationContextException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* Class to be extended by all application events. Abstract as it
|
||||
* doesn't make sense for generic events to be published directly.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public abstract class ApplicationEvent extends EventObject {
|
||||
|
||||
/** use serialVersionUID from Spring 1.2 for interoperability */
|
||||
private static final long serialVersionUID = 7099057708183571937L;
|
||||
|
||||
/** System time when the event happened */
|
||||
private final long timestamp;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ApplicationEvent.
|
||||
* @param source the component that published the event (never <code>null</code>)
|
||||
*/
|
||||
public ApplicationEvent(Object source) {
|
||||
super(source);
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the system time in milliseconds when the event happened.
|
||||
*/
|
||||
public final long getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context;
|
||||
|
||||
/**
|
||||
* Interface that encapsulates event publication functionality.
|
||||
* Serves as super-interface for ApplicationContext.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.1
|
||||
* @see ApplicationContext
|
||||
* @see ApplicationEventPublisherAware
|
||||
* @see org.springframework.context.ApplicationEvent
|
||||
* @see org.springframework.context.event.EventPublicationInterceptor
|
||||
*/
|
||||
public interface ApplicationEventPublisher {
|
||||
|
||||
/**
|
||||
* Notify all listeners registered with this application of an application
|
||||
* event. Events may be framework events (such as RequestHandledEvent)
|
||||
* or application-specific events.
|
||||
* @param event the event to publish
|
||||
* @see org.springframework.web.context.support.RequestHandledEvent
|
||||
*/
|
||||
void publishEvent(ApplicationEvent event);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any object that wishes to be notified
|
||||
* of the ApplicationEventPublisher (typically the ApplicationContext)
|
||||
* that it runs in.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.1
|
||||
* @see ApplicationContextAware
|
||||
*/
|
||||
public interface ApplicationEventPublisherAware {
|
||||
|
||||
/**
|
||||
* Set the ApplicationEventPublisher that this object runs in.
|
||||
* <p>Invoked after population of normal bean properties but before an init
|
||||
* callback like InitializingBean's afterPropertiesSet or a custom init-method.
|
||||
* Invoked before ApplicationContextAware's setApplicationContext.
|
||||
* @param applicationEventPublisher event publisher to be used by this object
|
||||
*/
|
||||
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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.context;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by application event listeners.
|
||||
* Based on the standard <code>java.util.EventListener</code> interface
|
||||
* for the Observer design pattern.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see org.springframework.context.event.ApplicationEventMulticaster
|
||||
*/
|
||||
public interface ApplicationListener extends EventListener {
|
||||
|
||||
/**
|
||||
* Handle an application event.
|
||||
* @param event the event to respond to
|
||||
*/
|
||||
void onApplicationEvent(ApplicationEvent event);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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.springframework.context;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
|
||||
/**
|
||||
* SPI interface to be implemented by most if not all application contexts.
|
||||
* Provides facilities to configure an application context in addition
|
||||
* to the application context client methods in the
|
||||
* {@link org.springframework.context.ApplicationContext} interface.
|
||||
*
|
||||
* <p>Configuration and lifecycle methods are encapsulated here to avoid
|
||||
* making them obvious to ApplicationContext client code. The present
|
||||
* methods should only be used by startup and shutdown code.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 03.11.2003
|
||||
*/
|
||||
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle {
|
||||
|
||||
/**
|
||||
* Any number of these characters are considered delimiters between
|
||||
* multiple context config paths in a single String value.
|
||||
* @see org.springframework.context.support.AbstractXmlApplicationContext#setConfigLocation
|
||||
* @see org.springframework.web.context.ContextLoader#CONFIG_LOCATION_PARAM
|
||||
* @see org.springframework.web.servlet.FrameworkServlet#setContextConfigLocation
|
||||
*/
|
||||
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
|
||||
|
||||
/**
|
||||
* Name of the LoadTimeWeaver bean in the factory. If such a bean is supplied,
|
||||
* the context will use a temporary ClassLoader for type matching, in order
|
||||
* to allow the LoadTimeWeaver to process all actual bean classes.
|
||||
* @see org.springframework.instrument.classloading.LoadTimeWeaver
|
||||
*/
|
||||
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
|
||||
|
||||
|
||||
/**
|
||||
* Set the parent of this application context.
|
||||
* <p>Note that the parent shouldn't be changed: It should only be set outside
|
||||
* a constructor if it isn't available when an object of this class is created,
|
||||
* for example in case of WebApplicationContext setup.
|
||||
* @param parent the parent context
|
||||
* @see org.springframework.web.context.ConfigurableWebApplicationContext
|
||||
*/
|
||||
void setParent(ApplicationContext parent);
|
||||
|
||||
/**
|
||||
* Add a new BeanFactoryPostProcessor that will get applied to the internal
|
||||
* bean factory of this application context on refresh, before any of the
|
||||
* bean definitions get evaluated. To be invoked during context configuration.
|
||||
* @param beanFactoryPostProcessor the factory processor to register
|
||||
*/
|
||||
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor);
|
||||
|
||||
/**
|
||||
* Add a new ApplicationListener that will be notified on context events
|
||||
* such as context refresh and context shutdown.
|
||||
* <p>Note that any ApplicationListener registered here will be applied
|
||||
* on refresh of this context. If a listener is added after the initial
|
||||
* refresh, it will be applied on next refresh of the context.
|
||||
* @param listener the ApplicationListener to register
|
||||
* @see org.springframework.context.event.ContextRefreshedEvent
|
||||
* @see org.springframework.context.event.ContextClosedEvent
|
||||
*/
|
||||
void addApplicationListener(ApplicationListener listener);
|
||||
|
||||
/**
|
||||
* Load or refresh the persistent representation of the configuration,
|
||||
* which might an XML file, properties file, or relational database schema.
|
||||
* <p>As this is a startup method, it should destroy already created singletons
|
||||
* if it fails, to avoid dangling resources. In other words, after invocation
|
||||
* of that method, either all or no singletons at all should be instantiated.
|
||||
* @throws BeansException if the bean factory could not be initialized
|
||||
* @throws IllegalStateException if already initialized and multiple refresh
|
||||
* attempts are not supported
|
||||
*/
|
||||
void refresh() throws BeansException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Register a shutdown hook with the JVM runtime, closing this context
|
||||
* on JVM shutdown unless it has already been closed at that time.
|
||||
* <p>This method can be called multiple times. Only one shutdown hook
|
||||
* (at max) will be registered for each context instance.
|
||||
* @see java.lang.Runtime#addShutdownHook
|
||||
* @see #close()
|
||||
*/
|
||||
void registerShutdownHook();
|
||||
|
||||
/**
|
||||
* Close this application context, releasing all resources and locks that the
|
||||
* implementation might hold. This includes destroying all cached singleton beans.
|
||||
* <p>Note: Does <i>not</i> invoke <code>close</code> on a parent context;
|
||||
* parent contexts have their own, independent lifecycle.
|
||||
* <p>This method can be called multiple times without side effects: Subsequent
|
||||
* <code>close</code> calls on an already closed context will be ignored.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Determine whether this application context is active, that is,
|
||||
* whether it has been refreshed at least once and has not been closed yet.
|
||||
* @return whether the context is still active
|
||||
* @see #refresh()
|
||||
* @see #close()
|
||||
* @see #getBeanFactory()
|
||||
*/
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
* Return the internal bean factory of this application context.
|
||||
* Can be used to access specific functionality of the underlying factory.
|
||||
* <p>Note: Do not use this to post-process the bean factory; singletons
|
||||
* will already have been instantiated before. Use a BeanFactoryPostProcessor
|
||||
* to intercept the BeanFactory setup process before beans get touched.
|
||||
* <p>Generally, this internal factory will only be accessible while the context
|
||||
* is active, that is, inbetween {@link #refresh()} and {@link #close()}.
|
||||
* The {@link #isActive()} flag can be used to check whether the context
|
||||
* is in an appropriate state.
|
||||
* @return the underlying bean factory
|
||||
* @throws IllegalStateException if the context does not hold an internal
|
||||
* bean factory (usually if {@link #refresh()} hasn't been called yet or
|
||||
* if {@link #close()} has already been called)
|
||||
* @see #isActive()
|
||||
* @see #refresh()
|
||||
* @see #close()
|
||||
* @see #addBeanFactoryPostProcessor
|
||||
*/
|
||||
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context;
|
||||
|
||||
/**
|
||||
* Sub-interface of MessageSource to be implemented by objects that
|
||||
* can resolve messages hierarchically.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public interface HierarchicalMessageSource extends MessageSource {
|
||||
|
||||
/**
|
||||
* Set the parent that will be used to try to resolve messages
|
||||
* that this object can't resolve.
|
||||
* @param parent the parent MessageSource that will be used to
|
||||
* resolve messages that this object can't resolve.
|
||||
* May be <code>null</code>, in which case no further resolution is possible.
|
||||
*/
|
||||
void setParentMessageSource(MessageSource parent);
|
||||
|
||||
/**
|
||||
* Return the parent of this MessageSource, or <code>null</code> if none.
|
||||
*/
|
||||
MessageSource getParentMessageSource();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context;
|
||||
|
||||
/**
|
||||
* Interface defining methods for start/stop lifecycle control.
|
||||
* The typical use case for this is to control asynchronous processing.
|
||||
*
|
||||
* <p>Can be implemented by both components (typically a Spring bean defined in
|
||||
* a Spring {@link org.springframework.beans.factory.BeanFactory}) and containers
|
||||
* (typically a Spring {@link ApplicationContext}). Containers will propagate
|
||||
* start/stop signals to all components that apply.
|
||||
*
|
||||
* <p>Can be used for direct invocations or for management operations via JMX.
|
||||
* In the latter case, the {@link org.springframework.jmx.export.MBeanExporter}
|
||||
* will typically be defined with an
|
||||
* {@link org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler},
|
||||
* restricting the visibility of activity-controlled components to the Lifecycle
|
||||
* interface.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see ConfigurableApplicationContext
|
||||
* @see org.springframework.jms.listener.AbstractMessageListenerContainer
|
||||
* @see org.springframework.scheduling.quartz.SchedulerFactoryBean
|
||||
*/
|
||||
public interface Lifecycle {
|
||||
|
||||
/**
|
||||
* Start this component.
|
||||
* Should not throw an exception if the component is already running.
|
||||
* <p>In the case of a container, this will propagate the start signal
|
||||
* to all components that apply.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stop this component.
|
||||
* Should not throw an exception if the component isn't started yet.
|
||||
* <p>In the case of a container, this will propagate the stop signal
|
||||
* to all components that apply.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Check whether this component is currently running.
|
||||
* <p>In the case of a container, this will return <code>true</code>
|
||||
* only if <i>all</i> components that apply are currently running.
|
||||
* @return whether the component is currently running
|
||||
*/
|
||||
boolean isRunning();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.springframework.context;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Strategy interface for resolving messages, with support for the parameterization
|
||||
* and internationalization of such messages.
|
||||
*
|
||||
* <p>Spring provides two out-of-the-box implementations for production:
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.context.support.ResourceBundleMessageSource},
|
||||
* built on top of the standard {@link java.util.ResourceBundle}
|
||||
* <li>{@link org.springframework.context.support.ReloadableResourceBundleMessageSource},
|
||||
* being able to reload message definitions without restarting the VM
|
||||
* </ul>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see org.springframework.context.support.ResourceBundleMessageSource
|
||||
* @see org.springframework.context.support.ReloadableResourceBundleMessageSource
|
||||
*/
|
||||
public interface MessageSource {
|
||||
|
||||
/**
|
||||
* Try to resolve the message. Return default message if no message was found.
|
||||
* @param code the code to lookup up, such as 'calculator.noRateSet'. Users of
|
||||
* this class are encouraged to base message names on the relevant fully
|
||||
* qualified class name, thus avoiding conflict and ensuring maximum clarity.
|
||||
* @param args array of arguments that will be filled in for params within
|
||||
* the message (params look like "{0}", "{1,date}", "{2,time}" within a message),
|
||||
* or <code>null</code> if none.
|
||||
* @param defaultMessage String to return if the lookup fails
|
||||
* @param locale the Locale in which to do the lookup
|
||||
* @return the resolved message if the lookup was successful;
|
||||
* otherwise the default message passed as a parameter
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
|
||||
|
||||
/**
|
||||
* Try to resolve the message. Treat as an error if the message can't be found.
|
||||
* @param code the code to lookup up, such as 'calculator.noRateSet'
|
||||
* @param args Array of arguments that will be filled in for params within
|
||||
* the message (params look like "{0}", "{1,date}", "{2,time}" within a message),
|
||||
* or <code>null</code> if none.
|
||||
* @param locale the Locale in which to do the lookup
|
||||
* @return the resolved message
|
||||
* @throws NoSuchMessageException if the message wasn't found
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
|
||||
|
||||
/**
|
||||
* Try to resolve the message using all the attributes contained within the
|
||||
* <code>MessageSourceResolvable</code> argument that was passed in.
|
||||
* <p>NOTE: We must throw a <code>NoSuchMessageException</code> on this method
|
||||
* since at the time of calling this method we aren't able to determine if the
|
||||
* <code>defaultMessage</code> property of the resolvable is null or not.
|
||||
* @param resolvable value object storing attributes required to properly resolve a message
|
||||
* @param locale the Locale in which to do the lookup
|
||||
* @return the resolved message
|
||||
* @throws NoSuchMessageException if the message wasn't found
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any object that wishes to be notified
|
||||
* of the MessageSource (typically the ApplicationContext) that it runs in.
|
||||
*
|
||||
* <p>Note that the MessageSource can usually also be passed on as bean
|
||||
* reference (to arbitrary bean properties or constructor arguments), because
|
||||
* it is defined as bean with name "messageSource" in the application context.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.1
|
||||
* @see ApplicationContextAware
|
||||
*/
|
||||
public interface MessageSourceAware {
|
||||
|
||||
/**
|
||||
* Set the MessageSource that this object runs in.
|
||||
* <p>Invoked after population of normal bean properties but before an init
|
||||
* callback like InitializingBean's afterPropertiesSet or a custom init-method.
|
||||
* Invoked before ApplicationContextAware's setApplicationContext.
|
||||
* @param messageSource message sourceto be used by this object
|
||||
*/
|
||||
void setMessageSource(MessageSource messageSource);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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.context;
|
||||
|
||||
/**
|
||||
* Interface for objects that are suitable for message resolution in a
|
||||
* {@link MessageSource}.
|
||||
*
|
||||
* <p>Spring's own validation error classes implement this interface.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see MessageSource#getMessage(MessageSourceResolvable, java.util.Locale)
|
||||
* @see org.springframework.validation.ObjectError
|
||||
* @see org.springframework.validation.FieldError
|
||||
*/
|
||||
public interface MessageSourceResolvable {
|
||||
|
||||
/**
|
||||
* Return the codes to be used to resolve this message, in the order that
|
||||
* they should get tried. The last code will therefore be the default one.
|
||||
* @return a String array of codes which are associated with this message
|
||||
*/
|
||||
public String[] getCodes();
|
||||
|
||||
/**
|
||||
* Return the array of arguments to be used to resolve this message.
|
||||
* @return an array of objects to be used as parameters to replace
|
||||
* placeholders within the message text
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
public Object[] getArguments();
|
||||
|
||||
/**
|
||||
* Return the default message to be used to resolve this message.
|
||||
* @return the default message, or <code>null</code> if no default
|
||||
*/
|
||||
public String getDefaultMessage();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Exception thrown when a message can't be resolved.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public class NoSuchMessageException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Create a new exception.
|
||||
* @param code code that could not be resolved for given locale
|
||||
* @param locale locale that was used to search for the code within
|
||||
*/
|
||||
public NoSuchMessageException(String code, Locale locale) {
|
||||
super("No message found under code '" + code + "' for locale '" + locale + "'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new exception.
|
||||
* @param code code that could not be resolved for given locale
|
||||
*/
|
||||
public NoSuchMessageException(String code) {
|
||||
super("No message found under code '" + code + "' for locale '" + Locale.getDefault() + "'.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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.context;
|
||||
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any object that wishes to be notified of
|
||||
* the <b>ResourceLoader</b> (typically the ApplicationContext) that it runs in.
|
||||
* This is an alternative to a full ApplicationContext dependency via the
|
||||
* ApplicationContextAware interface.
|
||||
*
|
||||
* <p>Note that Resource dependencies can also be exposed as bean properties
|
||||
* of type Resource, populated via Strings with automatic type conversion by
|
||||
* the bean factory. This removes the need for implementing any callback
|
||||
* interface just for the purpose of accessing a specific file resource.
|
||||
*
|
||||
* <p>You typically need a ResourceLoader when your application object has
|
||||
* to access a variety of file resources whose names are calculated. A good
|
||||
* strategy is to make the object use a DefaultResourceLoader but still
|
||||
* implement ResourceLoaderAware to allow for overriding when running in an
|
||||
* ApplicationContext. See ReloadableResourceBundleMessageSource for an example.
|
||||
*
|
||||
* <p>A passed-in ResourceLoader can also be checked for the
|
||||
* <b>ResourcePatternResolver</b> interface and cast accordingly, to be able
|
||||
* to resolve resource patterns into arrays of Resource objects. This will always
|
||||
* work when running in an ApplicationContext (the context interface extends
|
||||
* ResourcePatternResolver). Use a PathMatchingResourcePatternResolver as default.
|
||||
* See also the <code>ResourcePatternUtils.getResourcePatternResolver</code> method.
|
||||
*
|
||||
* <p>As alternative to a ResourcePatternResolver dependency, consider exposing
|
||||
* bean properties of type Resource array, populated via pattern Strings with
|
||||
* automatic type conversion by the bean factory.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 10.03.2004
|
||||
* @see ApplicationContextAware
|
||||
* @see org.springframework.beans.factory.InitializingBean
|
||||
* @see org.springframework.core.io.Resource
|
||||
* @see org.springframework.core.io.support.ResourcePatternResolver
|
||||
* @see org.springframework.core.io.support.ResourcePatternUtils#getResourcePatternResolver
|
||||
* @see org.springframework.core.io.DefaultResourceLoader
|
||||
* @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
|
||||
* @see org.springframework.context.support.ReloadableResourceBundleMessageSource
|
||||
*/
|
||||
public interface ResourceLoaderAware {
|
||||
|
||||
/**
|
||||
* Set the ResourceLoader that this object runs in.
|
||||
* <p>This might be a ResourcePatternResolver, which can be checked
|
||||
* through <code>instanceof ResourcePatternResolver</code>. See also the
|
||||
* <code>ResourcePatternUtils.getResourcePatternResolver</code> method.
|
||||
* <p>Invoked after population of normal bean properties but before an init callback
|
||||
* like InitializingBean's <code>afterPropertiesSet</code> or a custom init-method.
|
||||
* Invoked before ApplicationContextAware's <code>setApplicationContext</code>.
|
||||
* @param resourceLoader ResourceLoader object to be used by this object
|
||||
* @see org.springframework.core.io.support.ResourcePatternResolver
|
||||
* @see org.springframework.core.io.support.ResourcePatternUtils#getResourcePatternResolver
|
||||
*/
|
||||
void setResourceLoader(ResourceLoader resourceLoader);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context.access;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* ApplicationContext-specific implementation of BeanFactoryReference,
|
||||
* wrapping a newly created ApplicationContext, closing it on release.
|
||||
*
|
||||
* <p>As per BeanFactoryReference contract, <code>release</code> may be called
|
||||
* more than once, with subsequent calls not doing anything. However, calling
|
||||
* <code>getFactory</code> after a <code>release</code> call will cause an exception.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Colin Sampaleanu
|
||||
* @since 13.02.2004
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#close
|
||||
*/
|
||||
public class ContextBeanFactoryReference implements BeanFactoryReference {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ContextBeanFactoryReference for the given context.
|
||||
* @param applicationContext the ApplicationContext to wrap
|
||||
*/
|
||||
public ContextBeanFactoryReference(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
|
||||
public BeanFactory getFactory() {
|
||||
if (this.applicationContext == null) {
|
||||
throw new IllegalStateException(
|
||||
"ApplicationContext owned by this BeanFactoryReference has been released");
|
||||
}
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
if (this.applicationContext != null) {
|
||||
ApplicationContext savedCtx;
|
||||
|
||||
// We don't actually guarantee thread-safety, but it's not a lot of extra work.
|
||||
synchronized (this) {
|
||||
savedCtx = this.applicationContext;
|
||||
this.applicationContext = null;
|
||||
}
|
||||
|
||||
if (savedCtx != null && savedCtx instanceof ConfigurableApplicationContext) {
|
||||
((ConfigurableApplicationContext) savedCtx).close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.access;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springframework.beans.factory.access.BootstrapException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.jndi.JndiLocatorSupport;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* BeanFactoryLocator implementation that creates the BeanFactory from one or
|
||||
* more classpath locations specified in a JNDI environment variable.
|
||||
*
|
||||
* <p>This default implementation creates a
|
||||
* {@link org.springframework.context.support.ClassPathXmlApplicationContext}.
|
||||
* Subclasses may override {@link #createBeanFactory} for custom instantiation.
|
||||
*
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
* @see #createBeanFactory
|
||||
*/
|
||||
public class ContextJndiBeanFactoryLocator extends JndiLocatorSupport implements BeanFactoryLocator {
|
||||
|
||||
/**
|
||||
* Any number of these characters are considered delimiters between
|
||||
* multiple bean factory config paths in a single String value.
|
||||
*/
|
||||
public static final String BEAN_FACTORY_PATH_DELIMITERS = ",; \t\n";
|
||||
|
||||
|
||||
/**
|
||||
* Load/use a bean factory, as specified by a factory key which is a JNDI
|
||||
* address, of the form <code>java:comp/env/ejb/BeanFactoryPath</code>. The
|
||||
* contents of this JNDI location must be a string containing one or more
|
||||
* classpath resource names (separated by any of the delimiters '<code>,; \t\n</code>'
|
||||
* if there is more than one. The resulting BeanFactory (or ApplicationContext)
|
||||
* will be created from the combined resources.
|
||||
* @see #createBeanFactory
|
||||
*/
|
||||
public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
|
||||
try {
|
||||
String beanFactoryPath = (String) lookup(factoryKey, String.class);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Bean factory path from JNDI environment variable [" + factoryKey +
|
||||
"] is: " + beanFactoryPath);
|
||||
}
|
||||
String[] paths = StringUtils.tokenizeToStringArray(beanFactoryPath, BEAN_FACTORY_PATH_DELIMITERS);
|
||||
return createBeanFactory(paths);
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new BootstrapException("Define an environment variable [" + factoryKey + "] containing " +
|
||||
"the class path locations of XML bean definition files", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the BeanFactory instance, given an array of class path resource Strings
|
||||
* which should be combined. This is split out as a separate method so that
|
||||
* subclasses can override the actual BeanFactory implementation class.
|
||||
* <p>Delegates to <code>createApplicationContext</code> by default,
|
||||
* wrapping the result in a ContextBeanFactoryReference.
|
||||
* @param resources an array of Strings representing classpath resource names
|
||||
* @return the created BeanFactory, wrapped in a BeanFactoryReference
|
||||
* (for example, a ContextBeanFactoryReference wrapping an ApplicationContext)
|
||||
* @throws BeansException if factory creation failed
|
||||
* @see #createApplicationContext
|
||||
* @see ContextBeanFactoryReference
|
||||
*/
|
||||
protected BeanFactoryReference createBeanFactory(String[] resources) throws BeansException {
|
||||
ApplicationContext ctx = createApplicationContext(resources);
|
||||
return new ContextBeanFactoryReference(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ApplicationContext instance, given an array of class path resource
|
||||
* Strings which should be combined
|
||||
* @param resources an array of Strings representing classpath resource names
|
||||
* @return the created ApplicationContext
|
||||
* @throws BeansException if context creation failed
|
||||
*/
|
||||
protected ApplicationContext createApplicationContext(String[] resources) throws BeansException {
|
||||
return new ClassPathXmlApplicationContext(resources);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.access;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
|
||||
/**
|
||||
* <p>Variant of {@link org.springframework.beans.factory.access.SingletonBeanFactoryLocator}
|
||||
* which creates its internal bean factory reference as an
|
||||
* {@link org.springframework.context.ApplicationContext} instead of
|
||||
* SingletonBeanFactoryLocator's simple BeanFactory. For almost all usage scenarios,
|
||||
* this will not make a difference, since within that ApplicationContext or BeanFactory
|
||||
* you are still free to define either BeanFactory or ApplicationContext instances.
|
||||
* The main reason one would need to use this class is if bean post-processing
|
||||
* (or other ApplicationContext specific features are needed in the bean reference
|
||||
* definition itself).
|
||||
*
|
||||
* <p><strong>Note:</strong> This class uses <strong>classpath*:beanRefContext.xml</strong>
|
||||
* as the default resource location for the bean factory reference definition files.
|
||||
* It is not possible nor legal to share definitions with SingletonBeanFactoryLocator
|
||||
* at the same time.
|
||||
*
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
* @see org.springframework.beans.factory.access.SingletonBeanFactoryLocator
|
||||
* @see org.springframework.context.access.DefaultLocatorFactory
|
||||
*/
|
||||
public class ContextSingletonBeanFactoryLocator extends SingletonBeanFactoryLocator {
|
||||
|
||||
private static final String DEFAULT_RESOURCE_LOCATION = "classpath*:beanRefContext.xml";
|
||||
|
||||
/** The keyed singleton instances */
|
||||
private static final Map instances = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Returns an instance which uses the default "classpath*:beanRefContext.xml", as
|
||||
* the name of the definition file(s). All resources returned by the current
|
||||
* thread's context class loader's <code>getResources</code> method with this
|
||||
* name will be combined to create a definition, which is just a BeanFactory.
|
||||
* @return the corresponding BeanFactoryLocator instance
|
||||
* @throws BeansException in case of factory loading failure
|
||||
*/
|
||||
public static BeanFactoryLocator getInstance() throws BeansException {
|
||||
return getInstance(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance which uses the the specified selector, as the name of the
|
||||
* definition file(s). In the case of a name with a Spring "classpath*:" prefix,
|
||||
* or with no prefix, which is treated the same, the current thread's context class
|
||||
* loader's <code>getResources</code> method will be called with this value to get
|
||||
* all resources having that name. These resources will then be combined to form a
|
||||
* definition. In the case where the name uses a Spring "classpath:" prefix, or
|
||||
* a standard URL prefix, then only one resource file will be loaded as the
|
||||
* definition.
|
||||
* @param selector the location of the resource(s) which will be read and
|
||||
* combined to form the definition for the BeanFactoryLocator instance.
|
||||
* Any such files must form a valid ApplicationContext definition.
|
||||
* @return the corresponding BeanFactoryLocator instance
|
||||
* @throws BeansException in case of factory loading failure
|
||||
*/
|
||||
public static BeanFactoryLocator getInstance(String selector) throws BeansException {
|
||||
String resourceLocation = selector;
|
||||
if (resourceLocation == null) {
|
||||
resourceLocation = DEFAULT_RESOURCE_LOCATION;
|
||||
}
|
||||
|
||||
// For backwards compatibility, we prepend "classpath*:" to the selector name if there
|
||||
// is no other prefix (i.e. "classpath*:", "classpath:", or some URL prefix).
|
||||
if (!ResourcePatternUtils.isUrl(resourceLocation)) {
|
||||
resourceLocation = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resourceLocation;
|
||||
}
|
||||
|
||||
synchronized (instances) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("ContextSingletonBeanFactoryLocator.getInstance(): instances.hashCode=" +
|
||||
instances.hashCode() + ", instances=" + instances);
|
||||
}
|
||||
BeanFactoryLocator bfl = (BeanFactoryLocator) instances.get(resourceLocation);
|
||||
if (bfl == null) {
|
||||
bfl = new ContextSingletonBeanFactoryLocator(resourceLocation);
|
||||
instances.put(resourceLocation, bfl);
|
||||
}
|
||||
return bfl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor which uses the the specified name as the resource name
|
||||
* of the definition file(s).
|
||||
* @param resourceLocation the Spring resource location to use
|
||||
* (either a URL or a "classpath:" / "classpath*:" pseudo URL)
|
||||
*/
|
||||
protected ContextSingletonBeanFactoryLocator(String resourceLocation) {
|
||||
super(resourceLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default method to create definition object as an ApplicationContext
|
||||
* instead of the default BeanFactory. This does not affect what can actually
|
||||
* be loaded by that definition.
|
||||
* <p>The default implementation simply builds a
|
||||
* {@link org.springframework.context.support.ClassPathXmlApplicationContext}.
|
||||
*/
|
||||
protected BeanFactory createDefinition(String resourceLocation, String factoryKey) {
|
||||
return new ClassPathXmlApplicationContext(new String[] {resourceLocation}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default method to refresh the ApplicationContext, invoking
|
||||
* {@link ConfigurableApplicationContext#refresh ConfigurableApplicationContext.refresh()}.
|
||||
*/
|
||||
protected void initializeDefinition(BeanFactory groupDef) {
|
||||
if (groupDef instanceof ConfigurableApplicationContext) {
|
||||
((ConfigurableApplicationContext) groupDef).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default method to operate on an ApplicationContext, invoking
|
||||
* {@link ConfigurableApplicationContext#refresh ConfigurableApplicationContext.close()}.
|
||||
*/
|
||||
protected void destroyDefinition(BeanFactory groupDef, String selector) {
|
||||
if (groupDef instanceof ConfigurableApplicationContext) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Context group with selector '" + selector +
|
||||
"' being released, as there are no more references to it");
|
||||
}
|
||||
((ConfigurableApplicationContext) groupDef).close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context.access;
|
||||
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
|
||||
/**
|
||||
* A factory class to get a default ContextSingletonBeanFactoryLocator instance.
|
||||
*
|
||||
* @author Colin Sampaleanu
|
||||
* @see org.springframework.context.access.ContextSingletonBeanFactoryLocator
|
||||
*/
|
||||
public class DefaultLocatorFactory {
|
||||
|
||||
/**
|
||||
* Return an instance object implementing BeanFactoryLocator. This will normally
|
||||
* be a singleton instance of the specific ContextSingletonBeanFactoryLocator class,
|
||||
* using the default resource selector.
|
||||
*/
|
||||
public static BeanFactoryLocator getInstance() throws FatalBeanException {
|
||||
return ContextSingletonBeanFactoryLocator.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance object implementing BeanFactoryLocator. This will normally
|
||||
* be a singleton instance of the specific ContextSingletonBeanFactoryLocator class,
|
||||
* using the specified resource selector.
|
||||
* @param selector a selector variable which provides a hint to the factory as to
|
||||
* which instance to return.
|
||||
*/
|
||||
public static BeanFactoryLocator getInstance(String selector) throws FatalBeanException {
|
||||
return ContextSingletonBeanFactoryLocator.getInstance(selector);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Helper infrastructure to locate and access shared application contexts.
|
||||
|
||||
<p><b>Note: This package is only relevant for special sharing of application
|
||||
contexts, for example behind EJB facades. It is <i>not</i> used in a typical
|
||||
web application or standalone application.</b>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.support.BeanNameGenerator}
|
||||
* implementation for bean classes annotated with the
|
||||
* {@link org.springframework.stereotype.Component @Component} annotation
|
||||
* or with another annotation that is itself annotated with
|
||||
* {@link org.springframework.stereotype.Component @Component} as a
|
||||
* meta-annotation. For example, Spring's stereotype annotations (such as
|
||||
* {@link org.springframework.stereotype.Repository @Repository}) are
|
||||
* themselves annotated with
|
||||
* {@link org.springframework.stereotype.Component @Component}.
|
||||
*
|
||||
* <p>If the annotation's value doesn't indicate a bean name, an appropriate
|
||||
* name will be built based on the short name of the class (with the first
|
||||
* letter lower-cased). For example:
|
||||
*
|
||||
* <pre class="code">com.xyz.FooServiceImpl -> fooServiceImpl</pre>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see org.springframework.stereotype.Component#value()
|
||||
* @see org.springframework.stereotype.Repository#value()
|
||||
* @see org.springframework.stereotype.Service#value()
|
||||
* @see org.springframework.stereotype.Controller#value()
|
||||
*/
|
||||
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
|
||||
private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
|
||||
|
||||
|
||||
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
|
||||
if (definition instanceof AnnotatedBeanDefinition) {
|
||||
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
|
||||
if (StringUtils.hasText(beanName)) {
|
||||
// Explicit bean name found.
|
||||
return beanName;
|
||||
}
|
||||
}
|
||||
// Fallback: generate a unique default bean name.
|
||||
return buildDefaultBeanName(definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a bean name from one of the annotations on the class.
|
||||
* @param annotatedDef the annotation-aware bean definition
|
||||
* @return the bean name, or <code>null</code> if none is found
|
||||
*/
|
||||
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
|
||||
AnnotationMetadata amd = annotatedDef.getMetadata();
|
||||
Set<String> types = amd.getAnnotationTypes();
|
||||
String beanName = null;
|
||||
for (String type : types) {
|
||||
Map<String, Object> attributes = amd.getAnnotationAttributes(type);
|
||||
if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
|
||||
String value = (String) attributes.get("value");
|
||||
if (StringUtils.hasLength(value)) {
|
||||
if (beanName != null && !value.equals(beanName)) {
|
||||
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
|
||||
"component names: '" + beanName + "' versus '" + value + "'");
|
||||
}
|
||||
beanName = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given annotation is a stereotype that is allowed
|
||||
* to suggest a component name through its annotation <code>value()</code>.
|
||||
* @param annotationType the name of the annotation class to check
|
||||
* @param metaAnnotationTypes the names of meta-annotations on the given annotation
|
||||
* @param attributes the map of attributes for the given annotation
|
||||
* @return whether the annotation qualifies as a stereotype with component name
|
||||
*/
|
||||
protected boolean isStereotypeWithNameValue(String annotationType,
|
||||
Set<String> metaAnnotationTypes, Map<String, Object> attributes) {
|
||||
|
||||
boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
|
||||
(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME));
|
||||
return (isStereotype && attributes != null && attributes.containsKey("value"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a default bean name from the given bean definition.
|
||||
* <p>The default implementation simply builds a decapitalized version
|
||||
* of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
|
||||
* <p>Note that inner classes will thus have names of the form
|
||||
* "outerClassName.innerClassName", which because of the period in the
|
||||
* name may be an issue if you are autowiring by name.
|
||||
* @param definition the bean definition to build a bean name for
|
||||
* @return the default bean name (never <code>null</code>)
|
||||
*/
|
||||
protected String buildDefaultBeanName(BeanDefinition definition) {
|
||||
String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
|
||||
return Introspector.decapitalize(shortClassName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
||||
/**
|
||||
* Parser for the <context:annotation-config/> element.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Christian Dupuis
|
||||
* @since 2.5
|
||||
* @see AnnotationConfigUtils
|
||||
*/
|
||||
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
|
||||
// Obtain bean definitions for all relevant BeanPostProcessors.
|
||||
Set<BeanDefinitionHolder> processorDefinitions =
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
|
||||
|
||||
// Register component for the surrounding <context:annotation-config> element.
|
||||
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
|
||||
parserContext.pushContainingComponent(compDefinition);
|
||||
|
||||
// Nest the concrete beans in the surrounding component.
|
||||
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
|
||||
parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
|
||||
}
|
||||
|
||||
// Finally register the composite component.
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Utility class that allows for convenient registration of common
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
|
||||
* definitions for annotation-based configuration.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see CommonAnnotationBeanPostProcessor
|
||||
* @see org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
|
||||
* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
|
||||
* @see org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
|
||||
*/
|
||||
public class AnnotationConfigUtils {
|
||||
|
||||
/**
|
||||
* The bean name of the internally managed JPA annotation processor.
|
||||
*/
|
||||
public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
|
||||
"org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
|
||||
|
||||
/**
|
||||
* The bean name of the internally managed JSR-250 annotation processor.
|
||||
*/
|
||||
public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
|
||||
"org.springframework.context.annotation.internalCommonAnnotationProcessor";
|
||||
|
||||
/**
|
||||
* The bean name of the internally managed Autowired annotation processor.
|
||||
*/
|
||||
public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
|
||||
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
|
||||
|
||||
/**
|
||||
* The bean name of the internally managed Required annotation processor.
|
||||
*/
|
||||
public static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
|
||||
"org.springframework.context.annotation.internalRequiredAnnotationProcessor";
|
||||
|
||||
|
||||
private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
|
||||
"org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";
|
||||
|
||||
|
||||
private static final boolean jsr250Present =
|
||||
ClassUtils.isPresent("javax.annotation.Resource", AnnotationConfigUtils.class.getClassLoader());
|
||||
|
||||
private static final boolean jpaPresent =
|
||||
ClassUtils.isPresent("javax.persistence.EntityManagerFactory", AnnotationConfigUtils.class.getClassLoader()) &&
|
||||
ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* Register all relevant annotation post processors in the given registry.
|
||||
* @param registry the registry to operate on
|
||||
*/
|
||||
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
|
||||
registerAnnotationConfigProcessors(registry, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all relevant annotation post processors in the given registry.
|
||||
* @param registry the registry to operate on
|
||||
* @param source the configuration source element (already extracted)
|
||||
* that this registration was triggered from. May be <code>null</code>.
|
||||
* @return a Set of BeanDefinitionHolders, containing all bean definitions
|
||||
* that have actually been registered by this call
|
||||
*/
|
||||
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
|
||||
BeanDefinitionRegistry registry, Object source) {
|
||||
|
||||
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(4);
|
||||
|
||||
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
|
||||
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition();
|
||||
try {
|
||||
ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
|
||||
def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
|
||||
}
|
||||
def.setSource(source);
|
||||
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
beanDefinitions.add(registerBeanPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
|
||||
}
|
||||
|
||||
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
|
||||
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
|
||||
def.setSource(source);
|
||||
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
beanDefinitions.add(registerBeanPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
|
||||
}
|
||||
|
||||
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
|
||||
def.setSource(source);
|
||||
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
beanDefinitions.add(registerBeanPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
|
||||
}
|
||||
|
||||
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
|
||||
def.setSource(source);
|
||||
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
beanDefinitions.add(registerBeanPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
|
||||
}
|
||||
|
||||
return beanDefinitions;
|
||||
}
|
||||
|
||||
private static BeanDefinitionHolder registerBeanPostProcessor(
|
||||
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
|
||||
|
||||
// Default infrastructure bean: lowest order value; role infrastructure.
|
||||
definition.getPropertyValues().addPropertyValue("order", new Integer(Ordered.LOWEST_PRECEDENCE));
|
||||
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
registry.registerBeanDefinition(beanName, definition);
|
||||
return new BeanDefinitionHolder(definition, beanName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ScopeMetadataResolver} implementation that (by default) checks for
|
||||
* the presence of the {@link Scope} annotation on the bean class.
|
||||
*
|
||||
* <p>The exact type of annotation that is checked for is configurable via the
|
||||
* {@link #setScopeAnnotationType(Class)} property.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see Scope
|
||||
*/
|
||||
public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
|
||||
|
||||
private Class<? extends Annotation> scopeAnnotationType = Scope.class;
|
||||
|
||||
private ScopedProxyMode scopedProxyMode;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of the <code>AnnotationScopeMetadataResolver</code> class.
|
||||
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
|
||||
* @see ScopedProxyMode#NO
|
||||
*/
|
||||
public AnnotationScopeMetadataResolver() {
|
||||
this(ScopedProxyMode.NO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the <code>AnnotationScopeMetadataResolver</code> class.
|
||||
* @param scopedProxyMode the desired scoped-proxy mode
|
||||
*/
|
||||
public AnnotationScopeMetadataResolver(ScopedProxyMode scopedProxyMode) {
|
||||
Assert.notNull(scopedProxyMode, "'scopedProxyMode' must not be null");
|
||||
this.scopedProxyMode = scopedProxyMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the type of annotation that is checked for by this
|
||||
* {@link AnnotationScopeMetadataResolver}.
|
||||
* @param scopeAnnotationType the target annotation type
|
||||
*/
|
||||
public void setScopeAnnotationType(Class<? extends Annotation> scopeAnnotationType) {
|
||||
Assert.notNull(scopeAnnotationType, "'scopeAnnotationType' must not be null");
|
||||
this.scopeAnnotationType = scopeAnnotationType;
|
||||
}
|
||||
|
||||
|
||||
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
|
||||
ScopeMetadata metadata = new ScopeMetadata();
|
||||
if (definition instanceof AnnotatedBeanDefinition) {
|
||||
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
|
||||
Map<String, Object> attributes =
|
||||
annDef.getMetadata().getAnnotationAttributes(this.scopeAnnotationType.getName());
|
||||
if (attributes != null) {
|
||||
metadata.setScopeName((String) attributes.get("value"));
|
||||
}
|
||||
if (!metadata.getScopeName().equals(BeanDefinition.SCOPE_SINGLETON)) {
|
||||
metadata.setScopedProxyMode(this.scopedProxyMode);
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionDefaults;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* A bean definition scanner that detects bean candidates on the classpath,
|
||||
* registering corresponding bean definitions with a given registry (BeanFactory
|
||||
* or ApplicationContext).
|
||||
*
|
||||
* <p>Candidate classes are detected through configurable type filters. The
|
||||
* default filters include classes that are annotated with Spring's
|
||||
* {@link org.springframework.stereotype.Component @Component},
|
||||
* {@link org.springframework.stereotype.Repository @Repository},
|
||||
* {@link org.springframework.stereotype.Service @Service}, or
|
||||
* {@link org.springframework.stereotype.Controller @Controller} stereotype.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see org.springframework.stereotype.Component
|
||||
* @see org.springframework.stereotype.Repository
|
||||
* @see org.springframework.stereotype.Service
|
||||
* @see org.springframework.stereotype.Controller
|
||||
*/
|
||||
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
|
||||
|
||||
private final BeanDefinitionRegistry registry;
|
||||
|
||||
private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
|
||||
|
||||
private String[] autowireCandidatePatterns;
|
||||
|
||||
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
|
||||
|
||||
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
|
||||
|
||||
private boolean includeAnnotationConfig = true;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ClassPathBeanDefinitionScanner for the given bean factory.
|
||||
* @param registry the BeanFactory to load bean definitions into,
|
||||
* in the form of a BeanDefinitionRegistry
|
||||
*/
|
||||
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
|
||||
this(registry, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathBeanDefinitionScanner for the given bean factory.
|
||||
* <p>If the passed-in bean factory does not only implement the BeanDefinitionRegistry
|
||||
* interface but also the ResourceLoader interface, it will be used as default
|
||||
* ResourceLoader as well. This will usually be the case for
|
||||
* {@link org.springframework.context.ApplicationContext} implementations.
|
||||
* <p>If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a
|
||||
* {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
|
||||
* @param registry the BeanFactory to load bean definitions into,
|
||||
* in the form of a BeanDefinitionRegistry
|
||||
* @param useDefaultFilters whether to include the default filters for the
|
||||
* {@link org.springframework.stereotype.Component @Component},
|
||||
* {@link org.springframework.stereotype.Repository @Repository},
|
||||
* {@link org.springframework.stereotype.Service @Service}, and
|
||||
* {@link org.springframework.stereotype.Controller @Controller} stereotype
|
||||
* annotations.
|
||||
* @see #setResourceLoader
|
||||
*/
|
||||
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
|
||||
super(useDefaultFilters);
|
||||
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
|
||||
this.registry = registry;
|
||||
|
||||
// Determine ResourceLoader to use.
|
||||
if (this.registry instanceof ResourceLoader) {
|
||||
setResourceLoader((ResourceLoader) this.registry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the BeanDefinitionRegistry that this scanner operates on.
|
||||
*/
|
||||
public final BeanDefinitionRegistry getRegistry() {
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the defaults to use for detected beans.
|
||||
* @see BeanDefinitionDefaults
|
||||
*/
|
||||
public void setBeanDefinitionDefaults(BeanDefinitionDefaults beanDefinitionDefaults) {
|
||||
this.beanDefinitionDefaults =
|
||||
(beanDefinitionDefaults != null ? beanDefinitionDefaults : new BeanDefinitionDefaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name-matching patterns for determining autowire candidates.
|
||||
* @param autowireCandidatePatterns the patterns to match against
|
||||
*/
|
||||
public void setAutowireCandidatePatterns(String[] autowireCandidatePatterns) {
|
||||
this.autowireCandidatePatterns = autowireCandidatePatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BeanNameGenerator to use for detected bean classes.
|
||||
* <p>Default is a {@link AnnotationBeanNameGenerator}.
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ScopeMetadataResolver to use for detected bean classes.
|
||||
* Note that this will override any custom "scopedProxyMode" setting.
|
||||
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
|
||||
* @see #setScopedProxyMode
|
||||
*/
|
||||
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.scopeMetadataResolver = scopeMetadataResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the proxy behavior for non-singleton scoped beans.
|
||||
* Note that this will override any custom "scopeMetadataResolver" setting.
|
||||
* <p>The default is {@link ScopedProxyMode#NO}.
|
||||
* @see #setScopeMetadataResolver
|
||||
*/
|
||||
public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
|
||||
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to register annotation config post-processors.
|
||||
* <p>The default is to register the post-processors. Turn this off
|
||||
* to be able to ignore the annotations or to process them differently.
|
||||
*/
|
||||
public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) {
|
||||
this.includeAnnotationConfig = includeAnnotationConfig;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform a scan within the specified base packages.
|
||||
* @param basePackages the packages to check for annotated classes
|
||||
* @return number of beans registered
|
||||
*/
|
||||
public int scan(String... basePackages) {
|
||||
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
|
||||
|
||||
doScan(basePackages);
|
||||
|
||||
// Register annotation config processors, if necessary.
|
||||
if (this.includeAnnotationConfig) {
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
|
||||
}
|
||||
|
||||
return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a scan within the specified base packages,
|
||||
* returning the registered bean definitions.
|
||||
* <p>This method does <i>not</i> register an annotation config processor
|
||||
* but rather leaves this up to the caller.
|
||||
* @param basePackages the packages to check for annotated classes
|
||||
* @return number of beans registered
|
||||
*/
|
||||
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
|
||||
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
|
||||
for (int i = 0; i < basePackages.length; i++) {
|
||||
Set<BeanDefinition> candidates = findCandidateComponents(basePackages[i]);
|
||||
for (BeanDefinition candidate : candidates) {
|
||||
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
|
||||
if (candidate instanceof AbstractBeanDefinition) {
|
||||
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
|
||||
}
|
||||
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
|
||||
if (checkCandidate(beanName, candidate)) {
|
||||
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
|
||||
definitionHolder = applyScope(definitionHolder, scopeMetadata);
|
||||
beanDefinitions.add(definitionHolder);
|
||||
registerBeanDefinition(definitionHolder, this.registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return beanDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply further settings to the given bean definition,
|
||||
* beyond the contents retrieved from scanning the component class.
|
||||
* @param beanDefinition the scanned bean definition
|
||||
* @param beanName the generated bean name for the given bean
|
||||
*/
|
||||
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
|
||||
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
|
||||
if (this.autowireCandidatePatterns != null) {
|
||||
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the specified bean with the given registry.
|
||||
* <p>Can be overridden in subclasses, e.g. to adapt the registration
|
||||
* process or to register further bean definitions for each scanned bean.
|
||||
* @param definitionHolder the bean definition plus bean name for the bean
|
||||
* @param registry the BeanDefinitionRegistry to register the bean with
|
||||
*/
|
||||
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the given candidate's bean name, determining whether the corresponding
|
||||
* bean definition needs to be registered or conflicts with an existing definition.
|
||||
* @param beanName the suggested name for the bean
|
||||
* @param beanDefinition the corresponding bean definition
|
||||
* @return <code>true</code> if the bean can be registered as-is;
|
||||
* <code>false</code> if it should be skipped because there is an
|
||||
* existing, compatible bean definition for the specified name
|
||||
* @throws IllegalStateException if an existing, incompatible
|
||||
* bean definition has been found for the specified name
|
||||
*/
|
||||
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
|
||||
if (!this.registry.containsBeanDefinition(beanName)) {
|
||||
return true;
|
||||
}
|
||||
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
|
||||
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
|
||||
if (originatingDef != null) {
|
||||
existingDef = originatingDef;
|
||||
}
|
||||
if (isCompatible(beanDefinition, existingDef)) {
|
||||
return false;
|
||||
}
|
||||
throw new IllegalStateException("Annotation-specified bean name '" + beanName +
|
||||
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
|
||||
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given new bean definition is compatible with
|
||||
* the given existing bean definition.
|
||||
* <p>The default implementation simply considers them as compatible
|
||||
* when the bean class name matches.
|
||||
* @param newDefinition the new bean definition, originated from scanning
|
||||
* @param existingDefinition the existing bean definition, potentially an
|
||||
* explicitly defined one or a previously generated one from scanning
|
||||
* @return whether the definitions are considered as compatible, with the
|
||||
* new definition to be skipped in favor of the existing definition
|
||||
*/
|
||||
protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) {
|
||||
return (!(existingDefinition instanceof AnnotatedBeanDefinition) || // explicitly registered overriding bean
|
||||
newDefinition.getSource().equals(existingDefinition.getSource()) || // scanned same file twice
|
||||
newDefinition.equals(existingDefinition)); // scanned equivalent class twice
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the specified scope to the given bean definition.
|
||||
* @param definitionHolder the bean definition to configure
|
||||
* @param scopeMetadata the corresponding scope metadata
|
||||
* @return the final bean definition to use (potentially a proxy)
|
||||
*/
|
||||
private BeanDefinitionHolder applyScope(BeanDefinitionHolder definitionHolder, ScopeMetadata scopeMetadata) {
|
||||
String scope = scopeMetadata.getScopeName();
|
||||
ScopedProxyMode scopedProxyMode = scopeMetadata.getScopedProxyMode();
|
||||
definitionHolder.getBeanDefinition().setScope(scope);
|
||||
if (BeanDefinition.SCOPE_SINGLETON.equals(scope) || BeanDefinition.SCOPE_PROTOTYPE.equals(scope) ||
|
||||
scopedProxyMode.equals(ScopedProxyMode.NO)) {
|
||||
return definitionHolder;
|
||||
}
|
||||
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
|
||||
return ScopedProxyCreator.createScopedProxy(definitionHolder, this.registry, proxyTargetClass);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner factory class used to just introduce an AOP framework dependency
|
||||
* when actually creating a scoped proxy.
|
||||
*/
|
||||
private static class ScopedProxyCreator {
|
||||
|
||||
public static BeanDefinitionHolder createScopedProxy(
|
||||
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
|
||||
|
||||
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
/**
|
||||
* A component provider that scans the classpath from a base package. It then
|
||||
* applies exclude and include filters to the resulting classes to find candidates.
|
||||
*
|
||||
* <p>This implementation is based on Spring's
|
||||
* {@link org.springframework.core.type.classreading.MetadataReader MetadataReader}
|
||||
* facility, backed by an ASM {@link org.objectweb.asm.ClassReader ClassReader}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.5
|
||||
* @see org.springframework.core.type.classreading.MetadataReaderFactory
|
||||
* @see org.springframework.core.type.AnnotationMetadata
|
||||
* @see ScannedGenericBeanDefinition
|
||||
*/
|
||||
public class ClassPathScanningCandidateComponentProvider implements ResourceLoaderAware {
|
||||
|
||||
protected static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
|
||||
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
|
||||
|
||||
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
|
||||
|
||||
private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();
|
||||
|
||||
private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a ClassPathScanningCandidateComponentProvider.
|
||||
* @param useDefaultFilters whether to register the default filters for the
|
||||
* {@link Component @Component}, {@link Repository @Repository},
|
||||
* {@link Service @Service}, and {@link Controller @Controller}
|
||||
* stereotype annotations
|
||||
* @see #registerDefaultFilters()
|
||||
*/
|
||||
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) {
|
||||
if (useDefaultFilters) {
|
||||
registerDefaultFilters();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the ResourceLoader to use for resource locations.
|
||||
* This will typically be a ResourcePatternResolver implementation.
|
||||
* <p>Default is PathMatchingResourcePatternResolver, also capable of
|
||||
* resource pattern resolving through the ResourcePatternResolver interface.
|
||||
* @see org.springframework.core.io.support.ResourcePatternResolver
|
||||
* @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
|
||||
*/
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ResourceLoader that this component provider uses.
|
||||
*/
|
||||
public final ResourceLoader getResourceLoader() {
|
||||
return this.resourcePatternResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource pattern to use when scanning the classpath.
|
||||
* This value will be appended to each base package name.
|
||||
* @see #findCandidateComponents(String)
|
||||
* @see #DEFAULT_RESOURCE_PATTERN
|
||||
*/
|
||||
public void setResourcePattern(String resourcePattern) {
|
||||
Assert.notNull(resourcePattern, "'resourcePattern' must not be null");
|
||||
this.resourcePattern = resourcePattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an include type filter to the <i>end</i> of the inclusion list.
|
||||
*/
|
||||
public void addIncludeFilter(TypeFilter includeFilter) {
|
||||
this.includeFilters.add(includeFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an exclude type filter to the <i>front</i> of the exclusion list.
|
||||
*/
|
||||
public void addExcludeFilter(TypeFilter excludeFilter) {
|
||||
this.excludeFilters.add(0, excludeFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the configured type filters.
|
||||
* @param useDefaultFilters whether to re-register the default filters for
|
||||
* the {@link Component @Component}, {@link Repository @Repository},
|
||||
* {@link Service @Service}, and {@link Controller @Controller}
|
||||
* stereotype annotations
|
||||
* @see #registerDefaultFilters()
|
||||
*/
|
||||
public void resetFilters(boolean useDefaultFilters) {
|
||||
this.includeFilters.clear();
|
||||
this.excludeFilters.clear();
|
||||
if (useDefaultFilters) {
|
||||
registerDefaultFilters();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the default filter for {@link Component @Component}.
|
||||
* This will implicitly register all annotations that have the
|
||||
* {@link Component @Component} meta-annotation including the
|
||||
* {@link Repository @Repository}, {@link Service @Service}, and
|
||||
* {@link Controller @Controller} stereotype annotations.
|
||||
*/
|
||||
protected void registerDefaultFilters() {
|
||||
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan the class path for candidate components.
|
||||
* @param basePackage the package to check for annotated classes
|
||||
* @return a corresponding Set of autodetected bean definitions
|
||||
*/
|
||||
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
|
||||
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
|
||||
try {
|
||||
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
|
||||
resolveBasePackage(basePackage) + "/" + this.resourcePattern;
|
||||
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
|
||||
boolean traceEnabled = logger.isTraceEnabled();
|
||||
boolean debugEnabled = logger.isDebugEnabled();
|
||||
for (int i = 0; i < resources.length; i++) {
|
||||
Resource resource = resources[i];
|
||||
if (traceEnabled) {
|
||||
logger.trace("Scanning " + resource);
|
||||
}
|
||||
if (resource.isReadable()) {
|
||||
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
|
||||
if (isCandidateComponent(metadataReader)) {
|
||||
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
|
||||
sbd.setResource(resource);
|
||||
sbd.setSource(resource);
|
||||
if (isCandidateComponent(sbd)) {
|
||||
if (debugEnabled) {
|
||||
logger.debug("Identified candidate component class: " + resource);
|
||||
}
|
||||
candidates.add(sbd);
|
||||
}
|
||||
else {
|
||||
if (debugEnabled) {
|
||||
logger.debug("Ignored because not a concrete top-level class: " + resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (traceEnabled) {
|
||||
logger.trace("Ignored because not matching any filter: " + resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (traceEnabled) {
|
||||
logger.trace("Ignored because not readable: " + resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the specified base package into a pattern specification for
|
||||
* the package search path.
|
||||
* <p>The default implementation resolves placeholders against system properties,
|
||||
* and converts a "."-based package path to a "/"-based resource path.
|
||||
* @param basePackage the base package as specified by the user
|
||||
* @return the pattern specification to be used for package searching
|
||||
*/
|
||||
protected String resolveBasePackage(String basePackage) {
|
||||
return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given class does not match any exclude filter
|
||||
* and does match at least one include filter.
|
||||
* @param metadataReader the ASM ClassReader for the class
|
||||
* @return whether the class qualifies as a candidate component
|
||||
*/
|
||||
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
|
||||
for (TypeFilter tf : this.excludeFilters) {
|
||||
if (tf.match(metadataReader, this.metadataReaderFactory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (TypeFilter tf : this.includeFilters) {
|
||||
if (tf.match(metadataReader, this.metadataReaderFactory)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given bean definition qualifies as candidate.
|
||||
* <p>The default implementation checks whether the class is concrete
|
||||
* (i.e. not abstract and not an interface). Can be overridden in subclasses.
|
||||
* @param beanDefinition the bean definition to check
|
||||
* @return whether the bean definition qualifies as a candidate component
|
||||
*/
|
||||
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
|
||||
return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,712 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.annotation.Resource;
|
||||
import javax.ejb.EJB;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.ws.Service;
|
||||
import javax.xml.ws.WebServiceClient;
|
||||
import javax.xml.ws.WebServiceRef;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.annotation.InjectionMetadata;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.jndi.support.SimpleJndiBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||||
* that supports common Java annotations out of the box, in particular the JSR-250
|
||||
* annotations in the <code>javax.annotation</code> package. These common Java
|
||||
* annotations are supported in many Java EE 5 technologies (e.g. JSF 1.2),
|
||||
* as well as in Java 6's JAX-WS.
|
||||
*
|
||||
* <p>This post-processor includes support for the {@link javax.annotation.PostConstruct}
|
||||
* and {@link javax.annotation.PreDestroy} annotations - as init annotation
|
||||
* and destroy annotation, respectively - through inheriting from
|
||||
* {@link InitDestroyAnnotationBeanPostProcessor} with pre-configured annotation types.
|
||||
*
|
||||
* <p>The central element is the {@link javax.annotation.Resource} annotation
|
||||
* for annotation-driven injection of named beans, by default from the containing
|
||||
* Spring BeanFactory, with only <code>mappedName</code> references resolved in JNDI.
|
||||
* The {@link #setAlwaysUseJndiLookup "alwaysUseJndiLookup" flag} enforces JNDI lookups
|
||||
* equivalent to standard Java EE 5 resource injection for <code>name</code> references
|
||||
* and default names as well. The target beans can be simple POJOs, with no special
|
||||
* requirements other than the type having to match.
|
||||
*
|
||||
* <p>The JAX-WS {@link javax.xml.ws.WebServiceRef} annotation is supported too,
|
||||
* analogous to {@link javax.annotation.Resource} but with the capability of creating
|
||||
* specific JAX-WS service endpoints. This may either point to an explicitly defined
|
||||
* resource by name or operate on a locally specified JAX-WS service class. Finally,
|
||||
* this post-processor also supports the EJB 3 {@link javax.ejb.EJB} annotation,
|
||||
* analogous to {@link javax.annotation.Resource} as well, with the capability to
|
||||
* specify both a local bean name and a global JNDI name for fallback retrieval.
|
||||
* The target beans can be plain POJOs as well as EJB 3 Session Beans in this case.
|
||||
*
|
||||
* <p>The common annotations supported by this post-processor are available
|
||||
* in Java 6 (JDK 1.6) as well as in Java EE 5 (which provides a standalone jar for
|
||||
* its common annotations as well, allowing for use in any Java 5 based application).
|
||||
* Hence, this post-processor works out of the box on JDK 1.6, and requires the
|
||||
* JSR-250 API jar (and optionally the JAX-WS API jar and/or the EJB 3 API jar)
|
||||
* to be added to the classpath on JDK 1.5 (when running outside of Java EE 5).
|
||||
*
|
||||
* <p>For default usage, resolving resource names as Spring bean names,
|
||||
* simply define the following in your application context:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/></pre>
|
||||
*
|
||||
* For direct JNDI access, resolving resource names as JNDI resource references
|
||||
* within the Java EE application's "java:comp/env/" namespace, use the following:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
|
||||
* <property name="alwaysUseJndiLookup" value="true"/>
|
||||
* </bean></pre>
|
||||
*
|
||||
* <code>mappedName</code> references will always be resolved in JNDI,
|
||||
* allowing for global JNDI names (including "java:" prefix) as well. The
|
||||
* "alwaysUseJndiLookup" flag just affects <code>name</code> references and
|
||||
* default names (inferred from the field name / property name).
|
||||
*
|
||||
* <p><b>NOTE:</b> A default CommonAnnotationBeanPostProcessor will be registered
|
||||
* by the "context:annotation-config" and "context:component-scan" XML tags.
|
||||
* Remove or turn off the default annotation configuration there if you intend
|
||||
* to specify a custom CommonAnnotationBeanPostProcessor bean definition!
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see #setAlwaysUseJndiLookup
|
||||
* @see #setResourceFactory
|
||||
* @see org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor
|
||||
* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
|
||||
*/
|
||||
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
|
||||
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
|
||||
|
||||
private static Class<? extends Annotation> webServiceRefClass = null;
|
||||
|
||||
private static Class<? extends Annotation> ejbRefClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
webServiceRefClass = ClassUtils.forName("javax.xml.ws.WebServiceRef",
|
||||
CommonAnnotationBeanPostProcessor.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
webServiceRefClass = null;
|
||||
}
|
||||
try {
|
||||
ejbRefClass = ClassUtils.forName("javax.ejb.EJB",
|
||||
CommonAnnotationBeanPostProcessor.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
ejbRefClass = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Set<String> ignoredResourceTypes = new HashSet<String>(1);
|
||||
|
||||
private boolean fallbackToDefaultTypeMatch = true;
|
||||
|
||||
private boolean alwaysUseJndiLookup = false;
|
||||
|
||||
private transient BeanFactory jndiFactory = new SimpleJndiBeanFactory();
|
||||
|
||||
private transient BeanFactory resourceFactory;
|
||||
|
||||
private transient BeanFactory beanFactory;
|
||||
|
||||
private transient final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
|
||||
new ConcurrentHashMap<Class<?>, InjectionMetadata>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new CommonAnnotationBeanPostProcessor,
|
||||
* with the init and destroy annotation types set to
|
||||
* {@link javax.annotation.PostConstruct} and {@link javax.annotation.PreDestroy},
|
||||
* respectively.
|
||||
*/
|
||||
public CommonAnnotationBeanPostProcessor() {
|
||||
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
|
||||
setInitAnnotationType(PostConstruct.class);
|
||||
setDestroyAnnotationType(PreDestroy.class);
|
||||
ignoreResourceType("javax.xml.ws.WebServiceContext");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ignore the given resource type when resolving <code>@Resource</code>
|
||||
* annotations.
|
||||
* <p>By default, the <code>javax.xml.ws.WebServiceContext</code> interface
|
||||
* will be ignored, since it will be resolved by the JAX-WS runtime.
|
||||
* @param resourceType the resource type to ignore
|
||||
*/
|
||||
public void ignoreResourceType(String resourceType) {
|
||||
Assert.notNull(resourceType, "Ignored resource type must not be null");
|
||||
this.ignoredResourceTypes.add(resourceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to allow a fallback to a type match if no explicit name has been
|
||||
* specified. The default name (i.e. the field name or bean property name) will
|
||||
* still be checked first; if a bean of that name exists, it will be taken.
|
||||
* However, if no bean of that name exists, a by-type resolution of the
|
||||
* dependency will be attempted if this flag is "true".
|
||||
* <p>Default is "true". Switch this flag to "false" in order to enforce a
|
||||
* by-name lookup in all cases, throwing an exception in case of no name match.
|
||||
* @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#resolveDependency
|
||||
*/
|
||||
public void setFallbackToDefaultTypeMatch(boolean fallbackToDefaultTypeMatch) {
|
||||
this.fallbackToDefaultTypeMatch = fallbackToDefaultTypeMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to always use JNDI lookups equivalent to standard Java EE 5 resource
|
||||
* injection, <b>even for <code>name</code> attributes and default names</b>.
|
||||
* <p>Default is "false": Resource names are used for Spring bean lookups in the
|
||||
* containing BeanFactory; only <code>mappedName</code> attributes point directly
|
||||
* into JNDI. Switch this flag to "true" for enforcing Java EE style JNDI lookups
|
||||
* in any case, even for <code>name</code> attributes and default names.
|
||||
* @see #setJndiFactory
|
||||
* @see #setResourceFactory
|
||||
*/
|
||||
public void setAlwaysUseJndiLookup(boolean alwaysUseJndiLookup) {
|
||||
this.alwaysUseJndiLookup = alwaysUseJndiLookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the factory for objects to be injected into <code>@Resource</code> /
|
||||
* <code>@WebServiceRef</code> / <code>@EJB</code> annotated fields and setter methods,
|
||||
* <b>for <code>mappedName</code> attributes that point directly into JNDI</b>.
|
||||
* This factory will also be used if "alwaysUseJndiLookup" is set to "true" in order
|
||||
* to enforce JNDI lookups even for <code>name</code> attributes and default names.
|
||||
* <p>The default is a {@link org.springframework.jndi.support.SimpleJndiBeanFactory}
|
||||
* for JNDI lookup behavior equivalent to standard Java EE 5 resource injection.
|
||||
* @see #setResourceFactory
|
||||
* @see #setAlwaysUseJndiLookup
|
||||
*/
|
||||
public void setJndiFactory(BeanFactory jndiFactory) {
|
||||
Assert.notNull(jndiFactory, "BeanFactory must not be null");
|
||||
this.jndiFactory = jndiFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the factory for objects to be injected into <code>@Resource</code> /
|
||||
* <code>@WebServiceRef</code> / <code>@EJB</code> annotated fields and setter methods,
|
||||
* <b>for <code>name</code> attributes and default names</b>.
|
||||
* <p>The default is the BeanFactory that this post-processor is defined in,
|
||||
* if any, looking up resource names as Spring bean names. Specify the resource
|
||||
* factory explicitly for programmatic usage of this post-processor.
|
||||
* <p>Specifying Spring's {@link org.springframework.jndi.support.SimpleJndiBeanFactory}
|
||||
* leads to JNDI lookup behavior equivalent to standard Java EE 5 resource injection,
|
||||
* even for <code>name</code> attributes and default names. This is the same behavior
|
||||
* that the "alwaysUseJndiLookup" flag enables.
|
||||
* @see #setAlwaysUseJndiLookup
|
||||
*/
|
||||
public void setResourceFactory(BeanFactory resourceFactory) {
|
||||
Assert.notNull(resourceFactory, "BeanFactory must not be null");
|
||||
this.resourceFactory = resourceFactory;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
this.beanFactory = beanFactory;
|
||||
if (this.resourceFactory == null) {
|
||||
this.resourceFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) {
|
||||
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
|
||||
if (beanType != null) {
|
||||
InjectionMetadata metadata = findResourceMetadata(beanType);
|
||||
metadata.checkConfigMembers(beanDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
|
||||
InjectionMetadata metadata = findResourceMetadata(bean.getClass());
|
||||
try {
|
||||
metadata.injectFields(bean, beanName);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(beanName, "Injection of resource fields failed", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public PropertyValues postProcessPropertyValues(
|
||||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
|
||||
|
||||
InjectionMetadata metadata = findResourceMetadata(bean.getClass());
|
||||
try {
|
||||
metadata.injectMethods(bean, beanName, pvs);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanCreationException(beanName, "Injection of resource methods failed", ex);
|
||||
}
|
||||
return pvs;
|
||||
}
|
||||
|
||||
|
||||
private InjectionMetadata findResourceMetadata(final Class clazz) {
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
|
||||
if (metadata == null) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
metadata = this.injectionMetadataCache.get(clazz);
|
||||
if (metadata == null) {
|
||||
final InjectionMetadata newMetadata = new InjectionMetadata(clazz);
|
||||
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
|
||||
public void doWith(Field field) {
|
||||
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
|
||||
}
|
||||
newMetadata.addInjectedField(new WebServiceRefElement(field, null));
|
||||
}
|
||||
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static fields");
|
||||
}
|
||||
newMetadata.addInjectedField(new EjbRefElement(field, null));
|
||||
}
|
||||
else if (field.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static fields");
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(field.getType().getName())) {
|
||||
newMetadata.addInjectedField(new ResourceElement(field, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method method) {
|
||||
if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
newMetadata.addInjectedMethod(new WebServiceRefElement(method, pd));
|
||||
}
|
||||
else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
newMetadata.addInjectedMethod(new EjbRefElement(method, pd));
|
||||
}
|
||||
else if (method.isAnnotationPresent(Resource.class) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static methods");
|
||||
}
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
newMetadata.addInjectedMethod(new ResourceElement(method, pd));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
metadata = newMetadata;
|
||||
this.injectionMetadataCache.put(clazz, metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the resource object for the given name and type.
|
||||
* @param element the descriptor for the annotated field/method
|
||||
* @param requestingBeanName the name of the requesting bean
|
||||
* @return the resource object (never <code>null</code>)
|
||||
* @throws BeansException if we failed to obtain the target resource
|
||||
*/
|
||||
protected Object getResource(LookupElement element, String requestingBeanName) throws BeansException {
|
||||
if (StringUtils.hasLength(element.mappedName)) {
|
||||
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
|
||||
}
|
||||
if (this.alwaysUseJndiLookup) {
|
||||
return this.jndiFactory.getBean(element.name, element.lookupType);
|
||||
}
|
||||
if (this.resourceFactory == null) {
|
||||
throw new NoSuchBeanDefinitionException(element.lookupType,
|
||||
"No resource factory configured - specify the 'resourceFactory' property");
|
||||
}
|
||||
return autowireResource(this.resourceFactory, element, requestingBeanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a resource object for the given name and type through autowiring
|
||||
* based on the given factory.
|
||||
* @param factory the factory to autowire against
|
||||
* @param element the descriptor for the annotated field/method
|
||||
* @param requestingBeanName the name of the requesting bean
|
||||
* @return the resource object (never <code>null</code>)
|
||||
* @throws BeansException if we failed to obtain the target resource
|
||||
*/
|
||||
protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName)
|
||||
throws BeansException {
|
||||
|
||||
Object resource = null;
|
||||
Set<String> autowiredBeanNames = null;
|
||||
String name = element.name;
|
||||
|
||||
if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
|
||||
factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
|
||||
autowiredBeanNames = new LinkedHashSet<String>();
|
||||
resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
|
||||
element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
|
||||
}
|
||||
else {
|
||||
resource = factory.getBean(name, element.lookupType);
|
||||
autowiredBeanNames = Collections.singleton(name);
|
||||
}
|
||||
|
||||
if (factory instanceof ConfigurableBeanFactory) {
|
||||
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
|
||||
for (String autowiredBeanName : autowiredBeanNames) {
|
||||
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class representing generic injection information about an annotated field
|
||||
* or setter method, supporting @Resource and related annotations.
|
||||
*/
|
||||
protected abstract class LookupElement extends InjectionMetadata.InjectedElement {
|
||||
|
||||
protected String name;
|
||||
|
||||
protected boolean isDefaultName = false;
|
||||
|
||||
protected Class<?> lookupType;
|
||||
|
||||
protected String mappedName;
|
||||
|
||||
public LookupElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
initAnnotation((AnnotatedElement) member);
|
||||
}
|
||||
|
||||
protected abstract void initAnnotation(AnnotatedElement ae);
|
||||
|
||||
/**
|
||||
* Return the resource name for the lookup.
|
||||
*/
|
||||
public final String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the desired type for the lookup.
|
||||
*/
|
||||
public final Class<?> getLookupType() {
|
||||
return this.lookupType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a DependencyDescriptor for the underlying field/method.
|
||||
*/
|
||||
public final DependencyDescriptor getDependencyDescriptor() {
|
||||
if (this.isField) {
|
||||
return new LookupDependencyDescriptor((Field) this.member, this.lookupType);
|
||||
}
|
||||
else {
|
||||
return new LookupDependencyDescriptor((Method) this.member, this.lookupType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class representing injection information about an annotated field
|
||||
* or setter method, supporting the @Resource annotation.
|
||||
*/
|
||||
private class ResourceElement extends LookupElement {
|
||||
|
||||
protected boolean shareable = true;
|
||||
|
||||
public ResourceElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
}
|
||||
|
||||
protected void initAnnotation(AnnotatedElement ae) {
|
||||
Resource resource = ae.getAnnotation(Resource.class);
|
||||
String resourceName = resource.name();
|
||||
Class resourceType = resource.type();
|
||||
this.isDefaultName = !StringUtils.hasLength(resourceName);
|
||||
if (this.isDefaultName) {
|
||||
resourceName = this.member.getName();
|
||||
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
|
||||
resourceName = Introspector.decapitalize(resourceName.substring(3));
|
||||
}
|
||||
}
|
||||
if (resourceType != null && !Object.class.equals(resourceType)) {
|
||||
checkResourceType(resourceType);
|
||||
}
|
||||
else {
|
||||
// No resource type specified... check field/method.
|
||||
resourceType = getResourceType();
|
||||
}
|
||||
this.name = resourceName;
|
||||
this.lookupType = resourceType;
|
||||
this.mappedName = resource.mappedName();
|
||||
this.shareable = resource.shareable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getResourceToInject(Object target, String requestingBeanName) {
|
||||
return getResource(this, requestingBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class representing injection information about an annotated field
|
||||
* or setter method, supporting the @WebServiceRef annotation.
|
||||
*/
|
||||
private class WebServiceRefElement extends LookupElement {
|
||||
|
||||
private Class elementType;
|
||||
|
||||
private String wsdlLocation;
|
||||
|
||||
public WebServiceRefElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
}
|
||||
|
||||
protected void initAnnotation(AnnotatedElement ae) {
|
||||
WebServiceRef resource = ae.getAnnotation(WebServiceRef.class);
|
||||
String resourceName = resource.name();
|
||||
Class resourceType = resource.type();
|
||||
this.isDefaultName = !StringUtils.hasLength(resourceName);
|
||||
if (this.isDefaultName) {
|
||||
resourceName = this.member.getName();
|
||||
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
|
||||
resourceName = Introspector.decapitalize(resourceName.substring(3));
|
||||
}
|
||||
}
|
||||
if (resourceType != null && !Object.class.equals(resourceType)) {
|
||||
checkResourceType(resourceType);
|
||||
}
|
||||
else {
|
||||
// No resource type specified... check field/method.
|
||||
resourceType = getResourceType();
|
||||
}
|
||||
this.name = resourceName;
|
||||
this.elementType = resourceType;
|
||||
if (Service.class.isAssignableFrom(resourceType)) {
|
||||
this.lookupType = resourceType;
|
||||
}
|
||||
else {
|
||||
this.lookupType = (!Object.class.equals(resource.value()) ? resource.value() : Service.class);
|
||||
}
|
||||
this.mappedName = resource.mappedName();
|
||||
this.wsdlLocation = resource.wsdlLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getResourceToInject(Object target, String requestingBeanName) {
|
||||
Service service = null;
|
||||
try {
|
||||
service = (Service) getResource(this, requestingBeanName);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException notFound) {
|
||||
// Service to be created through generated class.
|
||||
if (Service.class.equals(this.lookupType)) {
|
||||
throw new IllegalStateException("No resource with name '" + this.name + "' found in context, " +
|
||||
"and no specific JAX-WS Service subclass specified. The typical solution is to either specify " +
|
||||
"a LocalJaxWsServiceFactoryBean with the given name or to specify the (generated) Service " +
|
||||
"subclass as @WebServiceRef(...) value.");
|
||||
}
|
||||
if (StringUtils.hasLength(this.wsdlLocation)) {
|
||||
try {
|
||||
Constructor ctor = this.lookupType.getConstructor(new Class[] {URL.class, QName.class});
|
||||
WebServiceClient clientAnn = this.lookupType.getAnnotation(WebServiceClient.class);
|
||||
if (clientAnn == null) {
|
||||
throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +
|
||||
"] does not carry a WebServiceClient annotation");
|
||||
}
|
||||
service = (Service) BeanUtils.instantiateClass(ctor,
|
||||
new Object[] {new URL(this.wsdlLocation), new QName(clientAnn.targetNamespace(), clientAnn.name())});
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +
|
||||
"] does not have a (URL, QName) constructor. Cannot apply specified WSDL location [" +
|
||||
this.wsdlLocation + "].");
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
"Specified WSDL location [" + this.wsdlLocation + "] isn't a valid URL");
|
||||
}
|
||||
}
|
||||
else {
|
||||
service = (Service) BeanUtils.instantiateClass(this.lookupType);
|
||||
}
|
||||
}
|
||||
return service.getPort(this.elementType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class representing injection information about an annotated field
|
||||
* or setter method, supporting the @EJB annotation.
|
||||
*/
|
||||
private class EjbRefElement extends LookupElement {
|
||||
|
||||
private String beanName;
|
||||
|
||||
public EjbRefElement(Member member, PropertyDescriptor pd) {
|
||||
super(member, pd);
|
||||
}
|
||||
|
||||
protected void initAnnotation(AnnotatedElement ae) {
|
||||
EJB resource = ae.getAnnotation(EJB.class);
|
||||
String resourceBeanName = resource.beanName();
|
||||
String resourceName = resource.name();
|
||||
this.isDefaultName = !StringUtils.hasLength(resourceName);
|
||||
if (this.isDefaultName) {
|
||||
resourceName = this.member.getName();
|
||||
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
|
||||
resourceName = Introspector.decapitalize(resourceName.substring(3));
|
||||
}
|
||||
}
|
||||
Class resourceType = resource.beanInterface();
|
||||
if (resourceType != null && !Object.class.equals(resourceType)) {
|
||||
checkResourceType(resourceType);
|
||||
}
|
||||
else {
|
||||
// No resource type specified... check field/method.
|
||||
resourceType = getResourceType();
|
||||
}
|
||||
this.beanName = resourceBeanName;
|
||||
this.name = resourceName;
|
||||
this.lookupType = resourceType;
|
||||
this.mappedName = resource.mappedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getResourceToInject(Object target, String requestingBeanName) {
|
||||
if (StringUtils.hasLength(this.beanName)) {
|
||||
if (beanFactory != null && beanFactory.containsBean(this.beanName)) {
|
||||
// Local match found for explicitly specified local bean name.
|
||||
Object bean = beanFactory.getBean(this.beanName, this.lookupType);
|
||||
if (beanFactory instanceof ConfigurableBeanFactory) {
|
||||
((ConfigurableBeanFactory) beanFactory).registerDependentBean(this.beanName, requestingBeanName);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
else if (this.isDefaultName && !StringUtils.hasLength(this.mappedName)) {
|
||||
throw new NoSuchBeanDefinitionException(this.beanName,
|
||||
"Cannot resolve 'beanName' in local BeanFactory. Consider specifying a general 'name' value instead.");
|
||||
}
|
||||
}
|
||||
// JNDI name lookup - may still go to a local BeanFactory.
|
||||
return getResource(this, requestingBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension of the DependencyDescriptor class,
|
||||
* overriding the dependency type with the specified resource type.
|
||||
*/
|
||||
private static class LookupDependencyDescriptor extends DependencyDescriptor {
|
||||
|
||||
private final Class lookupType;
|
||||
|
||||
public LookupDependencyDescriptor(Field field, Class lookupType) {
|
||||
super(field, true);
|
||||
this.lookupType = lookupType;
|
||||
}
|
||||
|
||||
public LookupDependencyDescriptor(Method method, Class lookupType) {
|
||||
super(new MethodParameter(method, 0), true);
|
||||
this.lookupType = lookupType;
|
||||
}
|
||||
|
||||
public Class getDependencyType() {
|
||||
return this.lookupType;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AspectJTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <context:component-scan/> element.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Ramnivas Laddad
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";
|
||||
|
||||
private static final String RESOURCE_PATTERN_ATTRIBUTE = "resource-pattern";
|
||||
|
||||
private static final String USE_DEFAULT_FILTERS_ATTRIBUTE = "use-default-filters";
|
||||
|
||||
private static final String ANNOTATION_CONFIG_ATTRIBUTE = "annotation-config";
|
||||
|
||||
private static final String NAME_GENERATOR_ATTRIBUTE = "name-generator";
|
||||
|
||||
private static final String SCOPE_RESOLVER_ATTRIBUTE = "scope-resolver";
|
||||
|
||||
private static final String SCOPED_PROXY_ATTRIBUTE = "scoped-proxy";
|
||||
|
||||
private static final String EXCLUDE_FILTER_ELEMENT = "exclude-filter";
|
||||
|
||||
private static final String INCLUDE_FILTER_ELEMENT = "include-filter";
|
||||
|
||||
private static final String FILTER_TYPE_ATTRIBUTE = "type";
|
||||
|
||||
private static final String FILTER_EXPRESSION_ATTRIBUTE = "expression";
|
||||
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String[] basePackages =
|
||||
StringUtils.commaDelimitedListToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE));
|
||||
|
||||
// Actually scan for bean definitions and register them.
|
||||
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
|
||||
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
|
||||
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
|
||||
XmlReaderContext readerContext = parserContext.getReaderContext();
|
||||
|
||||
boolean useDefaultFilters = true;
|
||||
if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
|
||||
useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
|
||||
}
|
||||
|
||||
// Delegate bean definition registration to scanner class.
|
||||
ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters);
|
||||
scanner.setResourceLoader(readerContext.getResourceLoader());
|
||||
scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
|
||||
scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
|
||||
|
||||
if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
|
||||
scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
|
||||
}
|
||||
|
||||
try {
|
||||
parseBeanNameGenerator(element, scanner);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
|
||||
}
|
||||
|
||||
try {
|
||||
parseScope(element, scanner);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
|
||||
}
|
||||
|
||||
parseTypeFilters(element, scanner, readerContext);
|
||||
|
||||
return scanner;
|
||||
}
|
||||
|
||||
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
|
||||
return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);
|
||||
}
|
||||
|
||||
protected void registerComponents(
|
||||
XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
|
||||
|
||||
Object source = readerContext.extractSource(element);
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
|
||||
|
||||
for (Iterator it = beanDefinitions.iterator(); it.hasNext();) {
|
||||
BeanDefinitionHolder beanDefHolder = (BeanDefinitionHolder) it.next();
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
|
||||
}
|
||||
|
||||
// Register annotation config processors, if necessary.
|
||||
boolean annotationConfig = true;
|
||||
if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
|
||||
annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
|
||||
}
|
||||
if (annotationConfig) {
|
||||
Set<BeanDefinitionHolder> processorDefinitions =
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
|
||||
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
|
||||
}
|
||||
}
|
||||
|
||||
readerContext.fireComponentRegistered(compositeDef);
|
||||
}
|
||||
|
||||
protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) {
|
||||
if (element.hasAttribute(NAME_GENERATOR_ATTRIBUTE)) {
|
||||
BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy(
|
||||
element.getAttribute(NAME_GENERATOR_ATTRIBUTE), BeanNameGenerator.class,
|
||||
scanner.getResourceLoader().getClassLoader());
|
||||
scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) {
|
||||
// Register ScopeMetadataResolver if class name provided.
|
||||
if (element.hasAttribute(SCOPE_RESOLVER_ATTRIBUTE)) {
|
||||
if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");
|
||||
}
|
||||
ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(
|
||||
element.getAttribute(SCOPE_RESOLVER_ATTRIBUTE), ScopeMetadataResolver.class,
|
||||
scanner.getResourceLoader().getClassLoader());
|
||||
scanner.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
}
|
||||
|
||||
if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
|
||||
String mode = element.getAttribute(SCOPED_PROXY_ATTRIBUTE);
|
||||
if ("targetClass".equals(mode)) {
|
||||
scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS);
|
||||
}
|
||||
else if ("interfaces".equals(mode)) {
|
||||
scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES);
|
||||
}
|
||||
else if ("no".equals(mode)) {
|
||||
scanner.setScopedProxyMode(ScopedProxyMode.NO);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseTypeFilters(
|
||||
Element element, ClassPathBeanDefinitionScanner scanner, XmlReaderContext readerContext) {
|
||||
|
||||
// Parse exclude and include filter elements.
|
||||
ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
|
||||
NodeList nodeList = element.getChildNodes();
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node node = nodeList.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
String localName = node.getLocalName();
|
||||
try {
|
||||
if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
|
||||
TypeFilter typeFilter = createTypeFilter((Element) node, classLoader);
|
||||
scanner.addIncludeFilter(typeFilter);
|
||||
}
|
||||
else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
|
||||
TypeFilter typeFilter = createTypeFilter((Element) node, classLoader);
|
||||
scanner.addExcludeFilter(typeFilter);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader) {
|
||||
String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
|
||||
String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
|
||||
try {
|
||||
if ("annotation".equals(filterType)) {
|
||||
return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
|
||||
}
|
||||
else if ("assignable".equals(filterType)) {
|
||||
return new AssignableTypeFilter(classLoader.loadClass(expression));
|
||||
}
|
||||
else if ("aspectj".equals(filterType)) {
|
||||
return new AspectJTypeFilter(expression, classLoader);
|
||||
}
|
||||
else if ("regex".equals(filterType)) {
|
||||
return new RegexPatternTypeFilter(Pattern.compile(expression));
|
||||
}
|
||||
else if ("custom".equals(filterType)) {
|
||||
Class filterClass = classLoader.loadClass(expression);
|
||||
if (!TypeFilter.class.isAssignableFrom(filterClass)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
|
||||
}
|
||||
return (TypeFilter) BeanUtils.instantiateClass(filterClass);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported filter type: " + filterType);
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new FatalBeanException("Type filter class not found: " + expression, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object instantiateUserDefinedStrategy(String className, Class strategyType, ClassLoader classLoader) {
|
||||
Object result = null;
|
||||
try {
|
||||
result = classLoader.loadClass(className).newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalArgumentException("Class [" + className + "] for strategy [" +
|
||||
strategyType.getName() + "] not found", ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
|
||||
strategyType.getName() + "]. A zero-argument constructor is required", ex);
|
||||
}
|
||||
|
||||
if (!strategyType.isAssignableFrom(result.getClass())) {
|
||||
throw new IllegalArgumentException("Provided class name must be an implementation of " + strategyType);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.springframework.context.annotation;
|
||||
|
||||
/**
|
||||
* Enumeration of the valid type filters to be added for annotation-driven configuration.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public enum FilterType {
|
||||
|
||||
ANNOTATION,
|
||||
ASSIGNABLE_TYPE,
|
||||
ASPECTJ_PATTERN,
|
||||
REGEX_PATTERN,
|
||||
CUSTOM
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extension of the {@link org.springframework.beans.factory.support.GenericBeanDefinition}
|
||||
* class, based on an ASM ClassReader, with support for annotation metadata exposed
|
||||
* through the {@link AnnotatedBeanDefinition} interface.
|
||||
*
|
||||
* <p>This class does <i>not</i> load the bean <code>Class</code> early.
|
||||
* It rather retrieves all relevant metadata from the ".class" file itself,
|
||||
* parsed with the ASM ClassReader.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see #getMetadata()
|
||||
* @see #getBeanClassName()
|
||||
* @see org.springframework.core.type.classreading.MetadataReaderFactory
|
||||
*/
|
||||
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
|
||||
|
||||
private final AnnotationMetadata metadata;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ScannedGenericBeanDefinition for the class that the
|
||||
* given MetadataReader describes.
|
||||
* @param metadataReader the MetadataReader for the scanned target class
|
||||
*/
|
||||
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
|
||||
Assert.notNull(metadataReader, "MetadataReader must not be null");
|
||||
this.metadata = metadataReader.getAnnotationMetadata();
|
||||
setBeanClassName(this.metadata.getClassName());
|
||||
}
|
||||
|
||||
|
||||
public final AnnotationMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
||||
/**
|
||||
* Indicates the name of a scope to use for instances of the annotated class.
|
||||
*
|
||||
* <p>In this context, scope means the lifecycle of an instance, such as
|
||||
* '<code>singleton</code>', '<code>prototype</code>', and so forth.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Scope {
|
||||
|
||||
/**
|
||||
* Specifies the scope to use for instances of the annotated class.
|
||||
* @return the desired scope
|
||||
*/
|
||||
String value() default BeanDefinition.SCOPE_SINGLETON;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
||||
/**
|
||||
* Describes scope characteristics for a Spring-managed bean including the scope
|
||||
* name and the scoped-proxy behavior.
|
||||
*
|
||||
* <p>The default scope is "singleton", and the default is to <i>not</i> create
|
||||
* scoped-proxies.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see ScopeMetadataResolver
|
||||
* @see ScopedProxyMode
|
||||
*/
|
||||
public class ScopeMetadata {
|
||||
|
||||
private String scopeName = BeanDefinition.SCOPE_SINGLETON;
|
||||
|
||||
private ScopedProxyMode scopedProxyMode = ScopedProxyMode.NO;
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the scope.
|
||||
* @return said scope name
|
||||
*/
|
||||
public String getScopeName() {
|
||||
return scopeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the scope.
|
||||
* @param scopeName said scope name
|
||||
*/
|
||||
public void setScopeName(String scopeName) {
|
||||
this.scopeName = scopeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the proxy-mode to be applied to the scoped instance.
|
||||
* @return said scoped-proxy mode
|
||||
*/
|
||||
public ScopedProxyMode getScopedProxyMode() {
|
||||
return scopedProxyMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the proxy-mode to be applied to the scoped instance.
|
||||
* @param scopedProxyMode said scoped-proxy mode
|
||||
*/
|
||||
public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
|
||||
this.scopedProxyMode = scopedProxyMode;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.annotation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
||||
/**
|
||||
* Strategy interface for resolving the scope of bean definitions.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see Scope
|
||||
*/
|
||||
public interface ScopeMetadataResolver {
|
||||
|
||||
/**
|
||||
* Resolve the {@link ScopeMetadata} appropriate to the supplied
|
||||
* bean <code>definition</code>.
|
||||
* <p>Implementations can of course use any strategy they like to
|
||||
* determine the scope metadata, but some implementations that spring
|
||||
* immediately to mind might be to use source level annotations
|
||||
* present on {@link BeanDefinition#getBeanClassName() the class} of the
|
||||
* supplied <code>definition</code>, or to use metadata present in the
|
||||
* {@link BeanDefinition#attributeNames()} of the supplied <code>definition</code>.
|
||||
* @param definition the target bean definition
|
||||
* @return the relevant scope metadata; never <code>null</code>
|
||||
*/
|
||||
ScopeMetadata resolveScopeMetadata(BeanDefinition definition);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.annotation;
|
||||
|
||||
/**
|
||||
* Enumerates the various scoped-proxy options.
|
||||
*
|
||||
* <p>For a fuller discussion of exactly what a scoped-proxy is, see that
|
||||
* section of the Spring reference documentation entitled 'Scoped beans as
|
||||
* dependencies'.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see ScopeMetadata
|
||||
*/
|
||||
public enum ScopedProxyMode {
|
||||
|
||||
/**
|
||||
* Do not create a scoped proxy.
|
||||
* <p>This proxy-mode is not typically useful when used with a
|
||||
* non-singleton scoped instance, which should favor the use of the
|
||||
* {@link #INTERFACES} or {@link #TARGET_CLASS} proxy-modes instead if it
|
||||
* is to be used as a dependency.
|
||||
*/
|
||||
NO,
|
||||
|
||||
/**
|
||||
* Create a JDK dynamic proxy implementing <i>all</i> interfaces exposed by
|
||||
* the class of the target object.
|
||||
*/
|
||||
INTERFACES,
|
||||
|
||||
/**
|
||||
* Create a class-based proxy (requires CGLIB).
|
||||
*/
|
||||
TARGET_CLASS
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Annotation support for context configuration,
|
||||
including classpath scanning for autowire candidates.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.springframework.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract parser for <context:property-.../> elements.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
* @since 2.5.2
|
||||
*/
|
||||
abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
protected boolean shouldGenerateId() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
String location = element.getAttribute("location");
|
||||
if (StringUtils.hasLength(location)) {
|
||||
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
|
||||
builder.addPropertyValue("locations", locations);
|
||||
}
|
||||
String propertiesRef = element.getAttribute("properties-ref");
|
||||
if (StringUtils.hasLength(propertiesRef)) {
|
||||
builder.addPropertyReference("properties", propertiesRef);
|
||||
}
|
||||
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.springframework.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.JdkVersion;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.NamespaceHandler}
|
||||
* for the '<code>context</code>' namespace.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
|
||||
registerJava5DependentParser("annotation-config",
|
||||
"org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser");
|
||||
registerJava5DependentParser("component-scan",
|
||||
"org.springframework.context.annotation.ComponentScanBeanDefinitionParser");
|
||||
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
|
||||
}
|
||||
|
||||
private void registerJava5DependentParser(final String elementName, final String parserClassName) {
|
||||
BeanDefinitionParser parser = null;
|
||||
if (JdkVersion.isAtLeastJava15()) {
|
||||
try {
|
||||
Class parserClass = ClassUtils.forName(parserClassName, ContextNamespaceHandler.class.getClassLoader());
|
||||
parser = (BeanDefinitionParser) parserClass.newInstance();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Unable to create Java 1.5 dependent parser: " + parserClassName, ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
parser = new BeanDefinitionParser() {
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
throw new IllegalStateException("Context namespace element '" + elementName +
|
||||
"' and its parser class [" + parserClassName + "] are only available on JDK 1.5 and higher");
|
||||
}
|
||||
};
|
||||
}
|
||||
registerBeanDefinitionParser(elementName, parser);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <context:load-time-weaver/> element.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
class LoadTimeWeaverBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String WEAVER_CLASS_ATTRIBUTE = "weaver-class";
|
||||
|
||||
private static final String ASPECTJ_WEAVING_ATTRIBUTE = "aspectj-weaving";
|
||||
|
||||
private static final String ASPECTJ_AOP_XML_RESOURCE = "META-INF/aop.xml";
|
||||
|
||||
private static final String DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME =
|
||||
"org.springframework.context.weaving.DefaultContextLoadTimeWeaver";
|
||||
|
||||
private static final String ASPECTJ_WEAVING_ENABLER_CLASS_NAME =
|
||||
"org.springframework.context.weaving.AspectJWeavingEnabler";
|
||||
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
if (element.hasAttribute(WEAVER_CLASS_ATTRIBUTE)) {
|
||||
return element.getAttribute(WEAVER_CLASS_ATTRIBUTE);
|
||||
}
|
||||
return DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME;
|
||||
}
|
||||
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
|
||||
return ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) {
|
||||
RootBeanDefinition weavingEnablerDef = new RootBeanDefinition();
|
||||
weavingEnablerDef.setBeanClassName(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);
|
||||
parserContext.getReaderContext().registerWithGeneratedName(weavingEnablerDef);
|
||||
|
||||
if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) {
|
||||
new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAspectJWeavingEnabled(String value, ParserContext parserContext) {
|
||||
if ("on".equals(value)) {
|
||||
return true;
|
||||
}
|
||||
else if ("off".equals(value)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// Determine default...
|
||||
ClassLoader cl = parserContext.getReaderContext().getResourceLoader().getClassLoader();
|
||||
return (cl.getResource(ASPECTJ_AOP_XML_RESOURCE) != null);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isBeanConfigurerAspectEnabled(ClassLoader beanClassLoader) {
|
||||
return ClassUtils.isPresent(SpringConfiguredBeanDefinitionParser.BEAN_CONFIGURER_ASPECT_CLASS_NAME,
|
||||
beanClassLoader);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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.springframework.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.JdkVersion;
|
||||
import org.springframework.jmx.support.MBeanRegistrationSupport;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <context:mbean-export/> element.
|
||||
*
|
||||
* <p>Registers an instance of
|
||||
* {@link org.springframework.jmx.export.annotation.AnnotationMBeanExporter}
|
||||
* within the context.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 2.5
|
||||
* @see org.springframework.jmx.export.annotation.AnnotationMBeanExporter
|
||||
*/
|
||||
class MBeanExportBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter";
|
||||
|
||||
private static final String DEFAULT_DOMAIN_ATTRIBUTE = "default-domain";
|
||||
|
||||
private static final String SERVER_ATTRIBUTE = "server";
|
||||
|
||||
private static final String REGISTRATION_ATTRIBUTE = "registration";
|
||||
|
||||
private static final String REGISTRATION_IGNORE_EXISTING = "ignoreExisting";
|
||||
|
||||
private static final String REGISTRATION_REPLACE_EXISTING = "replaceExisting";
|
||||
|
||||
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
|
||||
return MBEAN_EXPORTER_BEAN_NAME;
|
||||
}
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
String beanClassName = (JdkVersion.isAtLeastJava15() ?
|
||||
"org.springframework.jmx.export.annotation.AnnotationMBeanExporter" :
|
||||
"org.springframework.jmx.export.MBeanExporter");
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(beanClassName);
|
||||
|
||||
// Mark as infrastructure bean and attach source location.
|
||||
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
|
||||
|
||||
String defaultDomain = element.getAttribute(DEFAULT_DOMAIN_ATTRIBUTE);
|
||||
if (StringUtils.hasText(defaultDomain)) {
|
||||
builder.addPropertyValue("defaultDomain", defaultDomain);
|
||||
}
|
||||
|
||||
String serverBeanName = element.getAttribute(SERVER_ATTRIBUTE);
|
||||
if (StringUtils.hasText(serverBeanName)) {
|
||||
builder.addPropertyReference("server", serverBeanName);
|
||||
}
|
||||
else {
|
||||
AbstractBeanDefinition specialServer = MBeanServerBeanDefinitionParser.findServerForSpecialEnvironment();
|
||||
if (specialServer != null) {
|
||||
builder.addPropertyValue("server", specialServer);
|
||||
}
|
||||
}
|
||||
|
||||
String registration = element.getAttribute(REGISTRATION_ATTRIBUTE);
|
||||
int registrationBehavior = MBeanRegistrationSupport.REGISTRATION_FAIL_ON_EXISTING;
|
||||
if (REGISTRATION_IGNORE_EXISTING.equals(registration)) {
|
||||
registrationBehavior = MBeanRegistrationSupport.REGISTRATION_IGNORE_EXISTING;
|
||||
}
|
||||
else if (REGISTRATION_REPLACE_EXISTING.equals(registration)) {
|
||||
registrationBehavior = MBeanRegistrationSupport.REGISTRATION_REPLACE_EXISTING;
|
||||
}
|
||||
builder.addPropertyValue("registrationBehavior", new Integer(registrationBehavior));
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.springframework.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.jmx.support.MBeanServerFactoryBean;
|
||||
import org.springframework.jmx.support.WebSphereMBeanServerFactoryBean;
|
||||
import org.springframework.jndi.JndiObjectFactoryBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <context:mbean-server/> element.
|
||||
*
|
||||
* <p>Registers an instance of
|
||||
* {@link org.springframework.jmx.export.annotation.AnnotationMBeanExporter}
|
||||
* within the context.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see org.springframework.jmx.export.annotation.AnnotationMBeanExporter
|
||||
*/
|
||||
class MBeanServerBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
private static final String MBEAN_SERVER_BEAN_NAME = "mbeanServer";
|
||||
|
||||
private static final String AGENT_ID_ATTRIBUTE = "agent-id";
|
||||
|
||||
|
||||
private static final boolean weblogicPresent = ClassUtils.isPresent(
|
||||
"weblogic.management.Helper", MBeanServerBeanDefinitionParser.class.getClassLoader());
|
||||
|
||||
private static final boolean webspherePresent = ClassUtils.isPresent(
|
||||
"com.ibm.websphere.management.AdminServiceFactory", MBeanServerBeanDefinitionParser.class.getClassLoader());
|
||||
|
||||
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
|
||||
String id = element.getAttribute(ID_ATTRIBUTE);
|
||||
return (StringUtils.hasText(id) ? id : MBEAN_SERVER_BEAN_NAME);
|
||||
}
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
String agentId = element.getAttribute(AGENT_ID_ATTRIBUTE);
|
||||
if (StringUtils.hasText(agentId)) {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(MBeanServerFactoryBean.class);
|
||||
bd.getPropertyValues().addPropertyValue("agentId", agentId);
|
||||
return bd;
|
||||
}
|
||||
AbstractBeanDefinition specialServer = findServerForSpecialEnvironment();
|
||||
if (specialServer != null) {
|
||||
return specialServer;
|
||||
}
|
||||
RootBeanDefinition bd = new RootBeanDefinition(MBeanServerFactoryBean.class);
|
||||
bd.getPropertyValues().addPropertyValue("locateExistingServerIfPossible", Boolean.TRUE);
|
||||
|
||||
// Mark as infrastructure bean and attach source location.
|
||||
bd.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
bd.setSource(parserContext.extractSource(element));
|
||||
return bd;
|
||||
}
|
||||
|
||||
static AbstractBeanDefinition findServerForSpecialEnvironment() {
|
||||
if (weblogicPresent) {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(JndiObjectFactoryBean.class);
|
||||
bd.getPropertyValues().addPropertyValue("jndiName", "java:comp/env/jmx/runtime");
|
||||
return bd;
|
||||
}
|
||||
else if (webspherePresent) {
|
||||
return new RootBeanDefinition(WebSphereMBeanServerFactoryBean.class);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.springframework.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.PropertyOverrideConfigurer;
|
||||
|
||||
/**
|
||||
* Parser for the <context:property-override/> element.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
*/
|
||||
class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return PropertyOverrideConfigurer.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.springframework.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
|
||||
/**
|
||||
* Parser for the <context:property-placeholder/> element.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return PropertyPlaceholderConfigurer.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.springframework.context.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} responsible for parsing the
|
||||
* <code><context:spring-configured/></code> tag.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
class SpringConfiguredBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* The bean name of the internally managed bean configurer aspect.
|
||||
*/
|
||||
public static final String BEAN_CONFIGURER_ASPECT_BEAN_NAME =
|
||||
"org.springframework.context.config.internalBeanConfigurerAspect";
|
||||
|
||||
static final String BEAN_CONFIGURER_ASPECT_CLASS_NAME =
|
||||
"org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect";
|
||||
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(BEAN_CONFIGURER_ASPECT_BEAN_NAME)) {
|
||||
RootBeanDefinition def = new RootBeanDefinition();
|
||||
def.setBeanClassName(BEAN_CONFIGURER_ASPECT_CLASS_NAME);
|
||||
def.setFactoryMethodName("aspectOf");
|
||||
|
||||
// Mark as infrastructure bean and attach source location.
|
||||
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
def.setSource(parserContext.extractSource(element));
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(def, BEAN_CONFIGURER_ASPECT_BEAN_NAME));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Support package for advanced application context configuration,
|
||||
with XML schema being the primary configuration format.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,423 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/context" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
targetNamespace="http://www.springframework.org/schema/context" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Defines the configuration elements for the Spring Framework's application
|
||||
context support. Effects the activation of various configuration styles
|
||||
for the containing Spring ApplicationContext.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:element name="property-placeholder">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Activates replacement of ${...} placeholders, resolved against the specified properties file or Properties object
|
||||
(if any). Falls back to resolving placeholders against JVM system properties.
|
||||
Alternatively, define a parameterized PropertyPlaceholderConfigurer bean in the context.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="location" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The location of the properties file to resolve placeholders against, as a Spring
|
||||
resource location: a URL, a "classpath:" pseudo URL, or a relative file path.
|
||||
Multiple locations may be specified, separated by commas. If neither location nor properties-ref is
|
||||
specified, placeholders will be resolved against system properties.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="properties-ref" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:java.util.Properties"><![CDATA[
|
||||
The bean name of a Java Properties object that will be used for property substitution.
|
||||
If neither location nor properties-ref is specified, placeholders will be resolved against system properties.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="property-override">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Activates pushing of override values into bean properties, based on configuration
|
||||
lines of the following format: beanName.property=value
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="org.springframework.beans.factory.config.PropertyOverrideConfigurer"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="location" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The location of the properties file to read property overrides from, as a Spring
|
||||
resource location: a URL, a "classpath:" pseudo URL, or a relative file path.
|
||||
Multiple locations may be specified, separated by commas.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="properties-ref" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:java.util.Properties"><![CDATA[
|
||||
The bean name of a Java Properties object that will be used for property overrides.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="annotation-config">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Activates various annotations to be detected in bean classes: Spring's @Required and
|
||||
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
|
||||
JAX-WS's @WebServiceRef (if available), EJB3's @EJB (if available), and JPA's
|
||||
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
|
||||
choose to activate the individual BeanPostProcessors for those annotations.
|
||||
|
||||
Note: This tag does not activate processing of Spring's @Transactional or EJB3's
|
||||
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
|
||||
tag for that purpose.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="component-scan">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Scans the classpath for annotated components that will be auto-registered as
|
||||
Spring beans. By default, the Spring-provided @Component, @Repository,
|
||||
@Service, and @Controller stereotypes will be detected.
|
||||
|
||||
Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
|
||||
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
|
||||
annotations in the component classes, which is usually desired for autodetected components
|
||||
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
|
||||
this default behavior, for example in order to use custom BeanPostProcessor definitions
|
||||
for handling those annotations.
|
||||
|
||||
Note: You may use placeholders in package paths, but only resolved against system
|
||||
properties (analogous to resource paths). A component scan results in new bean definition
|
||||
being registered; Spring's PropertyPlaceholderConfigurer will apply to those bean
|
||||
definitions just like to regular bean definitions, but it won't apply to the component
|
||||
scan settings themselves.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="include-filter" type="filterType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Controls which eligible types to include for component scanning.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="exclude-filter" type="filterType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Controls which eligible types to exclude for component scanning.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="base-package" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The comma-separated list of packages to scan for annotated components.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="resource-pattern" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Controls the class files eligible for component detection. Defaults to "**/*.class", the recommended value.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="use-default-filters" type="xsd:boolean" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether automatic detection of classes annotated with @Component, @Repository, @Service, or @Controller
|
||||
should be enabled. Default is "true".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="annotation-config" type="xsd:boolean" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether the implicit AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor should
|
||||
be enabled. Default is "true".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="name-generator" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The fully-qualified classname of the BeanNameGenerator to be used for naming detected components.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:expected-type type="java.lang.Class"/>
|
||||
<tool:assignable-to type="org.springframework.beans.factory.support.BeanNameGenerator"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="scope-resolver" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The fully-qualified class name of the ScopeMetadataResolver to be used for resolving the scope of detected components.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:expected-type type="java.lang.Class"/>
|
||||
<tool:assignable-to type="org.springframework.context.annotation.ScopeMetadataResolver"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="scoped-proxy">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether proxies should be generated for detected components, which may be necessary when using certain
|
||||
non-singleton scopes in a proxy-style fashion. Default is to generate no such proxies.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="no"/>
|
||||
<xsd:enumeration value="interfaces"/>
|
||||
<xsd:enumeration value="targetClass"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="load-time-weaver">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Activates a Spring LoadTimeWeaver for this application context, available as
|
||||
a bean with the name "loadTimeWeaver". Any bean that implements the
|
||||
LoadTimeWeaverAware interface will then receive the LoadTimeWeaver reference
|
||||
automatically; for example, Spring's JPA bootstrap support.
|
||||
|
||||
The default weaver is determined automatically. As of Spring 2.5: detecting
|
||||
Sun's GlassFish, Oracle's OC4J, Spring's VM agent and any ClassLoader
|
||||
supported by Spring's ReflectiveLoadTimeWeaver (for example, the
|
||||
TomcatInstrumentableClassLoader).
|
||||
|
||||
The activation of AspectJ load-time weaving is specified via a simple flag
|
||||
(the 'aspectj-weaving' attribute), with the AspectJ class transformer
|
||||
registered through Spring's LoadTimeWeaver. AspectJ weaving will be activated
|
||||
by default if a "META-INF/aop.xml" resource is present in the classpath.
|
||||
|
||||
This also activates the current application context for applying dependency
|
||||
injection to non-managed classes that are instantiated outside of the Spring
|
||||
bean factory (typically classes annotated with the @Configurable annotation).
|
||||
This will only happen if the AnnotationBeanConfigurerAspect is on the classpath
|
||||
(i.e. spring-aspects.jar), effectively activating "spring-configured" by default.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="org.springframework.instrument.classloading.LoadTimeWeaver"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="weaver-class" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The fully-qualified classname of the LoadTimeWeaver that is to be activated.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:expected-type type="java.lang.Class"/>
|
||||
<tool:assignable-to type="org.springframework.instrument.classloading.LoadTimeWeaver"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="aspectj-weaving" default="autodetect">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="on">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Switches Spring-based AspectJ load-time weaving on.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="off">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Switches Spring-based AspectJ load-time weaving off.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="autodetect">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Switches AspectJ load-time weaving on if a "META-INF/aop.xml" resource
|
||||
is present in the classpath. If there is no such resource, then AspectJ
|
||||
load-time weaving will be switched off.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="spring-configured">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect">
|
||||
<![CDATA[
|
||||
Signals the current application context to apply dependency injection
|
||||
to non-managed classes that are instantiated outside of the Spring bean
|
||||
factory (typically classes annotated with the @Configurable annotation).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="mbean-export">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.jmx.export.annotation.AnnotationMBeanExporter"><![CDATA[
|
||||
Activates default exporting of MBeans by detecting standard MBeans in the Spring
|
||||
context as well as @ManagedResource annotations on Spring-defined beans.
|
||||
|
||||
The resulting MBeanExporter bean is defined under the name "mbeanExporter".
|
||||
Alternatively, consider defining a custom AnnotationMBeanExporter bean explicitly.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="org.springframework.jmx.export.annotation.MBeanExporter"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="default-domain" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default domain to use when generating JMX ObjectNames.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="server" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The bean name of the MBeanServer to which MBeans should be exported.
|
||||
Default is to use the platform's default MBeanServer (autodetecting
|
||||
WebLogic 9+, WebSphere 5.1+ and the JDK 1.5+ platform MBeanServer).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="registration">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The registration behavior, indicating how to deal with existing MBeans
|
||||
of the same name: fail with an exception, ignore and keep the existing
|
||||
MBean, or replace the existing one with the new MBean.
|
||||
|
||||
Default is to fail with an exception.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:NMTOKEN">
|
||||
<xsd:enumeration value="failOnExisting"/>
|
||||
<xsd:enumeration value="ignoreExisting"/>
|
||||
<xsd:enumeration value="replaceExisting"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="mbean-server">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.jmx.support.MBeanServerFactoryBean"><![CDATA[
|
||||
Exposes a default MBeanServer for the current platform.
|
||||
Autodetects WebLogic 9+, WebSphere 5.1+ and the JDK 1.5+ platform MBeanServer.
|
||||
|
||||
The default bean name for the exposed MBeanServer is "mbeanServer".
|
||||
This may be customized through specifying the "id" attribute.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="javax.management.MBeanServer"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:attribute name="agent-id" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The agent id of the target MBeanServer, if any.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="filterType">
|
||||
<xsd:attribute name="type" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Controls the type of filtering to apply to the expression.
|
||||
|
||||
"annotation" indicates an annotation to be present at the type level in target components;
|
||||
"assignable" indicates a class (or interface) that the target components are assignable to (extend/implement);
|
||||
"aspectj" indicates an AspectJ type expression to be matched by the target components;
|
||||
"regex" indicates a regex expression to be matched by the target components' class names;
|
||||
"custom" indicates a custom implementation of the org.springframework.core.type.TypeFilter interface.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="annotation"/>
|
||||
<xsd:enumeration value="assignable"/>
|
||||
<xsd:enumeration value="aspectj"/>
|
||||
<xsd:enumeration value="regex"/>
|
||||
<xsd:enumeration value="custom"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expression" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates the filter expression, the type of which is indicated by "type".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the {@link ApplicationEventMulticaster} interface,
|
||||
* providing the basic listener registration facility.
|
||||
*
|
||||
* <p>Doesn't permit multiple instances of the same listener by default,
|
||||
* as it keeps listeners in a linked Set. The collection class used to hold
|
||||
* ApplicationListener objects can be overridden through the "collectionClass"
|
||||
* bean property.
|
||||
*
|
||||
* <p>Implementing ApplicationEventMulticaster's actual {@link #multicastEvent} method
|
||||
* is left to subclasses. {@link SimpleApplicationEventMulticaster} simply multicasts
|
||||
* all events to all registered listeners, invoking them in the calling thread.
|
||||
* Alternative implementations could be more sophisticated in those respects.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.3
|
||||
* @see #setCollectionClass
|
||||
* @see #getApplicationListeners()
|
||||
* @see SimpleApplicationEventMulticaster
|
||||
*/
|
||||
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster {
|
||||
|
||||
/** Collection of ApplicationListeners */
|
||||
private Collection applicationListeners = new LinkedHashSet();
|
||||
|
||||
|
||||
/**
|
||||
* Set whether this multicaster should expect concurrent updates at runtime
|
||||
* (i.e. after context startup finished). In case of concurrent updates,
|
||||
* a copy-on-write strategy is applied, keeping iteration (for multicasting)
|
||||
* without synchronization while still making listener updates thread-safe.
|
||||
*/
|
||||
public void setConcurrentUpdates(boolean concurrent) {
|
||||
Collection newColl = (concurrent ? CollectionFactory.createCopyOnWriteSet() : new LinkedHashSet());
|
||||
// Add all previously registered listeners (usually none).
|
||||
newColl.addAll(this.applicationListeners);
|
||||
this.applicationListeners = newColl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the collection class to use. Can be populated with a fully
|
||||
* qualified class name when defined in a Spring application context.
|
||||
* <p>Default is a linked HashSet, keeping the registration order.
|
||||
* Note that a Set class specified will not permit multiple instances
|
||||
* of the same listener, while a List class will allow for registering
|
||||
* the same listener multiple times.
|
||||
*/
|
||||
public void setCollectionClass(Class collectionClass) {
|
||||
if (collectionClass == null) {
|
||||
throw new IllegalArgumentException("'collectionClass' must not be null");
|
||||
}
|
||||
if (!Collection.class.isAssignableFrom(collectionClass)) {
|
||||
throw new IllegalArgumentException("'collectionClass' must implement [java.util.Collection]");
|
||||
}
|
||||
// Create desired collection instance.
|
||||
Collection newColl = (Collection) BeanUtils.instantiateClass(collectionClass);
|
||||
// Add all previously registered listeners (usually none).
|
||||
newColl.addAll(this.applicationListeners);
|
||||
this.applicationListeners = newColl;
|
||||
}
|
||||
|
||||
|
||||
public void addApplicationListener(ApplicationListener listener) {
|
||||
this.applicationListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeApplicationListener(ApplicationListener listener) {
|
||||
this.applicationListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void removeAllListeners() {
|
||||
this.applicationListeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current Collection of ApplicationListeners.
|
||||
* <p>Note that this is the raw Collection of ApplicationListeners,
|
||||
* potentially modified when new listeners get registered or
|
||||
* existing ones get removed. This Collection is not a snapshot copy.
|
||||
* @return a Collection of ApplicationListeners
|
||||
* @see org.springframework.context.ApplicationListener
|
||||
*/
|
||||
protected Collection getApplicationListeners() {
|
||||
return this.applicationListeners;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Base class for events raised for an <code>ApplicationContext</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public abstract class ApplicationContextEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* Create a new ContextStartedEvent.
|
||||
* @param source the <code>ApplicationContext</code> that the event is raised for
|
||||
* (must not be <code>null</code>)
|
||||
*/
|
||||
public ApplicationContextEvent(ApplicationContext source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <code>ApplicationContext</code> that the event was raised for.
|
||||
*/
|
||||
public final ApplicationContext getApplicationContext() {
|
||||
return (ApplicationContext) getSource();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by objects that can manage a number
|
||||
* of ApplicationListeners, and publish events to them. An example
|
||||
* of such an object is an ApplicationEventPublisher, typically
|
||||
* the ApplicationContext, which can use an ApplicationEventMulticaster
|
||||
* as a helper to publish events to listeners.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public interface ApplicationEventMulticaster {
|
||||
|
||||
/**
|
||||
* Add a listener to be notified of all events.
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
void addApplicationListener(ApplicationListener listener);
|
||||
|
||||
/**
|
||||
* Remove a listener from the notification list.
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
void removeApplicationListener(ApplicationListener listener);
|
||||
|
||||
/**
|
||||
* Remove all listeners registered with this multicaster.
|
||||
* It will perform no action on event notification until more
|
||||
* listeners are registered.
|
||||
*/
|
||||
void removeAllListeners();
|
||||
|
||||
/**
|
||||
* Multicast the given application event to appropriate listeners.
|
||||
* @param event the event to multicast
|
||||
*/
|
||||
void multicastEvent(ApplicationEvent event);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Event raised when an <code>ApplicationContext</code> gets closed.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 12.08.2003
|
||||
* @see ContextRefreshedEvent
|
||||
*/
|
||||
public class ContextClosedEvent extends ApplicationContextEvent {
|
||||
|
||||
/**
|
||||
* Creates a new ContextClosedEvent.
|
||||
* @param source the <code>ApplicationContext</code> that has been closed
|
||||
* (must not be <code>null</code>)
|
||||
*/
|
||||
public ContextClosedEvent(ApplicationContext source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Event raised when an <code>ApplicationContext</code> gets initialized or refreshed.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 04.03.2003
|
||||
* @see ContextClosedEvent
|
||||
*/
|
||||
public class ContextRefreshedEvent extends ApplicationContextEvent {
|
||||
|
||||
/**
|
||||
* Create a new ContextRefreshedEvent.
|
||||
* @param source the <code>ApplicationContext</code> that has been initialized
|
||||
* or refreshed (must not be <code>null</code>)
|
||||
*/
|
||||
public ContextRefreshedEvent(ApplicationContext source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Event raised when an <code>ApplicationContext</code> gets started.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see ContextStoppedEvent
|
||||
*/
|
||||
public class ContextStartedEvent extends ApplicationContextEvent {
|
||||
|
||||
/**
|
||||
* Create a new ContextStartedEvent.
|
||||
* @param source the <code>ApplicationContext</code> that has been started
|
||||
* (must not be <code>null</code>)
|
||||
*/
|
||||
public ContextStartedEvent(ApplicationContext source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Event raised when an <code>ApplicationContext</code> gets stopped.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see ContextStartedEvent
|
||||
*/
|
||||
public class ContextStoppedEvent extends ApplicationContextEvent {
|
||||
|
||||
/**
|
||||
* Create a new ContextStoppedEvent.
|
||||
* @param source the <code>ApplicationContext</code> that has been stopped
|
||||
* (must not be <code>null</code>)
|
||||
*/
|
||||
public ContextStoppedEvent(ApplicationContext source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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.context.event;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
|
||||
/**
|
||||
* {@link MethodInterceptor Interceptor} that publishes an
|
||||
* <code>ApplicationEvent</code> to all <code>ApplicationListeners</code>
|
||||
* registered with an <code>ApplicationEventPublisher</code> after each
|
||||
* <i>successful</i> method invocation.
|
||||
*
|
||||
* <p>Note that this interceptor is only capable of publishing <i>stateless</i>
|
||||
* events configured via the
|
||||
* {@link #setApplicationEventClass "applicationEventClass"} property.
|
||||
*
|
||||
* @author Dmitriy Kopylenko
|
||||
* @author Juergen Hoeller
|
||||
* @author Rick Evans
|
||||
* @see #setApplicationEventClass
|
||||
* @see org.springframework.context.ApplicationEvent
|
||||
* @see org.springframework.context.ApplicationListener
|
||||
* @see org.springframework.context.ApplicationEventPublisher
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
*/
|
||||
public class EventPublicationInterceptor
|
||||
implements MethodInterceptor, ApplicationEventPublisherAware, InitializingBean {
|
||||
|
||||
private Constructor applicationEventClassConstructor;
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
|
||||
/**
|
||||
* Set the application event class to publish.
|
||||
* <p>The event class <b>must</b> have a constructor with a single
|
||||
* <code>Object</code> argument for the event source. The interceptor
|
||||
* will pass in the invoked object.
|
||||
* @throws IllegalArgumentException if the supplied <code>Class</code> is
|
||||
* <code>null</code> or if it is not an <code>ApplicationEvent</code> subclass or
|
||||
* if it does not expose a constructor that takes a single <code>Object</code> argument
|
||||
*/
|
||||
public void setApplicationEventClass(Class applicationEventClass) {
|
||||
if (ApplicationEvent.class.equals(applicationEventClass) ||
|
||||
!ApplicationEvent.class.isAssignableFrom(applicationEventClass)) {
|
||||
throw new IllegalArgumentException("applicationEventClass needs to extend ApplicationEvent");
|
||||
}
|
||||
try {
|
||||
this.applicationEventClassConstructor =
|
||||
applicationEventClass.getConstructor(new Class[] {Object.class});
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalArgumentException("applicationEventClass [" +
|
||||
applicationEventClass.getName() + "] does not have the required Object constructor: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.applicationEventClassConstructor == null) {
|
||||
throw new IllegalArgumentException("applicationEventClass is required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
Object retVal = invocation.proceed();
|
||||
|
||||
ApplicationEvent event = (ApplicationEvent)
|
||||
this.applicationEventClassConstructor.newInstance(new Object[] {invocation.getThis()});
|
||||
this.applicationEventPublisher.publishEvent(event);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
/**
|
||||
* Simple implementation of the {@link ApplicationEventMulticaster} interface.
|
||||
*
|
||||
* <p>Multicasts all events to all registered listeners, leaving it up to
|
||||
* the listeners to ignore events that they are not interested in.
|
||||
* Listeners will usually perform corresponding <code>instanceof</code>
|
||||
* checks on the passed-in event object.
|
||||
*
|
||||
* <p>By default, all listeners are invoked in the calling thread.
|
||||
* This allows the danger of a rogue listener blocking the entire application,
|
||||
* but adds minimal overhead. Specify an alternative TaskExecutor to have
|
||||
* listeners executed in different threads, for example from a thread pool.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #setTaskExecutor
|
||||
* @see #setConcurrentUpdates
|
||||
*/
|
||||
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
|
||||
|
||||
private TaskExecutor taskExecutor = new SyncTaskExecutor();
|
||||
|
||||
|
||||
/**
|
||||
* Set the TaskExecutor to execute application listeners with.
|
||||
* <p>Default is a SyncTaskExecutor, executing the listeners synchronously
|
||||
* in the calling thread.
|
||||
* <p>Consider specifying an asynchronous TaskExecutor here to not block the
|
||||
* caller until all listeners have been executed. However, note that asynchronous
|
||||
* execution will not participate in the caller's thread context (class loader,
|
||||
* transaction association) unless the TaskExecutor explicitly supports this.
|
||||
* @see org.springframework.core.task.SyncTaskExecutor
|
||||
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
|
||||
* @see org.springframework.scheduling.timer.TimerTaskExecutor
|
||||
*/
|
||||
public void setTaskExecutor(TaskExecutor taskExecutor) {
|
||||
this.taskExecutor = (taskExecutor != null ? taskExecutor : new SyncTaskExecutor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current TaskExecutor for this multicaster.
|
||||
*/
|
||||
protected TaskExecutor getTaskExecutor() {
|
||||
return this.taskExecutor;
|
||||
}
|
||||
|
||||
|
||||
public void multicastEvent(final ApplicationEvent event) {
|
||||
for (Iterator it = getApplicationListeners().iterator(); it.hasNext();) {
|
||||
final ApplicationListener listener = (ApplicationListener) it.next();
|
||||
getTaskExecutor().execute(new Runnable() {
|
||||
public void run() {
|
||||
listener.onApplicationEvent(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.context.ApplicationListener} decorator that filters
|
||||
* events from a specified event source, invoking its delegate listener for
|
||||
* matching {@link org.springframework.context.ApplicationEvent} objects only.
|
||||
*
|
||||
* <p>Can also be used as base class, overriding the {@link #onApplicationEventInternal}
|
||||
* method instead of specifying a delegate listener.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.5
|
||||
*/
|
||||
public class SourceFilteringListener implements ApplicationListener {
|
||||
|
||||
private final Object source;
|
||||
|
||||
private ApplicationListener delegate;
|
||||
|
||||
|
||||
/**
|
||||
* Create a SourceFilteringListener for the given event source.
|
||||
* @param source the event source that this listener filters for,
|
||||
* only processing events from this source
|
||||
* @param delegate the delegate listener to invoke with event
|
||||
* from the specified source
|
||||
*/
|
||||
public SourceFilteringListener(Object source, ApplicationListener delegate) {
|
||||
this.source = source;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SourceFilteringListener for the given event source,
|
||||
* expecting subclasses to override the {@link #onApplicationEventInternal}
|
||||
* method (instead of specifying a delegate listener).
|
||||
* @param source the event source that this listener filters for,
|
||||
* only processing events from this source
|
||||
*/
|
||||
protected SourceFilteringListener(Object source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if (event.getSource() == this.source) {
|
||||
onApplicationEventInternal(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually process the event, after having filtered according to the
|
||||
* desired event source already.
|
||||
* <p>The default implementation invokes the specified delegate, if any.
|
||||
* @param event the event to process (matching the specified source)
|
||||
*/
|
||||
protected void onApplicationEventInternal(ApplicationEvent event) {
|
||||
if (this.delegate == null) {
|
||||
throw new IllegalStateException(
|
||||
"Must specify a delegate object or override the onApplicationEventInternal method");
|
||||
}
|
||||
this.delegate.onApplicationEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Support classes for application events, like standard context events.
|
||||
To be supported by all major application context implementations.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Strategy interface for determining the current Locale.
|
||||
*
|
||||
* <p>A LocaleContext instance can be associated with a thread
|
||||
* via the LocaleContextHolder class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see LocaleContextHolder
|
||||
* @see java.util.Locale
|
||||
*/
|
||||
public interface LocaleContext {
|
||||
|
||||
/**
|
||||
* Return the current Locale, which can be fixed or determined dynamically,
|
||||
* depending on the implementation strategy.
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.springframework.context.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.core.NamedInheritableThreadLocal;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* Simple holder class that associates a LocaleContext instance
|
||||
* with the current thread. The LocaleContext will be inherited
|
||||
* by any child threads spawned by the current thread.
|
||||
*
|
||||
* <p>Used as a central holder for the current Locale in Spring,
|
||||
* wherever necessary: for example, in MessageSourceAccessor.
|
||||
* DispatcherServlet automatically exposes its current Locale here.
|
||||
* Other applications can expose theirs too, to make classes like
|
||||
* MessageSourceAccessor automatically use that Locale.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see LocaleContext
|
||||
* @see org.springframework.context.support.MessageSourceAccessor
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
*/
|
||||
public abstract class LocaleContextHolder {
|
||||
|
||||
private static final ThreadLocal localeContextHolder = new NamedThreadLocal("Locale context");
|
||||
|
||||
private static final ThreadLocal inheritableLocaleContextHolder =
|
||||
new NamedInheritableThreadLocal("Locale context");
|
||||
|
||||
|
||||
/**
|
||||
* Reset the LocaleContext for the current thread.
|
||||
*/
|
||||
public static void resetLocaleContext() {
|
||||
localeContextHolder.set(null);
|
||||
inheritableLocaleContextHolder.set(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given LocaleContext with the current thread,
|
||||
* <i>not</i> exposing it as inheritable for child threads.
|
||||
* @param localeContext the current LocaleContext, or <code>null</code> to reset
|
||||
* the thread-bound context
|
||||
*/
|
||||
public static void setLocaleContext(LocaleContext localeContext) {
|
||||
setLocaleContext(localeContext, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given LocaleContext with the current thread.
|
||||
* @param localeContext the current LocaleContext, or <code>null</code> to reset
|
||||
* the thread-bound context
|
||||
* @param inheritable whether to expose the LocaleContext as inheritable
|
||||
* for child threads (using an {@link java.lang.InheritableThreadLocal})
|
||||
*/
|
||||
public static void setLocaleContext(LocaleContext localeContext, boolean inheritable) {
|
||||
if (inheritable) {
|
||||
inheritableLocaleContextHolder.set(localeContext);
|
||||
localeContextHolder.set(null);
|
||||
}
|
||||
else {
|
||||
localeContextHolder.set(localeContext);
|
||||
inheritableLocaleContextHolder.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the LocaleContext associated with the current thread, if any.
|
||||
* @return the current LocaleContext, or <code>null</code> if none
|
||||
*/
|
||||
public static LocaleContext getLocaleContext() {
|
||||
LocaleContext localeContext = (LocaleContext) localeContextHolder.get();
|
||||
if (localeContext == null) {
|
||||
localeContext = (LocaleContext) inheritableLocaleContextHolder.get();
|
||||
}
|
||||
return localeContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given Locale with the current thread.
|
||||
* <p>Will implicitly create a LocaleContext for the given Locale,
|
||||
* <i>not</i> exposing it as inheritable for child threads.
|
||||
* @param locale the current Locale, or <code>null</code> to reset
|
||||
* the thread-bound context
|
||||
* @see SimpleLocaleContext#SimpleLocaleContext(java.util.Locale)
|
||||
*/
|
||||
public static void setLocale(Locale locale) {
|
||||
setLocale(locale, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given Locale with the current thread.
|
||||
* <p>Will implicitly create a LocaleContext for the given Locale.
|
||||
* @param locale the current Locale, or <code>null</code> to reset
|
||||
* the thread-bound context
|
||||
* @param inheritable whether to expose the LocaleContext as inheritable
|
||||
* for child threads (using an {@link java.lang.InheritableThreadLocal})
|
||||
* @see SimpleLocaleContext#SimpleLocaleContext(java.util.Locale)
|
||||
*/
|
||||
public static void setLocale(Locale locale, boolean inheritable) {
|
||||
LocaleContext localeContext = (locale != null ? new SimpleLocaleContext(locale) : null);
|
||||
setLocaleContext(localeContext, inheritable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Locale associated with the current thread, if any,
|
||||
* or the system default Locale else.
|
||||
* @return the current Locale, or the system default Locale if no
|
||||
* specific Locale has been associated with the current thread
|
||||
* @see LocaleContext#getLocale()
|
||||
* @see java.util.Locale#getDefault()
|
||||
*/
|
||||
public static Locale getLocale() {
|
||||
LocaleContext localeContext = getLocaleContext();
|
||||
return (localeContext != null ? localeContext.getLocale() : Locale.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.springframework.context.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple implementation of the {@link LocaleContext} interface,
|
||||
* always returning a specified <code>Locale</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
*/
|
||||
public class SimpleLocaleContext implements LocaleContext {
|
||||
|
||||
private final Locale locale;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SimpleLocaleContext that exposes the specified Locale.
|
||||
* Every <code>getLocale()</code> will return this Locale.
|
||||
* @param locale the Locale to expose
|
||||
*/
|
||||
public SimpleLocaleContext(Locale locale) {
|
||||
Assert.notNull(locale, "Locale must not be null");
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.locale.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Abstraction for determining the current Locale,
|
||||
plus global holder that exposes a thread-bound Locale.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
This package builds on the beans package to add support for
|
||||
message sources and for the Observer design pattern, and the
|
||||
ability for application objects to obtain resources using a
|
||||
consistent API.
|
||||
|
||||
<p>There is no necessity for Spring applications to depend
|
||||
on ApplicationContext or even BeanFactory functionality
|
||||
explicitly. One of the strengths of the Spring architecture
|
||||
is that application objects can often be configured without
|
||||
any dependency on Spring-specific APIs.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.context.HierarchicalMessageSource;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the {@link HierarchicalMessageSource} interface,
|
||||
* implementing common handling of message variants, making it easy
|
||||
* to implement a specific strategy for a concrete MessageSource.
|
||||
*
|
||||
* <p>Subclasses must implement the abstract {@link #resolveCode}
|
||||
* method. For efficient resolution of messages without arguments, the
|
||||
* {@link #resolveCodeWithoutArguments} method should be overridden
|
||||
* as well, resolving messages without a MessageFormat being involved.
|
||||
*
|
||||
* <p><b>Note:</b> By default, message texts are only parsed through
|
||||
* MessageFormat if arguments have been passed in for the message. In case
|
||||
* of no arguments, message texts will be returned as-is. As a consequence,
|
||||
* you should only use MessageFormat escaping for messages with actual
|
||||
* arguments, and keep all other messages unescaped. If you prefer to
|
||||
* escape all messages, set the "alwaysUseMessageFormat" flag to "true".
|
||||
*
|
||||
* <p>Supports not only MessageSourceResolvables as primary messages
|
||||
* but also resolution of message arguments that are in turn
|
||||
* MessageSourceResolvables themselves.
|
||||
*
|
||||
* <p>This class does not implement caching of messages per code, thus
|
||||
* subclasses can dynamically change messages over time. Subclasses are
|
||||
* encouraged to cache their messages in a modification-aware fashion,
|
||||
* allowing for hot deployment of updated messages.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
* @see #resolveCode(String, java.util.Locale)
|
||||
* @see #resolveCodeWithoutArguments(String, java.util.Locale)
|
||||
* @see #setAlwaysUseMessageFormat
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
public abstract class AbstractMessageSource extends MessageSourceSupport implements HierarchicalMessageSource {
|
||||
|
||||
private MessageSource parentMessageSource;
|
||||
|
||||
private boolean useCodeAsDefaultMessage = false;
|
||||
|
||||
|
||||
public void setParentMessageSource(MessageSource parent) {
|
||||
this.parentMessageSource = parent;
|
||||
}
|
||||
|
||||
public MessageSource getParentMessageSource() {
|
||||
return this.parentMessageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use the message code as default message instead of
|
||||
* throwing a NoSuchMessageException. Useful for development and debugging.
|
||||
* Default is "false".
|
||||
* <p>Note: In case of a MessageSourceResolvable with multiple codes
|
||||
* (like a FieldError) and a MessageSource that has a parent MessageSource,
|
||||
* do <i>not</i> activate "useCodeAsDefaultMessage" in the <i>parent</i>:
|
||||
* Else, you'll get the first code returned as message by the parent,
|
||||
* without attempts to check further codes.
|
||||
* <p>To be able to work with "useCodeAsDefaultMessage" turned on in the parent,
|
||||
* AbstractMessageSource and AbstractApplicationContext contain special checks
|
||||
* to delegate to the internal <code>getMessageInternal</code> method if available.
|
||||
* In general, it is recommended to just use "useCodeAsDefaultMessage" during
|
||||
* development and not rely on it in production in the first place, though.
|
||||
* @see #getMessage(String, Object[], Locale)
|
||||
* @see #getMessageInternal
|
||||
* @see org.springframework.validation.FieldError
|
||||
*/
|
||||
public void setUseCodeAsDefaultMessage(boolean useCodeAsDefaultMessage) {
|
||||
this.useCodeAsDefaultMessage = useCodeAsDefaultMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to use the message code as default message instead of
|
||||
* throwing a NoSuchMessageException. Useful for development and debugging.
|
||||
* Default is "false".
|
||||
* <p>Alternatively, consider overriding the <code>getDefaultMessage</code>
|
||||
* method to return a custom fallback message for an unresolvable code.
|
||||
* @see #getDefaultMessage(String)
|
||||
*/
|
||||
protected boolean isUseCodeAsDefaultMessage() {
|
||||
return this.useCodeAsDefaultMessage;
|
||||
}
|
||||
|
||||
|
||||
public final String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
|
||||
String msg = getMessageInternal(code, args, locale);
|
||||
if (msg != null) {
|
||||
return msg;
|
||||
}
|
||||
if (defaultMessage == null) {
|
||||
String fallback = getDefaultMessage(code);
|
||||
if (fallback != null) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
return renderDefaultMessage(defaultMessage, args, locale);
|
||||
}
|
||||
|
||||
public final String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
|
||||
String msg = getMessageInternal(code, args, locale);
|
||||
if (msg != null) {
|
||||
return msg;
|
||||
}
|
||||
String fallback = getDefaultMessage(code);
|
||||
if (fallback != null) {
|
||||
return fallback;
|
||||
}
|
||||
throw new NoSuchMessageException(code, locale);
|
||||
}
|
||||
|
||||
public final String getMessage(MessageSourceResolvable resolvable, Locale locale)
|
||||
throws NoSuchMessageException {
|
||||
|
||||
String[] codes = resolvable.getCodes();
|
||||
if (codes == null) {
|
||||
codes = new String[0];
|
||||
}
|
||||
for (int i = 0; i < codes.length; i++) {
|
||||
String msg = getMessageInternal(codes[i], resolvable.getArguments(), locale);
|
||||
if (msg != null) {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
if (resolvable.getDefaultMessage() != null) {
|
||||
return renderDefaultMessage(resolvable.getDefaultMessage(), resolvable.getArguments(), locale);
|
||||
}
|
||||
if (codes.length > 0) {
|
||||
String fallback = getDefaultMessage(codes[0]);
|
||||
if (fallback != null) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
throw new NoSuchMessageException(codes.length > 0 ? codes[codes.length - 1] : null, locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve the given code and arguments as message in the given Locale,
|
||||
* returning <code>null</code> if not found. Does <i>not</i> fall back to
|
||||
* the code as default message. Invoked by <code>getMessage</code> methods.
|
||||
* @param code the code to lookup up, such as 'calculator.noRateSet'
|
||||
* @param args array of arguments that will be filled in for params
|
||||
* within the message
|
||||
* @param locale the Locale in which to do the lookup
|
||||
* @return the resolved message, or <code>null</code> if not found
|
||||
* @see #getMessage(String, Object[], String, Locale)
|
||||
* @see #getMessage(String, Object[], Locale)
|
||||
* @see #getMessage(MessageSourceResolvable, Locale)
|
||||
* @see #setUseCodeAsDefaultMessage
|
||||
*/
|
||||
protected String getMessageInternal(String code, Object[] args, Locale locale) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
Object[] argsToUse = args;
|
||||
|
||||
if (!isAlwaysUseMessageFormat() && ObjectUtils.isEmpty(args)) {
|
||||
// Optimized resolution: no arguments to apply,
|
||||
// therefore no MessageFormat needs to be involved.
|
||||
// Note that the default implementation still uses MessageFormat;
|
||||
// this can be overridden in specific subclasses.
|
||||
String message = resolveCodeWithoutArguments(code, locale);
|
||||
if (message != null) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// Resolve arguments eagerly, for the case where the message
|
||||
// is defined in a parent MessageSource but resolvable arguments
|
||||
// are defined in the child MessageSource.
|
||||
argsToUse = resolveArguments(args, locale);
|
||||
|
||||
MessageFormat messageFormat = resolveCode(code, locale);
|
||||
if (messageFormat != null) {
|
||||
synchronized (messageFormat) {
|
||||
return messageFormat.format(argsToUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not found -> check parent, if any.
|
||||
return getMessageFromParent(code, argsToUse, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to retrieve the given message from the parent MessageSource, if any.
|
||||
* @param code the code to lookup up, such as 'calculator.noRateSet'
|
||||
* @param args array of arguments that will be filled in for params
|
||||
* within the message
|
||||
* @param locale the Locale in which to do the lookup
|
||||
* @return the resolved message, or <code>null</code> if not found
|
||||
* @see #getParentMessageSource()
|
||||
*/
|
||||
protected String getMessageFromParent(String code, Object[] args, Locale locale) {
|
||||
MessageSource parent = getParentMessageSource();
|
||||
if (parent != null) {
|
||||
if (parent instanceof AbstractMessageSource) {
|
||||
// Call internal method to avoid getting the default code back
|
||||
// in case of "useCodeAsDefaultMessage" being activated.
|
||||
return ((AbstractMessageSource) parent).getMessageInternal(code, args, locale);
|
||||
}
|
||||
else {
|
||||
// Check parent MessageSource, returning null if not found there.
|
||||
return parent.getMessage(code, args, null, locale);
|
||||
}
|
||||
}
|
||||
// Not found in parent either.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fallback default message for the given code, if any.
|
||||
* <p>Default is to return the code itself if "useCodeAsDefaultMessage"
|
||||
* is activated, or return no fallback else. In case of no fallback,
|
||||
* the caller will usually receive a NoSuchMessageException from
|
||||
* <code>getMessage</code>.
|
||||
* @param code the message code that we couldn't resolve
|
||||
* and that we didn't receive an explicit default message for
|
||||
* @return the default message to use, or <code>null</code> if none
|
||||
* @see #setUseCodeAsDefaultMessage
|
||||
*/
|
||||
protected String getDefaultMessage(String code) {
|
||||
if (isUseCodeAsDefaultMessage()) {
|
||||
return code;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the given default message String. The default message is
|
||||
* passed in as specified by the caller and can be rendered into
|
||||
* a fully formatted default message shown to the user.
|
||||
* <p>The default implementation passes the String to <code>formatMessage</code>,
|
||||
* resolving any argument placeholders found in them. Subclasses may override
|
||||
* this method to plug in custom processing of default messages.
|
||||
* @param defaultMessage the passed-in default message String
|
||||
* @param args array of arguments that will be filled in for params within
|
||||
* the message, or <code>null</code> if none.
|
||||
* @param locale the Locale used for formatting
|
||||
* @return the rendered default message (with resolved arguments)
|
||||
* @see #formatMessage(String, Object[], java.util.Locale)
|
||||
*/
|
||||
protected String renderDefaultMessage(String defaultMessage, Object[] args, Locale locale) {
|
||||
return formatMessage(defaultMessage, args, locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Searches through the given array of objects, find any
|
||||
* MessageSourceResolvable objects and resolve them.
|
||||
* <p>Allows for messages to have MessageSourceResolvables as arguments.
|
||||
* @param args array of arguments for a message
|
||||
* @param locale the locale to resolve through
|
||||
* @return an array of arguments with any MessageSourceResolvables resolved
|
||||
*/
|
||||
protected Object[] resolveArguments(Object[] args, Locale locale) {
|
||||
if (args == null) {
|
||||
return new Object[0];
|
||||
}
|
||||
List resolvedArgs = new ArrayList(args.length);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] instanceof MessageSourceResolvable) {
|
||||
resolvedArgs.add(getMessage((MessageSourceResolvable) args[i], locale));
|
||||
}
|
||||
else {
|
||||
resolvedArgs.add(args[i]);
|
||||
}
|
||||
}
|
||||
return resolvedArgs.toArray(new Object[resolvedArgs.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this method to resolve a message without
|
||||
* arguments in an optimized fashion, that is, to resolve a message
|
||||
* without involving a MessageFormat.
|
||||
* <p>The default implementation <i>does</i> use MessageFormat,
|
||||
* through delegating to the <code>resolveCode</code> method.
|
||||
* Subclasses are encouraged to replace this with optimized resolution.
|
||||
* <p>Unfortunately, <code>java.text.MessageFormat</code> is not
|
||||
* implemented in an efficient fashion. In particular, it does not
|
||||
* detect that a message pattern doesn't contain argument placeholders
|
||||
* in the first place. Therefore, it's advisable to circumvent
|
||||
* MessageFormat completely for messages without arguments.
|
||||
* @param code the code of the message to resolve
|
||||
* @param locale the Locale to resolve the code for
|
||||
* (subclasses are encouraged to support internationalization)
|
||||
* @return the message String, or <code>null</code> if not found
|
||||
* @see #resolveCode
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
protected String resolveCodeWithoutArguments(String code, Locale locale) {
|
||||
MessageFormat messageFormat = resolveCode(code, locale);
|
||||
if (messageFormat != null) {
|
||||
synchronized (messageFormat) {
|
||||
return messageFormat.format(new Object[0]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method to resolve a message.
|
||||
* <p>Returns a MessageFormat instance rather than a message String,
|
||||
* to allow for appropriate caching of MessageFormats in subclasses.
|
||||
* <p><b>Subclasses are encouraged to provide optimized resolution
|
||||
* for messages without arguments, not involving MessageFormat.</b>
|
||||
* See <code>resolveCodeWithoutArguments</code> javadoc for details.
|
||||
* @param code the code of the message to resolve
|
||||
* @param locale the Locale to resolve the code for
|
||||
* (subclasses are encouraged to support internationalization)
|
||||
* @return the MessageFormat for the message, or <code>null</code> if not found
|
||||
* @see #resolveCodeWithoutArguments(String, java.util.Locale)
|
||||
*/
|
||||
protected abstract MessageFormat resolveCode(String code, Locale locale);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
|
||||
/**
|
||||
* Base class for {@link org.springframework.context.ApplicationContext}
|
||||
* implementations which are supposed to support multiple refreshs,
|
||||
* creating a new internal bean factory instance every time.
|
||||
* Typically (but not necessarily), such a context will be driven by
|
||||
* a set of config locations to load bean definitions from.
|
||||
*
|
||||
* <p>The only method to be implemented by subclasses is {@link #loadBeanDefinitions},
|
||||
* which gets invoked on each refresh. A concrete implementation is supposed to load
|
||||
* bean definitions into the given
|
||||
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory},
|
||||
* typically delegating to one or more specific bean definition readers.
|
||||
*
|
||||
* <p><b>Note that there is a similar base class for WebApplicationContexts.</b>
|
||||
* {@link org.springframework.web.context.support.AbstractRefreshableWebApplicationContext}
|
||||
* provides the same subclassing strategy, but additionally pre-implements
|
||||
* all context functionality for web environments. There is also a
|
||||
* pre-defined way to receive config locations for a web context.
|
||||
*
|
||||
* <p>Concrete standalone subclasses of this base class, reading in a
|
||||
* specific bean definition format, are {@link ClassPathXmlApplicationContext}
|
||||
* and {@link FileSystemXmlApplicationContext}, which both derive from the
|
||||
* common {@link AbstractXmlApplicationContext} base class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.3
|
||||
* @see #loadBeanDefinitions
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory
|
||||
* @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext
|
||||
* @see AbstractXmlApplicationContext
|
||||
* @see ClassPathXmlApplicationContext
|
||||
* @see FileSystemXmlApplicationContext
|
||||
*/
|
||||
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
|
||||
|
||||
private Boolean allowBeanDefinitionOverriding;
|
||||
|
||||
private Boolean allowCircularReferences;
|
||||
|
||||
/** Bean factory for this context */
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
/** Synchronization monitor for the internal BeanFactory */
|
||||
private final Object beanFactoryMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AbstractRefreshableApplicationContext with no parent.
|
||||
*/
|
||||
public AbstractRefreshableApplicationContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AbstractRefreshableApplicationContext with the given parent context.
|
||||
* @param parent the parent context
|
||||
*/
|
||||
public AbstractRefreshableApplicationContext(ApplicationContext parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether it should be allowed to override bean definitions by registering
|
||||
* a different definition with the same name, automatically replacing the former.
|
||||
* If not, an exception will be thrown. Default is "true".
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
|
||||
*/
|
||||
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
|
||||
this.allowBeanDefinitionOverriding = Boolean.valueOf(allowBeanDefinitionOverriding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to allow circular references between beans - and automatically
|
||||
* try to resolve them.
|
||||
* <p>Default is "true". Turn this off to throw an exception when encountering
|
||||
* a circular reference, disallowing them completely.
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
|
||||
*/
|
||||
public void setAllowCircularReferences(boolean allowCircularReferences) {
|
||||
this.allowCircularReferences = Boolean.valueOf(allowCircularReferences);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation performs an actual refresh of this context's underlying
|
||||
* bean factory, shutting down the previous bean factory (if any) and
|
||||
* initializing a fresh bean factory for the next phase of the context's lifecycle.
|
||||
*/
|
||||
protected final void refreshBeanFactory() throws BeansException {
|
||||
if (hasBeanFactory()) {
|
||||
destroyBeans();
|
||||
closeBeanFactory();
|
||||
}
|
||||
try {
|
||||
DefaultListableBeanFactory beanFactory = createBeanFactory();
|
||||
customizeBeanFactory(beanFactory);
|
||||
loadBeanDefinitions(beanFactory);
|
||||
synchronized (this.beanFactoryMonitor) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new ApplicationContextException(
|
||||
"I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void closeBeanFactory() {
|
||||
synchronized (this.beanFactoryMonitor) {
|
||||
this.beanFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this context currently holds a bean factory,
|
||||
* i.e. has been refreshed at least once and not been closed yet.
|
||||
*/
|
||||
protected final boolean hasBeanFactory() {
|
||||
synchronized (this.beanFactoryMonitor) {
|
||||
return (this.beanFactory != null);
|
||||
}
|
||||
}
|
||||
|
||||
public final ConfigurableListableBeanFactory getBeanFactory() {
|
||||
synchronized (this.beanFactoryMonitor) {
|
||||
if (this.beanFactory == null) {
|
||||
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
|
||||
"call 'refresh' before accessing beans via the ApplicationContext");
|
||||
}
|
||||
return this.beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an internal bean factory for this context.
|
||||
* Called for each {@link #refresh()} attempt.
|
||||
* <p>The default implementation creates a
|
||||
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
|
||||
* with the {@link #getInternalParentBeanFactory() internal bean factory} of this
|
||||
* context's parent as parent bean factory. Can be overridden in subclasses,
|
||||
* for example to customize DefaultListableBeanFactory's settings.
|
||||
* @return the bean factory for this context
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
|
||||
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
|
||||
*/
|
||||
protected DefaultListableBeanFactory createBeanFactory() {
|
||||
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the internal bean factory used by this context.
|
||||
* Called for each {@link #refresh()} attempt.
|
||||
* <p>The default implementation applies this context's
|
||||
* {@link #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
|
||||
* and {@link #setAllowCircularReferences "allowCircularReferences"} settings,
|
||||
* if specified. Can be overridden in subclasses to customize any of
|
||||
* {@link DefaultListableBeanFactory}'s settings.
|
||||
* @param beanFactory the newly created bean factory for this context
|
||||
* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
|
||||
* @see DefaultListableBeanFactory#setAllowCircularReferences
|
||||
* @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
|
||||
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
|
||||
*/
|
||||
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
|
||||
if (this.allowBeanDefinitionOverriding != null) {
|
||||
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding.booleanValue());
|
||||
}
|
||||
if (this.allowCircularReferences != null) {
|
||||
beanFactory.setAllowCircularReferences(this.allowCircularReferences.booleanValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean definitions into the given bean factory, typically through
|
||||
* delegating to one or more bean definition readers.
|
||||
* @param beanFactory the bean factory to load bean definitions into
|
||||
* @throws IOException if loading of bean definition files failed
|
||||
* @throws BeansException if parsing of the bean definitions failed
|
||||
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
*/
|
||||
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
|
||||
throws IOException, BeansException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
/**
|
||||
* {@link AbstractRefreshableApplicationContext} subclass that adds common handling
|
||||
* of specified config locations. Serves as base class for XML-based application
|
||||
* context implementations such as {@link ClassPathXmlApplicationContext} and
|
||||
* {@link FileSystemXmlApplicationContext}, as well as
|
||||
* {@link org.springframework.web.context.support.XmlWebApplicationContext} and
|
||||
* {@link org.springframework.web.portlet.context.XmlPortletApplicationContext}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
* @see #setConfigLocation
|
||||
* @see #setConfigLocations
|
||||
* @see #getDefaultConfigLocations
|
||||
*/
|
||||
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
|
||||
implements BeanNameAware, InitializingBean {
|
||||
|
||||
private String[] configLocations;
|
||||
|
||||
private boolean setIdCalled = false;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AbstractRefreshableConfigApplicationContext with no parent.
|
||||
*/
|
||||
public AbstractRefreshableConfigApplicationContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AbstractRefreshableConfigApplicationContext with the given parent context.
|
||||
* @param parent the parent context
|
||||
*/
|
||||
public AbstractRefreshableConfigApplicationContext(ApplicationContext parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the config locations for this application context in init-param style,
|
||||
* i.e. with distinct locations separated by commas, semicolons or whitespace.
|
||||
* <p>If not set, the implementation may use a default as appropriate.
|
||||
*/
|
||||
public void setConfigLocation(String location) {
|
||||
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the config locations for this application context.
|
||||
* <p>If not set, the implementation may use a default as appropriate.
|
||||
*/
|
||||
public void setConfigLocations(String[] locations) {
|
||||
if (locations != null) {
|
||||
Assert.noNullElements(locations, "Config locations must not be null");
|
||||
this.configLocations = new String[locations.length];
|
||||
for (int i = 0; i < locations.length; i++) {
|
||||
this.configLocations[i] = resolvePath(locations[i]).trim();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.configLocations = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of resource locations, referring to the XML bean definition
|
||||
* files that this context should be built with. Can also include location
|
||||
* patterns, which will get resolved via a ResourcePatternResolver.
|
||||
* <p>The default implementation returns <code>null</code>. Subclasses can override
|
||||
* this to provide a set of resource locations to load bean definitions from.
|
||||
* @return an array of resource locations, or <code>null</code> if none
|
||||
* @see #getResources
|
||||
* @see #getResourcePatternResolver
|
||||
*/
|
||||
protected String[] getConfigLocations() {
|
||||
return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default config locations to use, for the case where no
|
||||
* explicit config locations have been specified.
|
||||
* <p>The default implementation returns <code>null</code>,
|
||||
* requiring explicit config locations.
|
||||
* @return an array of default config locations, if any
|
||||
* @see #setConfigLocations
|
||||
*/
|
||||
protected String[] getDefaultConfigLocations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given path, replacing placeholders with corresponding
|
||||
* system property values if necessary. Applied to config locations.
|
||||
* @param path the original file path
|
||||
* @return the resolved file path
|
||||
* @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders
|
||||
*/
|
||||
protected String resolvePath(String path) {
|
||||
return SystemPropertyUtils.resolvePlaceholders(path);
|
||||
}
|
||||
|
||||
|
||||
public void setId(String id) {
|
||||
super.setId(id);
|
||||
this.setIdCalled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id of this context to the bean name by default,
|
||||
* for cases where the context instance is itself defined as a bean.
|
||||
*/
|
||||
public void setBeanName(String name) {
|
||||
if (!this.setIdCalled) {
|
||||
super.setId(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers {@link #refresh()} if not refreshed in the concrete context's
|
||||
* constructor already.
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
if (!isActive()) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.ResourceEntityResolver;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Convenient base class for {@link org.springframework.context.ApplicationContext}
|
||||
* implementations, drawing configuration from XML documents containing bean definitions
|
||||
* understood by an {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
|
||||
*
|
||||
* <p>Subclasses just have to implement the {@link #getConfigResources} and/or
|
||||
* the {@link #getConfigLocations} method. Furthermore, they might override
|
||||
* the {@link #getResourceByPath} hook to interpret relative paths in an
|
||||
* environment-specific fashion, and/or {@link #getResourcePatternResolver}
|
||||
* for extended pattern resolution.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #getConfigResources
|
||||
* @see #getConfigLocations
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
*/
|
||||
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
|
||||
|
||||
/**
|
||||
* Create a new AbstractXmlApplicationContext with no parent.
|
||||
*/
|
||||
public AbstractXmlApplicationContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AbstractXmlApplicationContext with the given parent context.
|
||||
* @param parent the parent context
|
||||
*/
|
||||
public AbstractXmlApplicationContext(ApplicationContext parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the bean definitions via an XmlBeanDefinitionReader.
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
* @see #initBeanDefinitionReader
|
||||
* @see #loadBeanDefinitions
|
||||
*/
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
|
||||
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
|
||||
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
|
||||
|
||||
// Configure the bean definition reader with this context's
|
||||
// resource loading environment.
|
||||
beanDefinitionReader.setResourceLoader(this);
|
||||
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
|
||||
|
||||
// Allow a subclass to provide custom initialization of the reader,
|
||||
// then proceed with actually loading the bean definitions.
|
||||
initBeanDefinitionReader(beanDefinitionReader);
|
||||
loadBeanDefinitions(beanDefinitionReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the bean definition reader used for loading the bean
|
||||
* definitions of this context. Default implementation is empty.
|
||||
* <p>Can be overridden in subclasses, e.g. for turning off XML validation
|
||||
* or using a different XmlBeanDefinitionParser implementation.
|
||||
* @param beanDefinitionReader the bean definition reader used by this context
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
|
||||
*/
|
||||
protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the bean definitions with the given XmlBeanDefinitionReader.
|
||||
* <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}
|
||||
* method; hence this method is just supposed to load and/or register bean definitions.
|
||||
* @param reader the XmlBeanDefinitionReader to use
|
||||
* @throws BeansException in case of bean registration errors
|
||||
* @throws IOException if the required XML document isn't found
|
||||
* @see #refreshBeanFactory
|
||||
* @see #getConfigLocations
|
||||
* @see #getResources
|
||||
* @see #getResourcePatternResolver
|
||||
*/
|
||||
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
|
||||
Resource[] configResources = getConfigResources();
|
||||
if (configResources != null) {
|
||||
reader.loadBeanDefinitions(configResources);
|
||||
}
|
||||
String[] configLocations = getConfigLocations();
|
||||
if (configLocations != null) {
|
||||
reader.loadBeanDefinitions(configLocations);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of Resource objects, referring to the XML bean definition
|
||||
* files that this context should be built with.
|
||||
* <p>The default implementation returns <code>null</code>. Subclasses can override
|
||||
* this to provide pre-built Resource objects rather than location Strings.
|
||||
* @return an array of Resource objects, or <code>null</code> if none
|
||||
* @see #getConfigLocations()
|
||||
*/
|
||||
protected Resource[] getConfigResources() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.support;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
|
||||
* implementation that passes the ApplicationContext to beans that
|
||||
* implement the {@link ResourceLoaderAware}, {@link MessageSourceAware},
|
||||
* {@link ApplicationEventPublisherAware} and/or
|
||||
* {@link ApplicationContextAware} interfaces.
|
||||
* If all of them are implemented, they are satisfied in the given order.
|
||||
*
|
||||
* <p>Application contexts will automatically register this with their
|
||||
* underlying bean factory. Applications do not use this directly.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 10.10.2003
|
||||
* @see org.springframework.context.ResourceLoaderAware
|
||||
* @see org.springframework.context.MessageSourceAware
|
||||
* @see org.springframework.context.ApplicationEventPublisherAware
|
||||
* @see org.springframework.context.ApplicationContextAware
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#refresh()
|
||||
*/
|
||||
class ApplicationContextAwareProcessor implements BeanPostProcessor {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ApplicationContextAwareProcessor for the given context.
|
||||
*/
|
||||
public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof ResourceLoaderAware) {
|
||||
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
|
||||
}
|
||||
if (bean instanceof ApplicationEventPublisherAware) {
|
||||
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
|
||||
}
|
||||
if (bean instanceof MessageSourceAware) {
|
||||
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
|
||||
}
|
||||
if (bean instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String name) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
|
||||
/**
|
||||
* Convenient superclass for application objects that want to be aware of
|
||||
* the application context, e.g. for custom lookup of collaborating beans
|
||||
* or for context-specific resource access. It saves the application
|
||||
* context reference and provides an initialization callback method.
|
||||
* Furthermore, it offers numerous convenience methods for message lookup.
|
||||
*
|
||||
* <p>There is no requirement to subclass this class: It just makes things
|
||||
* a little easier if you need access to the context, e.g. for access to
|
||||
* file resources or to the message source. Note that many application
|
||||
* objects do not need to be aware of the application context at all,
|
||||
* as they can receive collaborating beans via bean references.
|
||||
*
|
||||
* <p>Many framework classes are derived from this class, particularly
|
||||
* within the web support.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see org.springframework.web.context.support.WebApplicationObjectSupport
|
||||
*/
|
||||
public abstract class ApplicationObjectSupport implements ApplicationContextAware {
|
||||
|
||||
/** Logger that is available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** ApplicationContext this object runs in */
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/** MessageSourceAccessor for easy message access */
|
||||
private MessageSourceAccessor messageSourceAccessor;
|
||||
|
||||
|
||||
public final void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
if (context == null && !isContextRequired()) {
|
||||
// Reset internal context state.
|
||||
this.applicationContext = null;
|
||||
this.messageSourceAccessor = null;
|
||||
}
|
||||
else if (this.applicationContext == null) {
|
||||
// Initialize with passed-in context.
|
||||
if (!requiredContextClass().isInstance(context)) {
|
||||
throw new ApplicationContextException(
|
||||
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
|
||||
}
|
||||
this.applicationContext = context;
|
||||
this.messageSourceAccessor = new MessageSourceAccessor(context);
|
||||
initApplicationContext(context);
|
||||
}
|
||||
else {
|
||||
// Ignore reinitialization if same context passed in.
|
||||
if (this.applicationContext != context) {
|
||||
throw new ApplicationContextException(
|
||||
"Cannot reinitialize with different application context: current one is [" +
|
||||
this.applicationContext + "], passed-in one is [" + context + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this application object needs to run in an ApplicationContext.
|
||||
* <p>Default is "false". Can be overridden to enforce running in a context
|
||||
* (i.e. to throw IllegalStateException on accessors if outside a context).
|
||||
* @see #getApplicationContext
|
||||
* @see #getMessageSourceAccessor
|
||||
*/
|
||||
protected boolean isContextRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the context class that any context passed to
|
||||
* <code>setApplicationContext</code> must be an instance of.
|
||||
* Can be overridden in subclasses.
|
||||
* @see #setApplicationContext
|
||||
*/
|
||||
protected Class requiredContextClass() {
|
||||
return ApplicationContext.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this for custom initialization behavior.
|
||||
* Gets called by <code>setApplicationContext</code> after setting the context instance.
|
||||
* <p>Note: Does </i>not</i> get called on reinitialization of the context
|
||||
* but rather just on first initialization of this object's context reference.
|
||||
* <p>The default implementation calls the overloaded {@link #initApplicationContext()}
|
||||
* method without ApplicationContext reference.
|
||||
* @param context the containing ApplicationContext
|
||||
* @throws ApplicationContextException in case of initialization errors
|
||||
* @throws BeansException if thrown by ApplicationContext methods
|
||||
* @see #setApplicationContext
|
||||
*/
|
||||
protected void initApplicationContext(ApplicationContext context) throws BeansException {
|
||||
initApplicationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this for custom initialization behavior.
|
||||
* <p>The default implementation is empty. Called by
|
||||
* {@link #initApplicationContext(org.springframework.context.ApplicationContext)}.
|
||||
* @throws ApplicationContextException in case of initialization errors
|
||||
* @throws BeansException if thrown by ApplicationContext methods
|
||||
* @see #setApplicationContext
|
||||
*/
|
||||
protected void initApplicationContext() throws BeansException {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the ApplicationContext that this object is associated with.
|
||||
* @throws IllegalStateException if not running in an ApplicationContext
|
||||
*/
|
||||
public final ApplicationContext getApplicationContext() throws IllegalStateException {
|
||||
if (this.applicationContext == null && isContextRequired()) {
|
||||
throw new IllegalStateException(
|
||||
"ApplicationObjectSupport instance [" + this + "] does not run in an ApplicationContext");
|
||||
}
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a MessageSourceAccessor for the application context
|
||||
* used by this object, for easy message access.
|
||||
* @throws IllegalStateException if not running in an ApplicationContext
|
||||
*/
|
||||
protected final MessageSourceAccessor getMessageSourceAccessor() throws IllegalStateException {
|
||||
if (this.messageSourceAccessor == null && isContextRequired()) {
|
||||
throw new IllegalStateException(
|
||||
"ApplicationObjectSupport instance [" + this + "] does not run in an ApplicationContext");
|
||||
}
|
||||
return this.messageSourceAccessor;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Standalone XML application context, taking the context definition files
|
||||
* from the class path, interpreting plain paths as class path resource names
|
||||
* that include the package path (e.g. "mypackage/myresource.txt"). Useful for
|
||||
* test harnesses as well as for application contexts embedded within JARs.
|
||||
*
|
||||
* <p>The config location defaults can be overridden via {@link #getConfigLocations},
|
||||
* Config locations can either denote concrete files like "/myfiles/context.xml"
|
||||
* or Ant-style patterns like "/myfiles/*-context.xml" (see the
|
||||
* {@link org.springframework.util.AntPathMatcher} javadoc for pattern details).
|
||||
*
|
||||
* <p>Note: In case of multiple config locations, later bean definitions will
|
||||
* override ones defined in earlier loaded files. This can be leveraged to
|
||||
* deliberately override certain bean definitions via an extra XML file.
|
||||
*
|
||||
* <p><b>This is a simple, one-stop shop convenience ApplicationContext.
|
||||
* Consider using the {@link GenericApplicationContext} class in combination
|
||||
* with an {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}
|
||||
* for more flexible context setup.</b>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #getResource
|
||||
* @see #getResourceByPath
|
||||
* @see GenericApplicationContext
|
||||
*/
|
||||
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
|
||||
|
||||
private Resource[] configResources;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext for bean-style configuration.
|
||||
* @see #setConfigLocation
|
||||
* @see #setConfigLocations
|
||||
* @see #afterPropertiesSet()
|
||||
*/
|
||||
public ClassPathXmlApplicationContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext for bean-style configuration.
|
||||
* @param parent the parent context
|
||||
* @see #setConfigLocation
|
||||
* @see #setConfigLocations
|
||||
* @see #afterPropertiesSet()
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(ApplicationContext parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext, loading the definitions
|
||||
* from the given XML file and automatically refreshing the context.
|
||||
* @param configLocation resource location
|
||||
* @throws BeansException if context creation failed
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
|
||||
this(new String[] {configLocation}, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext, loading the definitions
|
||||
* from the given XML files and automatically refreshing the context.
|
||||
* @param configLocations array of resource locations
|
||||
* @throws BeansException if context creation failed
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
|
||||
this(configLocations, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext with the given parent,
|
||||
* loading the definitions from the given XML files and automatically
|
||||
* refreshing the context.
|
||||
* @param configLocations array of resource locations
|
||||
* @param parent the parent context
|
||||
* @throws BeansException if context creation failed
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
|
||||
this(configLocations, true, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext, loading the definitions
|
||||
* from the given XML files.
|
||||
* @param configLocations array of resource locations
|
||||
* @param refresh whether to automatically refresh the context,
|
||||
* loading all bean definitions and creating all singletons.
|
||||
* Alternatively, call refresh manually after further configuring the context.
|
||||
* @throws BeansException if context creation failed
|
||||
* @see #refresh()
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
|
||||
this(configLocations, refresh, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext with the given parent,
|
||||
* loading the definitions from the given XML files.
|
||||
* @param configLocations array of resource locations
|
||||
* @param refresh whether to automatically refresh the context,
|
||||
* loading all bean definitions and creating all singletons.
|
||||
* Alternatively, call refresh manually after further configuring the context.
|
||||
* @param parent the parent context
|
||||
* @throws BeansException if context creation failed
|
||||
* @see #refresh()
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
|
||||
throws BeansException {
|
||||
|
||||
super(parent);
|
||||
setConfigLocations(configLocations);
|
||||
if (refresh) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext, loading the definitions
|
||||
* from the given XML file and automatically refreshing the context.
|
||||
* <p>This is a convenience method to load class path resources relative to a
|
||||
* given Class. For full flexibility, consider using a GenericApplicationContext
|
||||
* with an XmlBeanDefinitionReader and a ClassPathResource argument.
|
||||
* @param path relative (or absolute) path within the class path
|
||||
* @param clazz the class to load resources with (basis for the given paths)
|
||||
* @throws BeansException if context creation failed
|
||||
* @see org.springframework.core.io.ClassPathResource#ClassPathResource(String, Class)
|
||||
* @see org.springframework.context.support.GenericApplicationContext
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String path, Class clazz) throws BeansException {
|
||||
this(new String[] {path}, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext, loading the definitions
|
||||
* from the given XML files and automatically refreshing the context.
|
||||
* @param paths array of relative (or absolute) paths within the class path
|
||||
* @param clazz the class to load resources with (basis for the given paths)
|
||||
* @throws BeansException if context creation failed
|
||||
* @see org.springframework.core.io.ClassPathResource#ClassPathResource(String, Class)
|
||||
* @see org.springframework.context.support.GenericApplicationContext
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String[] paths, Class clazz) throws BeansException {
|
||||
this(paths, clazz, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClassPathXmlApplicationContext with the given parent,
|
||||
* loading the definitions from the given XML files and automatically
|
||||
* refreshing the context.
|
||||
* @param paths array of relative (or absolute) paths within the class path
|
||||
* @param clazz the class to load resources with (basis for the given paths)
|
||||
* @param parent the parent context
|
||||
* @throws BeansException if context creation failed
|
||||
* @see org.springframework.core.io.ClassPathResource#ClassPathResource(String, Class)
|
||||
* @see org.springframework.context.support.GenericApplicationContext
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
*/
|
||||
public ClassPathXmlApplicationContext(String[] paths, Class clazz, ApplicationContext parent)
|
||||
throws BeansException {
|
||||
|
||||
super(parent);
|
||||
Assert.notNull(paths, "Path array must not be null");
|
||||
Assert.notNull(clazz, "Class argument must not be null");
|
||||
this.configResources = new Resource[paths.length];
|
||||
for (int i = 0; i < paths.length; i++) {
|
||||
this.configResources[i] = new ClassPathResource(paths[i], clazz);
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
|
||||
protected Resource[] getConfigResources() {
|
||||
return this.configResources;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.DecoratingClassLoader;
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Special variant of an overriding ClassLoader, used for temporary type
|
||||
* matching in {@link AbstractApplicationContext}. Redefines classes from
|
||||
* a cached byte array for every <code>loadClass</code> call in order to
|
||||
* pick up recently loaded types in the parent ClassLoader.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see AbstractApplicationContext
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setTempClassLoader
|
||||
*/
|
||||
class ContextTypeMatchClassLoader extends DecoratingClassLoader implements SmartClassLoader {
|
||||
|
||||
private static Method findLoadedClassMethod;
|
||||
|
||||
static {
|
||||
try {
|
||||
findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] {String.class});
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Invalid [java.lang.ClassLoader] class: no 'findLoadedClass' method defined!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Cache for byte array per class name */
|
||||
private final Map bytesCache = new HashMap();
|
||||
|
||||
|
||||
public ContextTypeMatchClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public Class loadClass(String name) throws ClassNotFoundException {
|
||||
return new ContextOverridingClassLoader(getParent()).loadClass(name);
|
||||
}
|
||||
|
||||
public boolean isClassReloadable(Class clazz) {
|
||||
return (clazz.getClassLoader() instanceof ContextOverridingClassLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ClassLoader to be created for each loaded class.
|
||||
* Caches class file content but redefines class for each call.
|
||||
*/
|
||||
private class ContextOverridingClassLoader extends OverridingClassLoader {
|
||||
|
||||
public ContextOverridingClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
protected boolean isEligibleForOverriding(String className) {
|
||||
if (isExcluded(className) || ContextTypeMatchClassLoader.this.isExcluded(className)) {
|
||||
return false;
|
||||
}
|
||||
ReflectionUtils.makeAccessible(findLoadedClassMethod);
|
||||
ClassLoader parent = getParent();
|
||||
while (parent != null) {
|
||||
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, new Object[] {className}) != null) {
|
||||
return false;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Class loadClassForOverriding(String name) throws ClassNotFoundException {
|
||||
byte[] bytes = (byte[]) bytesCache.get(name);
|
||||
if (bytes == null) {
|
||||
bytes = loadBytesForClass(name);
|
||||
if (bytes != null) {
|
||||
bytesCache.put(name, bytes);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link MessageSourceResolvable} interface.
|
||||
* Offers an easy way to store all the necessary values needed to resolve
|
||||
* a message via a {@link org.springframework.context.MessageSource}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 13.02.2004
|
||||
* @see org.springframework.context.MessageSource#getMessage(MessageSourceResolvable, java.util.Locale)
|
||||
*/
|
||||
public class DefaultMessageSourceResolvable implements MessageSourceResolvable, Serializable {
|
||||
|
||||
private final String[] codes;
|
||||
|
||||
private final Object[] arguments;
|
||||
|
||||
private final String defaultMessage;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new DefaultMessageSourceResolvable.
|
||||
* @param code the code to be used to resolve this message
|
||||
*/
|
||||
public DefaultMessageSourceResolvable(String code) {
|
||||
this(new String[] {code}, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DefaultMessageSourceResolvable.
|
||||
* @param codes the codes to be used to resolve this message
|
||||
*/
|
||||
public DefaultMessageSourceResolvable(String[] codes) {
|
||||
this(codes, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DefaultMessageSourceResolvable.
|
||||
* @param codes the codes to be used to resolve this message
|
||||
* @param defaultMessage the default message to be used to resolve this message
|
||||
*/
|
||||
public DefaultMessageSourceResolvable(String[] codes, String defaultMessage) {
|
||||
this(codes, null, defaultMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DefaultMessageSourceResolvable.
|
||||
* @param codes the codes to be used to resolve this message
|
||||
* @param arguments the array of arguments to be used to resolve this message
|
||||
*/
|
||||
public DefaultMessageSourceResolvable(String[] codes, Object[] arguments) {
|
||||
this(codes, arguments, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DefaultMessageSourceResolvable.
|
||||
* @param codes the codes to be used to resolve this message
|
||||
* @param arguments the array of arguments to be used to resolve this message
|
||||
* @param defaultMessage the default message to be used to resolve this message
|
||||
*/
|
||||
public DefaultMessageSourceResolvable(String[] codes, Object[] arguments, String defaultMessage) {
|
||||
this.codes = codes;
|
||||
this.arguments = arguments;
|
||||
this.defaultMessage = defaultMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor: Create a new instance from another resolvable.
|
||||
* @param resolvable the resolvable to copy from
|
||||
*/
|
||||
public DefaultMessageSourceResolvable(MessageSourceResolvable resolvable) {
|
||||
this(resolvable.getCodes(), resolvable.getArguments(), resolvable.getDefaultMessage());
|
||||
}
|
||||
|
||||
|
||||
public String[] getCodes() {
|
||||
return this.codes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default code of this resolvable, that is,
|
||||
* the last one in the codes array.
|
||||
*/
|
||||
public String getCode() {
|
||||
return (this.codes != null && this.codes.length > 0) ? this.codes[this.codes.length - 1] : null;
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return this.arguments;
|
||||
}
|
||||
|
||||
public String getDefaultMessage() {
|
||||
return this.defaultMessage;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a default String representation for this MessageSourceResolvable:
|
||||
* including codes, arguments, and default message.
|
||||
*/
|
||||
protected final String resolvableToString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("codes [").append(StringUtils.arrayToDelimitedString(this.codes, ","));
|
||||
buf.append("]; arguments [" + StringUtils.arrayToDelimitedString(this.arguments, ","));
|
||||
buf.append("]; default message [").append(this.defaultMessage).append(']');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation exposes the attributes of this MessageSourceResolvable.
|
||||
* To be overridden in more specific subclasses, potentially including the
|
||||
* resolvable content through <code>resolvableToString()</code>.
|
||||
* @see #resolvableToString()
|
||||
*/
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + resolvableToString();
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof MessageSourceResolvable)) {
|
||||
return false;
|
||||
}
|
||||
MessageSourceResolvable otherResolvable = (MessageSourceResolvable) other;
|
||||
return ObjectUtils.nullSafeEquals(getCodes(), otherResolvable.getCodes()) &&
|
||||
ObjectUtils.nullSafeEquals(getArguments(), otherResolvable.getArguments()) &&
|
||||
ObjectUtils.nullSafeEquals(getDefaultMessage(), otherResolvable.getDefaultMessage());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(getCodes());
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(getArguments());
|
||||
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(getDefaultMessage());
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.context.HierarchicalMessageSource;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
|
||||
/**
|
||||
* Empty {@link MessageSource} that delegates all calls to the parent MessageSource.
|
||||
* If no parent is available, it simply won't resolve any message.
|
||||
*
|
||||
* <p>Used as placeholder by AbstractApplicationContext, if the context doesn't
|
||||
* define its own MessageSource. Not intended for direct use in applications.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.5
|
||||
* @see AbstractApplicationContext
|
||||
*/
|
||||
public class DelegatingMessageSource extends MessageSourceSupport implements HierarchicalMessageSource {
|
||||
|
||||
private MessageSource parentMessageSource;
|
||||
|
||||
|
||||
public void setParentMessageSource(MessageSource parent) {
|
||||
this.parentMessageSource = parent;
|
||||
}
|
||||
|
||||
public MessageSource getParentMessageSource() {
|
||||
return this.parentMessageSource;
|
||||
}
|
||||
|
||||
|
||||
public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
|
||||
if (this.parentMessageSource != null) {
|
||||
return this.parentMessageSource.getMessage(code, args, defaultMessage, locale);
|
||||
}
|
||||
else {
|
||||
return renderDefaultMessage(defaultMessage, args, locale);
|
||||
}
|
||||
}
|
||||
|
||||
public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
|
||||
if (this.parentMessageSource != null) {
|
||||
return this.parentMessageSource.getMessage(code, args, locale);
|
||||
}
|
||||
else {
|
||||
throw new NoSuchMessageException(code, locale);
|
||||
}
|
||||
}
|
||||
|
||||
public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
|
||||
if (this.parentMessageSource != null) {
|
||||
return this.parentMessageSource.getMessage(resolvable, locale);
|
||||
}
|
||||
else {
|
||||
if (resolvable.getDefaultMessage() != null) {
|
||||
return renderDefaultMessage(resolvable.getDefaultMessage(), resolvable.getArguments(), locale);
|
||||
}
|
||||
String[] codes = resolvable.getCodes();
|
||||
String code = (codes != null && codes.length > 0 ? codes[0] : null);
|
||||
throw new NoSuchMessageException(code, locale);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Standalone XML application context, taking the context definition files
|
||||
* from the file system or from URLs, interpreting plain paths as relative
|
||||
* file system locations (e.g. "mydir/myfile.txt"). Useful for test harnesses
|
||||
* as well as for standalone environments.
|
||||
*
|
||||
* <p><b>NOTE:</b> Plain paths will always be interpreted as relative
|
||||
* to the current VM working directory, even if they start with a slash.
|
||||
* (This is consistent with the semantics in a Servlet container.)
|
||||
* <b>Use an explicit "file:" prefix to enforce an absolute file path.</b>
|
||||
*
|
||||
* <p>The config location defaults can be overridden via {@link #getConfigLocations},
|
||||
* Config locations can either denote concrete files like "/myfiles/context.xml"
|
||||
* or Ant-style patterns like "/myfiles/*-context.xml" (see the
|
||||
* {@link org.springframework.util.AntPathMatcher} javadoc for pattern details).
|
||||
*
|
||||
* <p>Note: In case of multiple config locations, later bean definitions will
|
||||
* override ones defined in earlier loaded files. This can be leveraged to
|
||||
* deliberately override certain bean definitions via an extra XML file.
|
||||
*
|
||||
* <p><b>This is a simple, one-stop shop convenience ApplicationContext.
|
||||
* Consider using the {@link GenericApplicationContext} class in combination
|
||||
* with an {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}
|
||||
* for more flexible context setup.</b>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #getResource
|
||||
* @see #getResourceByPath
|
||||
* @see GenericApplicationContext
|
||||
*/
|
||||
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
|
||||
|
||||
/**
|
||||
* Create a new FileSystemXmlApplicationContext for bean-style configuration.
|
||||
* @see #setConfigLocation
|
||||
* @see #setConfigLocations
|
||||
* @see #afterPropertiesSet()
|
||||
*/
|
||||
public FileSystemXmlApplicationContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileSystemXmlApplicationContext for bean-style configuration.
|
||||
* @param parent the parent context
|
||||
* @see #setConfigLocation
|
||||
* @see #setConfigLocations
|
||||
* @see #afterPropertiesSet()
|
||||
*/
|
||||
public FileSystemXmlApplicationContext(ApplicationContext parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileSystemXmlApplicationContext, loading the definitions
|
||||
* from the given XML file and automatically refreshing the context.
|
||||
* @param configLocation file path
|
||||
* @throws BeansException if context creation failed
|
||||
*/
|
||||
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
|
||||
this(new String[] {configLocation}, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileSystemXmlApplicationContext, loading the definitions
|
||||
* from the given XML files and automatically refreshing the context.
|
||||
* @param configLocations array of file paths
|
||||
* @throws BeansException if context creation failed
|
||||
*/
|
||||
public FileSystemXmlApplicationContext(String[] configLocations) throws BeansException {
|
||||
this(configLocations, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileSystemXmlApplicationContext with the given parent,
|
||||
* loading the definitions from the given XML files and automatically
|
||||
* refreshing the context.
|
||||
* @param configLocations array of file paths
|
||||
* @param parent the parent context
|
||||
* @throws BeansException if context creation failed
|
||||
*/
|
||||
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
|
||||
this(configLocations, true, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileSystemXmlApplicationContext, loading the definitions
|
||||
* from the given XML files.
|
||||
* @param configLocations array of file paths
|
||||
* @param refresh whether to automatically refresh the context,
|
||||
* loading all bean definitions and creating all singletons.
|
||||
* Alternatively, call refresh manually after further configuring the context.
|
||||
* @throws BeansException if context creation failed
|
||||
* @see #refresh()
|
||||
*/
|
||||
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
|
||||
this(configLocations, refresh, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FileSystemXmlApplicationContext with the given parent,
|
||||
* loading the definitions from the given XML files.
|
||||
* @param configLocations array of file paths
|
||||
* @param refresh whether to automatically refresh the context,
|
||||
* loading all bean definitions and creating all singletons.
|
||||
* Alternatively, call refresh manually after further configuring the context.
|
||||
* @param parent the parent context
|
||||
* @throws BeansException if context creation failed
|
||||
* @see #refresh()
|
||||
*/
|
||||
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
|
||||
throws BeansException {
|
||||
|
||||
super(parent);
|
||||
setConfigLocations(configLocations);
|
||||
if (refresh) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve resource paths as file system paths.
|
||||
* <p>Note: Even if a given path starts with a slash, it will get
|
||||
* interpreted as relative to the current VM working directory.
|
||||
* This is consistent with the semantics in a Servlet container.
|
||||
* @param path path to the resource
|
||||
* @return Resource handle
|
||||
* @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath
|
||||
*/
|
||||
protected Resource getResourceByPath(String path) {
|
||||
if (path != null && path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
return new FileSystemResource(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Generic ApplicationContext implementation that holds a single internal
|
||||
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
|
||||
* instance and does not assume a specific bean definition format. Implements
|
||||
* the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
|
||||
* interface in order to allow for applying any bean definition readers to it.
|
||||
*
|
||||
* <p>Typical usage is to register a variety of bean definitions via the
|
||||
* {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
|
||||
* interface and then call {@link #refresh()} to initialize those beans
|
||||
* with application context semantics (handling
|
||||
* {@link org.springframework.context.ApplicationContextAware}, auto-detecting
|
||||
* {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors},
|
||||
* etc).
|
||||
*
|
||||
* <p>In contrast to other ApplicationContext implementations that create a new
|
||||
* internal BeanFactory instance for each refresh, the internal BeanFactory of
|
||||
* this context is available right from the start, to be able to register bean
|
||||
* definitions on it. {@link #refresh()} may only be called once.
|
||||
*
|
||||
* <p>Usage example:
|
||||
*
|
||||
* <pre>
|
||||
* GenericApplicationContext ctx = new GenericApplicationContext();
|
||||
* XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
|
||||
* xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
|
||||
* PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
|
||||
* propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
|
||||
* ctx.refresh();
|
||||
*
|
||||
* MyBean myBean = (MyBean) ctx.getBean("myBean");
|
||||
* ...</pre>
|
||||
*
|
||||
* For the typical case of XML bean definitions, simply use
|
||||
* {@link ClassPathXmlApplicationContext} or {@link FileSystemXmlApplicationContext},
|
||||
* which are easier to set up - but less flexible, since you can just use standard
|
||||
* resource locations for XML bean definitions, rather than mixing arbitrary bean
|
||||
* definition formats. The equivalent in a web environment is
|
||||
* {@link org.springframework.web.context.support.XmlWebApplicationContext}.
|
||||
*
|
||||
* <p>For custom application context implementations that are supposed to read
|
||||
* special bean definition formats in a refreshable manner, consider deriving
|
||||
* from the {@link AbstractRefreshableApplicationContext} base class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.2
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh()
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
|
||||
*/
|
||||
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
|
||||
|
||||
private final DefaultListableBeanFactory beanFactory;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private boolean refreshed = false;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new GenericApplicationContext.
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public GenericApplicationContext() {
|
||||
this.beanFactory = new DefaultListableBeanFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
|
||||
* @param beanFactory the DefaultListableBeanFactory instance to use for this context
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new GenericApplicationContext with the given parent.
|
||||
* @param parent the parent application context
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public GenericApplicationContext(ApplicationContext parent) {
|
||||
this();
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
|
||||
* @param beanFactory the DefaultListableBeanFactory instance to use for this context
|
||||
* @param parent the parent application context
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent) {
|
||||
this(beanFactory);
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the parent of this application context, also setting
|
||||
* the parent of the internal BeanFactory accordingly.
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setParentBeanFactory
|
||||
*/
|
||||
public void setParent(ApplicationContext parent) {
|
||||
super.setParent(parent);
|
||||
this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a ResourceLoader to use for this context. If set, the context will
|
||||
* delegate all <code>getResource</code> calls to the given ResourceLoader.
|
||||
* If not set, default resource loading will apply.
|
||||
* <p>The main reason to specify a custom ResourceLoader is to resolve
|
||||
* resource paths (withour URL prefix) in a specific fashion.
|
||||
* The default behavior is to resolve such paths as class path locations.
|
||||
* To resolve resource paths as file system locations, specify a
|
||||
* FileSystemResourceLoader here.
|
||||
* <p>You can also pass in a full ResourcePatternResolver, which will
|
||||
* be autodetected by the context and used for <code>getResources</code>
|
||||
* calls as well. Else, default resource pattern matching will apply.
|
||||
* @see #getResource
|
||||
* @see org.springframework.core.io.DefaultResourceLoader
|
||||
* @see org.springframework.core.io.FileSystemResourceLoader
|
||||
* @see org.springframework.core.io.support.ResourcePatternResolver
|
||||
* @see #getResources
|
||||
*/
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation delegates to this context's ResourceLoader if set,
|
||||
* falling back to the default superclass behavior else.
|
||||
* @see #setResourceLoader
|
||||
*/
|
||||
public Resource getResource(String location) {
|
||||
if (this.resourceLoader != null) {
|
||||
return this.resourceLoader.getResource(location);
|
||||
}
|
||||
return super.getResource(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to this context's ResourceLoader if it
|
||||
* implements the ResourcePatternResolver interface, falling back to the
|
||||
* default superclass behavior else.
|
||||
* @see #setResourceLoader
|
||||
*/
|
||||
public Resource[] getResources(String locationPattern) throws IOException {
|
||||
if (this.resourceLoader instanceof ResourcePatternResolver) {
|
||||
return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern);
|
||||
}
|
||||
return super.getResources(locationPattern);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementations of AbstractApplicationContext's template methods
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Do nothing: We hold a single internal BeanFactory and rely on callers
|
||||
* to register beans through our public methods (or the BeanFactory's).
|
||||
* @see #registerBeanDefinition
|
||||
*/
|
||||
protected final void refreshBeanFactory() throws IllegalStateException {
|
||||
if (this.refreshed) {
|
||||
throw new IllegalStateException(
|
||||
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
|
||||
}
|
||||
this.refreshed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing: We hold a single internal BeanFactory that will never
|
||||
* get released.
|
||||
*/
|
||||
protected final void closeBeanFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the single internal BeanFactory held by this context
|
||||
* (as ConfigurableListableBeanFactory).
|
||||
*/
|
||||
public final ConfigurableListableBeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying bean factory of this context,
|
||||
* available for registering bean definitions.
|
||||
* <p><b>NOTE:</b> You need to call {@link #refresh()} to initialize the
|
||||
* bean factory and its contained beans with application context semantics
|
||||
* (autodetecting BeanFactoryPostProcessors, etc).
|
||||
* @return the internal bean factory (as DefaultListableBeanFactory)
|
||||
*/
|
||||
public final DefaultListableBeanFactory getDefaultListableBeanFactory() {
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Implementation of BeanDefinitionRegistry
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
|
||||
}
|
||||
|
||||
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
|
||||
this.beanFactory.removeBeanDefinition(beanName);
|
||||
}
|
||||
|
||||
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
|
||||
return this.beanFactory.getBeanDefinition(beanName);
|
||||
}
|
||||
|
||||
public boolean isBeanNameInUse(String beanName) {
|
||||
return this.beanFactory.isBeanNameInUse(beanName);
|
||||
}
|
||||
|
||||
public void registerAlias(String beanName, String alias) {
|
||||
this.beanFactory.registerAlias(beanName, alias);
|
||||
}
|
||||
|
||||
public void removeAlias(String alias) {
|
||||
this.beanFactory.removeAlias(alias);
|
||||
}
|
||||
|
||||
public boolean isAlias(String beanName) {
|
||||
return this.beanFactory.isAlias(beanName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context.support;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
/**
|
||||
* Helper class for easy access to messages from a MessageSource,
|
||||
* providing various overloaded getMessage methods.
|
||||
*
|
||||
* <p>Available from ApplicationObjectSupport, but also reusable
|
||||
* as a standalone helper to delegate to in application objects.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 23.10.2003
|
||||
* @see ApplicationObjectSupport#getMessageSourceAccessor
|
||||
*/
|
||||
public class MessageSourceAccessor {
|
||||
|
||||
private final MessageSource messageSource;
|
||||
|
||||
private final Locale defaultLocale;
|
||||
|
||||
/**
|
||||
* Create a new MessageSourceAccessor, using LocaleContextHolder's locale
|
||||
* as default locale.
|
||||
* @param messageSource the MessageSource to wrap
|
||||
* @see org.springframework.context.i18n.LocaleContextHolder#getLocale()
|
||||
*/
|
||||
public MessageSourceAccessor(MessageSource messageSource) {
|
||||
this.messageSource = messageSource;
|
||||
this.defaultLocale = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MessageSourceAccessor, using the given default locale.
|
||||
* @param messageSource the MessageSource to wrap
|
||||
* @param defaultLocale the default locale to use for message access
|
||||
*/
|
||||
public MessageSourceAccessor(MessageSource messageSource, Locale defaultLocale) {
|
||||
this.messageSource = messageSource;
|
||||
this.defaultLocale = defaultLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default locale to use if no explicit locale has been given.
|
||||
* <p>The default implementation returns the default locale passed into the
|
||||
* corresponding constructor, or LocaleContextHolder's locale as fallback.
|
||||
* Can be overridden in subclasses.
|
||||
* @see #MessageSourceAccessor(org.springframework.context.MessageSource, java.util.Locale)
|
||||
* @see org.springframework.context.i18n.LocaleContextHolder#getLocale()
|
||||
*/
|
||||
protected Locale getDefaultLocale() {
|
||||
return (this.defaultLocale != null ? this.defaultLocale : LocaleContextHolder.getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the default Locale.
|
||||
* @param code code of the message
|
||||
* @param defaultMessage String to return if the lookup fails
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage(String code, String defaultMessage) {
|
||||
return this.messageSource.getMessage(code, null, defaultMessage, getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the given Locale.
|
||||
* @param code code of the message
|
||||
* @param defaultMessage String to return if the lookup fails
|
||||
* @param locale Locale in which to do lookup
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage(String code, String defaultMessage, Locale locale) {
|
||||
return this.messageSource.getMessage(code, null, defaultMessage, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the default Locale.
|
||||
* @param code code of the message
|
||||
* @param args arguments for the message, or <code>null</code> if none
|
||||
* @param defaultMessage String to return if the lookup fails
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage(String code, Object[] args, String defaultMessage) {
|
||||
return this.messageSource.getMessage(code, args, defaultMessage, getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the given Locale.
|
||||
* @param code code of the message
|
||||
* @param args arguments for the message, or <code>null</code> if none
|
||||
* @param defaultMessage String to return if the lookup fails
|
||||
* @param locale Locale in which to do lookup
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
|
||||
return this.messageSource.getMessage(code, args, defaultMessage, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the default Locale.
|
||||
* @param code code of the message
|
||||
* @return the message
|
||||
* @throws org.springframework.context.NoSuchMessageException if not found
|
||||
*/
|
||||
public String getMessage(String code) throws NoSuchMessageException {
|
||||
return this.messageSource.getMessage(code, null, getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the given Locale.
|
||||
* @param code code of the message
|
||||
* @param locale Locale in which to do lookup
|
||||
* @return the message
|
||||
* @throws org.springframework.context.NoSuchMessageException if not found
|
||||
*/
|
||||
public String getMessage(String code, Locale locale) throws NoSuchMessageException {
|
||||
return this.messageSource.getMessage(code, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the default Locale.
|
||||
* @param code code of the message
|
||||
* @param args arguments for the message, or <code>null</code> if none
|
||||
* @return the message
|
||||
* @throws org.springframework.context.NoSuchMessageException if not found
|
||||
*/
|
||||
public String getMessage(String code, Object[] args) throws NoSuchMessageException {
|
||||
return this.messageSource.getMessage(code, args, getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message for the given code and the given Locale.
|
||||
* @param code code of the message
|
||||
* @param args arguments for the message, or <code>null</code> if none
|
||||
* @param locale Locale in which to do lookup
|
||||
* @return the message
|
||||
* @throws org.springframework.context.NoSuchMessageException if not found
|
||||
*/
|
||||
public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
|
||||
return this.messageSource.getMessage(code, args, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the given MessageSourceResolvable (e.g. an ObjectError instance)
|
||||
* in the default Locale.
|
||||
* @param resolvable the MessageSourceResolvable
|
||||
* @return the message
|
||||
* @throws org.springframework.context.NoSuchMessageException if not found
|
||||
*/
|
||||
public String getMessage(MessageSourceResolvable resolvable) throws NoSuchMessageException {
|
||||
return this.messageSource.getMessage(resolvable, getDefaultLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the given MessageSourceResolvable (e.g. an ObjectError instance)
|
||||
* in the given Locale.
|
||||
* @param resolvable the MessageSourceResolvable
|
||||
* @param locale Locale in which to do lookup
|
||||
* @return the message
|
||||
* @throws org.springframework.context.NoSuchMessageException if not found
|
||||
*/
|
||||
public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
|
||||
return this.messageSource.getMessage(resolvable, locale);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class that allows for accessing a Spring
|
||||
* {@link org.springframework.context.MessageSource} as a {@link java.util.ResourceBundle}.
|
||||
* Used for example to expose a Spring MessageSource to JSTL web views.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 27.02.2003
|
||||
* @see org.springframework.context.MessageSource
|
||||
* @see java.util.ResourceBundle
|
||||
* @see org.springframework.web.servlet.support.JstlUtils#exposeLocalizationContext
|
||||
*/
|
||||
public class MessageSourceResourceBundle extends ResourceBundle {
|
||||
|
||||
private final MessageSource messageSource;
|
||||
|
||||
private final Locale locale;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new MessageSourceResourceBundle for the given MessageSource and Locale.
|
||||
* @param source the MessageSource to retrieve messages from
|
||||
* @param locale the Locale to retrieve messages for
|
||||
*/
|
||||
public MessageSourceResourceBundle(MessageSource source, Locale locale) {
|
||||
Assert.notNull(source, "MessageSource must not be null");
|
||||
this.messageSource = source;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MessageSourceResourceBundle for the given MessageSource and Locale.
|
||||
* @param source the MessageSource to retrieve messages from
|
||||
* @param locale the Locale to retrieve messages for
|
||||
* @param parent the parent ResourceBundle to delegate to if no local message found
|
||||
*/
|
||||
public MessageSourceResourceBundle(MessageSource source, Locale locale, ResourceBundle parent) {
|
||||
this(source, locale);
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation resolves the code in the MessageSource.
|
||||
* Returns <code>null</code> if the message could not be resolved.
|
||||
*/
|
||||
protected Object handleGetObject(String code) {
|
||||
try {
|
||||
return this.messageSource.getMessage(code, null, this.locale);
|
||||
}
|
||||
catch (NoSuchMessageException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns <code>null</code>, as a MessageSource does
|
||||
* not allow for enumerating the defined message codes.
|
||||
*/
|
||||
public Enumeration getKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation exposes the specified Locale for introspection
|
||||
* through the standard <code>ResourceBundle.getLocale()</code> method.
|
||||
*/
|
||||
public Locale getLocale() {
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Base class for message source implementations, providing support infrastructure
|
||||
* such as {@link java.text.MessageFormat} handling but not implementing concrete
|
||||
* methods defined in the {@link org.springframework.context.MessageSource}.
|
||||
*
|
||||
* <p>{@link AbstractMessageSource} derives from this class, providing concrete
|
||||
* <code>getMessage</code> implementations that delegate to a central template
|
||||
* method for message code resolution.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.5
|
||||
*/
|
||||
public abstract class MessageSourceSupport {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private boolean alwaysUseMessageFormat = false;
|
||||
|
||||
/**
|
||||
* Cache to hold already generated MessageFormats per message.
|
||||
* Used for passed-in default messages. MessageFormats for resolved
|
||||
* codes are cached on a specific basis in subclasses.
|
||||
*/
|
||||
private final Map cachedMessageFormats = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to always apply the MessageFormat rules, parsing even
|
||||
* messages without arguments.
|
||||
* <p>Default is "false": Messages without arguments are by default
|
||||
* returned as-is, without parsing them through MessageFormat.
|
||||
* Set this to "true" to enforce MessageFormat for all messages,
|
||||
* expecting all message texts to be written with MessageFormat escaping.
|
||||
* <p>For example, MessageFormat expects a single quote to be escaped
|
||||
* as "''". If your message texts are all written with such escaping,
|
||||
* even when not defining argument placeholders, you need to set this
|
||||
* flag to "true". Else, only message texts with actual arguments
|
||||
* are supposed to be written with MessageFormat escaping.
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
public void setAlwaysUseMessageFormat(boolean alwaysUseMessageFormat) {
|
||||
this.alwaysUseMessageFormat = alwaysUseMessageFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to always apply the MessageFormat rules, parsing even
|
||||
* messages without arguments.
|
||||
*/
|
||||
protected boolean isAlwaysUseMessageFormat() {
|
||||
return this.alwaysUseMessageFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format the given message String, using cached MessageFormats.
|
||||
* By default invoked for passed-in default messages, to resolve
|
||||
* any argument placeholders found in them.
|
||||
* @param msg the message to format
|
||||
* @param args array of arguments that will be filled in for params within
|
||||
* the message, or <code>null</code> if none.
|
||||
* @param locale the Locale used for formatting
|
||||
* @return the formatted message (with resolved arguments)
|
||||
*/
|
||||
protected String formatMessage(String msg, Object[] args, Locale locale) {
|
||||
if (msg == null || (!this.alwaysUseMessageFormat && (args == null || args.length == 0))) {
|
||||
return msg;
|
||||
}
|
||||
MessageFormat messageFormat = null;
|
||||
synchronized (this.cachedMessageFormats) {
|
||||
messageFormat = (MessageFormat) this.cachedMessageFormats.get(msg);
|
||||
if (messageFormat == null) {
|
||||
messageFormat = createMessageFormat(msg, locale);
|
||||
this.cachedMessageFormats.put(msg, messageFormat);
|
||||
}
|
||||
}
|
||||
synchronized (messageFormat) {
|
||||
return messageFormat.format(resolveArguments(args, locale));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MessageFormat for the given message and Locale.
|
||||
* @param msg the message to create a MessageFormat for
|
||||
* @param locale the Locale to create a MessageFormat for
|
||||
* @return the MessageFormat instance
|
||||
*/
|
||||
protected MessageFormat createMessageFormat(String msg, Locale locale) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating MessageFormat for pattern [" + msg + "] and locale '" + locale + "'");
|
||||
}
|
||||
return new MessageFormat((msg != null ? msg : ""), locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for resolving argument objects.
|
||||
* <p>The default implementation simply returns the given argument
|
||||
* array as-is. Can be overridden in subclasses in order to resolve
|
||||
* special argument types.
|
||||
* @param args the original argument array
|
||||
* @param locale the Locale to resolve against
|
||||
* @return the resolved argument array
|
||||
*/
|
||||
protected Object[] resolveArguments(Object[] args, Locale locale) {
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render the given default message String. The default message is
|
||||
* passed in as specified by the caller and can be rendered into
|
||||
* a fully formatted default message shown to the user.
|
||||
* <p>The default implementation passes the String to <code>formatMessage</code>,
|
||||
* resolving any argument placeholders found in them. Subclasses may override
|
||||
* this method to plug in custom processing of default messages.
|
||||
* @param defaultMessage the passed-in default message String
|
||||
* @param args array of arguments that will be filled in for params within
|
||||
* the message, or <code>null</code> if none.
|
||||
* @param locale the Locale used for formatting
|
||||
* @return the rendered default message (with resolved arguments)
|
||||
* @see #formatMessage(String, Object[], java.util.Locale)
|
||||
*/
|
||||
protected String renderDefaultMessage(String defaultMessage, Object[] args, Locale locale) {
|
||||
return formatMessage(defaultMessage, args, locale);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,663 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.DefaultPropertiesPersister;
|
||||
import org.springframework.util.PropertiesPersister;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.context.MessageSource} implementation that
|
||||
* accesses resource bundles using specified basenames. This class uses
|
||||
* {@link java.util.Properties} instances as its custom data structure for
|
||||
* messages, loading them via a {@link org.springframework.util.PropertiesPersister}
|
||||
* strategy: The default strategy is capable of loading properties files
|
||||
* with a specific character encoding, if desired.
|
||||
*
|
||||
* <p>In contrast to {@link ResourceBundleMessageSource}, this class supports
|
||||
* reloading of properties files through the {@link #setCacheSeconds "cacheSeconds"}
|
||||
* setting, and also through programmatically clearing the properties cache.
|
||||
* Since application servers typically cache all files loaded from the classpath,
|
||||
* it is necessary to store resources somewhere else (for example, in the
|
||||
* "WEB-INF" directory of a web app). Otherwise changes of files in the
|
||||
* classpath will <i>not</i> be reflected in the application.
|
||||
*
|
||||
* <p>Note that the base names set as {@link #setBasenames "basenames"} property
|
||||
* are treated in a slightly different fashion than the "basenames" property of
|
||||
* {@link ResourceBundleMessageSource}. It follows the basic ResourceBundle rule of not
|
||||
* specifying file extension or language codes, but can refer to any Spring resource
|
||||
* location (instead of being restricted to classpath resources). With a "classpath:"
|
||||
* prefix, resources can still be loaded from the classpath, but "cacheSeconds" values
|
||||
* other than "-1" (caching forever) will not work in this case.
|
||||
*
|
||||
* <p>This MessageSource implementation is usually slightly faster than
|
||||
* {@link ResourceBundleMessageSource}, which builds on {@link java.util.ResourceBundle}
|
||||
* - in the default mode, i.e. when caching forever. With "cacheSeconds" set to 1,
|
||||
* message lookup takes about twice as long - with the benefit that changes in
|
||||
* individual properties files are detected with a maximum delay of 1 second.
|
||||
* Higher "cacheSeconds" values usually <i>do not</i> make a significant difference.
|
||||
*
|
||||
* <p>This MessageSource can easily be used outside of an
|
||||
* {@link org.springframework.context.ApplicationContext}: It will use a
|
||||
* {@link org.springframework.core.io.DefaultResourceLoader} as default,
|
||||
* simply getting overridden with the ApplicationContext's resource loader
|
||||
* if running in a context. It does not have any other specific dependencies.
|
||||
*
|
||||
* <p>Thanks to Thomas Achleitner for providing the initial implementation of
|
||||
* this message source!
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see #setCacheSeconds
|
||||
* @see #setBasenames
|
||||
* @see #setDefaultEncoding
|
||||
* @see #setFileEncodings
|
||||
* @see #setPropertiesPersister
|
||||
* @see #setResourceLoader
|
||||
* @see org.springframework.util.DefaultPropertiesPersister
|
||||
* @see org.springframework.core.io.DefaultResourceLoader
|
||||
* @see ResourceBundleMessageSource
|
||||
* @see java.util.ResourceBundle
|
||||
*/
|
||||
public class ReloadableResourceBundleMessageSource extends AbstractMessageSource
|
||||
implements ResourceLoaderAware {
|
||||
|
||||
private static final String PROPERTIES_SUFFIX = ".properties";
|
||||
|
||||
private static final String XML_SUFFIX = ".xml";
|
||||
|
||||
|
||||
private String[] basenames = new String[0];
|
||||
|
||||
private String defaultEncoding;
|
||||
|
||||
private Properties fileEncodings;
|
||||
|
||||
private boolean fallbackToSystemLocale = true;
|
||||
|
||||
private long cacheMillis = -1;
|
||||
|
||||
private PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
|
||||
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
/** Cache to hold filename lists per Locale */
|
||||
private final Map cachedFilenames = new HashMap();
|
||||
|
||||
/** Cache to hold already loaded properties per filename */
|
||||
private final Map cachedProperties = new HashMap();
|
||||
|
||||
/** Cache to hold merged loaded properties per basename */
|
||||
private final Map cachedMergedProperties = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Set a single basename, following the basic ResourceBundle convention of
|
||||
* not specifying file extension or language codes, but in contrast to
|
||||
* {@link ResourceBundleMessageSource} referring to a Spring resource location:
|
||||
* e.g. "WEB-INF/messages" for "WEB-INF/messages.properties",
|
||||
* "WEB-INF/messages_en.properties", etc.
|
||||
* <p>As of Spring 1.2.2, XML properties files are also supported:
|
||||
* e.g. "WEB-INF/messages" will find and load "WEB-INF/messages.xml",
|
||||
* "WEB-INF/messages_en.xml", etc as well. Note that this will only
|
||||
* work on JDK 1.5+.
|
||||
* @param basename the single basename
|
||||
* @see #setBasenames
|
||||
* @see org.springframework.core.io.ResourceEditor
|
||||
* @see java.util.ResourceBundle
|
||||
*/
|
||||
public void setBasename(String basename) {
|
||||
setBasenames(new String[] {basename});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an array of basenames, each following the basic ResourceBundle convention
|
||||
* of not specifying file extension or language codes, but in contrast to
|
||||
* {@link ResourceBundleMessageSource} referring to a Spring resource location:
|
||||
* e.g. "WEB-INF/messages" for "WEB-INF/messages.properties",
|
||||
* "WEB-INF/messages_en.properties", etc.
|
||||
* <p>As of Spring 1.2.2, XML properties files are also supported:
|
||||
* e.g. "WEB-INF/messages" will find and load "WEB-INF/messages.xml",
|
||||
* "WEB-INF/messages_en.xml", etc as well. Note that this will only
|
||||
* work on JDK 1.5+.
|
||||
* <p>The associated resource bundles will be checked sequentially
|
||||
* when resolving a message code. Note that message definitions in a
|
||||
* <i>previous</i> resource bundle will override ones in a later bundle,
|
||||
* due to the sequential lookup.
|
||||
* @param basenames an array of basenames
|
||||
* @see #setBasename
|
||||
* @see java.util.ResourceBundle
|
||||
*/
|
||||
public void setBasenames(String[] basenames) {
|
||||
if (basenames != null) {
|
||||
this.basenames = new String[basenames.length];
|
||||
for (int i = 0; i < basenames.length; i++) {
|
||||
String basename = basenames[i];
|
||||
Assert.hasText(basename, "Basename must not be empty");
|
||||
this.basenames[i] = basename.trim();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.basenames = new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default charset to use for parsing properties files.
|
||||
* Used if no file-specific charset is specified for a file.
|
||||
* <p>Default is none, using the <code>java.util.Properties</code>
|
||||
* default encoding.
|
||||
* <p>Only applies to classic properties files, not to XML files.
|
||||
* @param defaultEncoding the default charset
|
||||
* @see #setFileEncodings
|
||||
* @see org.springframework.util.PropertiesPersister#load
|
||||
*/
|
||||
public void setDefaultEncoding(String defaultEncoding) {
|
||||
this.defaultEncoding = defaultEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set per-file charsets to use for parsing properties files.
|
||||
* <p>Only applies to classic properties files, not to XML files.
|
||||
* @param fileEncodings Properties with filenames as keys and charset
|
||||
* names as values. Filenames have to match the basename syntax,
|
||||
* with optional locale-specific appendices: e.g. "WEB-INF/messages"
|
||||
* or "WEB-INF/messages_en".
|
||||
* @see #setBasenames
|
||||
* @see org.springframework.util.PropertiesPersister#load
|
||||
*/
|
||||
public void setFileEncodings(Properties fileEncodings) {
|
||||
this.fileEncodings = fileEncodings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to fall back to the system Locale if no files for a specific
|
||||
* Locale have been found. Default is "true"; if this is turned off, the only
|
||||
* fallback will be the default file (e.g. "messages.properties" for
|
||||
* basename "messages").
|
||||
* <p>Falling back to the system Locale is the default behavior of
|
||||
* <code>java.util.ResourceBundle</code>. However, this is often not
|
||||
* desirable in an application server environment, where the system Locale
|
||||
* is not relevant to the application at all: Set this flag to "false"
|
||||
* in such a scenario.
|
||||
*/
|
||||
public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {
|
||||
this.fallbackToSystemLocale = fallbackToSystemLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of seconds to cache loaded properties files.
|
||||
* <ul>
|
||||
* <li>Default is "-1", indicating to cache forever (just like
|
||||
* <code>java.util.ResourceBundle</code>).
|
||||
* <li>A positive number will cache loaded properties files for the given
|
||||
* number of seconds. This is essentially the interval between refresh checks.
|
||||
* Note that a refresh attempt will first check the last-modified timestamp
|
||||
* of the file before actually reloading it; so if files don't change, this
|
||||
* interval can be set rather low, as refresh attempts will not actually reload.
|
||||
* <li>A value of "0" will check the last-modified timestamp of the file on
|
||||
* every message access. <b>Do not use this in a production environment!</b>
|
||||
* </ul>
|
||||
*/
|
||||
public void setCacheSeconds(int cacheSeconds) {
|
||||
this.cacheMillis = (cacheSeconds * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PropertiesPersister to use for parsing properties files.
|
||||
* <p>The default is a DefaultPropertiesPersister.
|
||||
* @see org.springframework.util.DefaultPropertiesPersister
|
||||
*/
|
||||
public void setPropertiesPersister(PropertiesPersister propertiesPersister) {
|
||||
this.propertiesPersister =
|
||||
(propertiesPersister != null ? propertiesPersister : new DefaultPropertiesPersister());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ResourceLoader to use for loading bundle properties files.
|
||||
* <p>The default is a DefaultResourceLoader. Will get overridden by the
|
||||
* ApplicationContext if running in a context, as it implements the
|
||||
* ResourceLoaderAware interface. Can be manually overridden when
|
||||
* running outside of an ApplicationContext.
|
||||
* @see org.springframework.core.io.DefaultResourceLoader
|
||||
* @see org.springframework.context.ResourceLoaderAware
|
||||
*/
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves the given message code as key in the retrieved bundle files,
|
||||
* returning the value found in the bundle as-is (without MessageFormat parsing).
|
||||
*/
|
||||
protected String resolveCodeWithoutArguments(String code, Locale locale) {
|
||||
if (this.cacheMillis < 0) {
|
||||
PropertiesHolder propHolder = getMergedProperties(locale);
|
||||
String result = propHolder.getProperty(code);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < this.basenames.length; i++) {
|
||||
List filenames = calculateAllFilenames(this.basenames[i], locale);
|
||||
for (int j = 0; j < filenames.size(); j++) {
|
||||
String filename = (String) filenames.get(j);
|
||||
PropertiesHolder propHolder = getProperties(filename);
|
||||
String result = propHolder.getProperty(code);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given message code as key in the retrieved bundle files,
|
||||
* using a cached MessageFormat instance per message code.
|
||||
*/
|
||||
protected MessageFormat resolveCode(String code, Locale locale) {
|
||||
if (this.cacheMillis < 0) {
|
||||
PropertiesHolder propHolder = getMergedProperties(locale);
|
||||
MessageFormat result = propHolder.getMessageFormat(code, locale);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < this.basenames.length; i++) {
|
||||
List filenames = calculateAllFilenames(this.basenames[i], locale);
|
||||
for (int j = 0; j < filenames.size(); j++) {
|
||||
String filename = (String) filenames.get(j);
|
||||
PropertiesHolder propHolder = getProperties(filename);
|
||||
MessageFormat result = propHolder.getMessageFormat(code, locale);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a PropertiesHolder that contains the actually visible properties
|
||||
* for a Locale, after merging all specified resource bundles.
|
||||
* Either fetches the holder from the cache or freshly loads it.
|
||||
* <p>Only used when caching resource bundle contents forever, i.e.
|
||||
* with cacheSeconds < 0. Therefore, merged properties are always
|
||||
* cached forever.
|
||||
*/
|
||||
protected PropertiesHolder getMergedProperties(Locale locale) {
|
||||
synchronized (this.cachedMergedProperties) {
|
||||
PropertiesHolder mergedHolder = (PropertiesHolder) this.cachedMergedProperties.get(locale);
|
||||
if (mergedHolder != null) {
|
||||
return mergedHolder;
|
||||
}
|
||||
Properties mergedProps = new Properties();
|
||||
mergedHolder = new PropertiesHolder(mergedProps, -1);
|
||||
for (int i = this.basenames.length - 1; i >= 0; i--) {
|
||||
List filenames = calculateAllFilenames(this.basenames[i], locale);
|
||||
for (int j = filenames.size() - 1; j >= 0; j--) {
|
||||
String filename = (String) filenames.get(j);
|
||||
PropertiesHolder propHolder = getProperties(filename);
|
||||
if (propHolder.getProperties() != null) {
|
||||
mergedProps.putAll(propHolder.getProperties());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.cachedMergedProperties.put(locale, mergedHolder);
|
||||
return mergedHolder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate all filenames for the given bundle basename and Locale.
|
||||
* Will calculate filenames for the given Locale, the system Locale
|
||||
* (if applicable), and the default file.
|
||||
* @param basename the basename of the bundle
|
||||
* @param locale the locale
|
||||
* @return the List of filenames to check
|
||||
* @see #setFallbackToSystemLocale
|
||||
* @see #calculateFilenamesForLocale
|
||||
*/
|
||||
protected List calculateAllFilenames(String basename, Locale locale) {
|
||||
synchronized (this.cachedFilenames) {
|
||||
Map localeMap = (Map) this.cachedFilenames.get(basename);
|
||||
if (localeMap != null) {
|
||||
List filenames = (List) localeMap.get(locale);
|
||||
if (filenames != null) {
|
||||
return filenames;
|
||||
}
|
||||
}
|
||||
List filenames = new ArrayList(7);
|
||||
filenames.addAll(calculateFilenamesForLocale(basename, locale));
|
||||
if (this.fallbackToSystemLocale && !locale.equals(Locale.getDefault())) {
|
||||
List fallbackFilenames = calculateFilenamesForLocale(basename, Locale.getDefault());
|
||||
for (Iterator it = fallbackFilenames.iterator(); it.hasNext();) {
|
||||
String fallbackFilename = (String) it.next();
|
||||
if (!filenames.contains(fallbackFilename)) {
|
||||
// Entry for fallback locale that isn't already in filenames list.
|
||||
filenames.add(fallbackFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
filenames.add(basename);
|
||||
if (localeMap != null) {
|
||||
localeMap.put(locale, filenames);
|
||||
}
|
||||
else {
|
||||
localeMap = new HashMap();
|
||||
localeMap.put(locale, filenames);
|
||||
this.cachedFilenames.put(basename, localeMap);
|
||||
}
|
||||
return filenames;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the filenames for the given bundle basename and Locale,
|
||||
* appending language code, country code, and variant code.
|
||||
* E.g.: basename "messages", Locale "de_AT_oo" -> "messages_de_AT_OO",
|
||||
* "messages_de_AT", "messages_de".
|
||||
* @param basename the basename of the bundle
|
||||
* @param locale the locale
|
||||
* @return the List of filenames to check
|
||||
*/
|
||||
protected List calculateFilenamesForLocale(String basename, Locale locale) {
|
||||
List result = new ArrayList(3);
|
||||
String language = locale.getLanguage();
|
||||
String country = locale.getCountry();
|
||||
String variant = locale.getVariant();
|
||||
StringBuffer temp = new StringBuffer(basename);
|
||||
|
||||
if (language.length() > 0) {
|
||||
temp.append('_').append(language);
|
||||
result.add(0, temp.toString());
|
||||
}
|
||||
|
||||
if (country.length() > 0) {
|
||||
temp.append('_').append(country);
|
||||
result.add(0, temp.toString());
|
||||
}
|
||||
|
||||
if (variant.length() > 0) {
|
||||
temp.append('_').append(variant);
|
||||
result.add(0, temp.toString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a PropertiesHolder for the given filename, either from the
|
||||
* cache or freshly loaded.
|
||||
* @param filename the bundle filename (basename + Locale)
|
||||
* @return the current PropertiesHolder for the bundle
|
||||
*/
|
||||
protected PropertiesHolder getProperties(String filename) {
|
||||
synchronized (this.cachedProperties) {
|
||||
PropertiesHolder propHolder = (PropertiesHolder) this.cachedProperties.get(filename);
|
||||
if (propHolder != null &&
|
||||
(propHolder.getRefreshTimestamp() < 0 ||
|
||||
propHolder.getRefreshTimestamp() > System.currentTimeMillis() - this.cacheMillis)) {
|
||||
// up to date
|
||||
return propHolder;
|
||||
}
|
||||
return refreshProperties(filename, propHolder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the PropertiesHolder for the given bundle filename.
|
||||
* The holder can be <code>null</code> if not cached before, or a timed-out cache entry
|
||||
* (potentially getting re-validated against the current last-modified timestamp).
|
||||
* @param filename the bundle filename (basename + Locale)
|
||||
* @param propHolder the current PropertiesHolder for the bundle
|
||||
*/
|
||||
protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) {
|
||||
long refreshTimestamp = (this.cacheMillis < 0) ? -1 : System.currentTimeMillis();
|
||||
|
||||
Resource resource = this.resourceLoader.getResource(filename + PROPERTIES_SUFFIX);
|
||||
if (!resource.exists()) {
|
||||
resource = this.resourceLoader.getResource(filename + XML_SUFFIX);
|
||||
}
|
||||
|
||||
if (resource.exists()) {
|
||||
long fileTimestamp = -1;
|
||||
if (this.cacheMillis >= 0) {
|
||||
// Last-modified timestamp of file will just be read if caching with timeout.
|
||||
try {
|
||||
fileTimestamp = resource.lastModified();
|
||||
if (propHolder != null && propHolder.getFileTimestamp() == fileTimestamp) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Re-caching properties for filename [" + filename + "] - file hasn't been modified");
|
||||
}
|
||||
propHolder.setRefreshTimestamp(refreshTimestamp);
|
||||
return propHolder;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// Probably a class path resource: cache it forever.
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
resource + " could not be resolved in the file system - assuming that is hasn't changed", ex);
|
||||
}
|
||||
fileTimestamp = -1;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Properties props = loadProperties(resource, filename);
|
||||
propHolder = new PropertiesHolder(props, fileTimestamp);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not parse properties file [" + resource.getFilename() + "]", ex);
|
||||
}
|
||||
// Empty holder representing "not valid".
|
||||
propHolder = new PropertiesHolder();
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// Resource does not exist.
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No properties file found for [" + filename + "] - neither plain properties nor XML");
|
||||
}
|
||||
// Empty holder representing "not found".
|
||||
propHolder = new PropertiesHolder();
|
||||
}
|
||||
|
||||
propHolder.setRefreshTimestamp(refreshTimestamp);
|
||||
this.cachedProperties.put(filename, propHolder);
|
||||
return propHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the properties from the given resource.
|
||||
* @param resource the resource to load from
|
||||
* @param filename the original bundle filename (basename + Locale)
|
||||
* @return the populated Properties instance
|
||||
* @throws IOException if properties loading failed
|
||||
*/
|
||||
protected Properties loadProperties(Resource resource, String filename) throws IOException {
|
||||
InputStream is = resource.getInputStream();
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
if (resource.getFilename().endsWith(XML_SUFFIX)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading properties [" + resource.getFilename() + "]");
|
||||
}
|
||||
this.propertiesPersister.loadFromXml(props, is);
|
||||
}
|
||||
else {
|
||||
String encoding = null;
|
||||
if (this.fileEncodings != null) {
|
||||
encoding = this.fileEncodings.getProperty(filename);
|
||||
}
|
||||
if (encoding == null) {
|
||||
encoding = this.defaultEncoding;
|
||||
}
|
||||
if (encoding != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading properties [" + resource.getFilename() + "] with encoding '" + encoding + "'");
|
||||
}
|
||||
this.propertiesPersister.load(props, new InputStreamReader(is, encoding));
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loading properties [" + resource.getFilename() + "]");
|
||||
}
|
||||
this.propertiesPersister.load(props, is);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear the resource bundle cache.
|
||||
* Subsequent resolve calls will lead to reloading of the properties files.
|
||||
*/
|
||||
public void clearCache() {
|
||||
logger.debug("Clearing entire resource bundle cache");
|
||||
synchronized (this.cachedProperties) {
|
||||
this.cachedProperties.clear();
|
||||
}
|
||||
synchronized (this.cachedMergedProperties) {
|
||||
this.cachedMergedProperties.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the resource bundle caches of this MessageSource and all its ancestors.
|
||||
* @see #clearCache
|
||||
*/
|
||||
public void clearCacheIncludingAncestors() {
|
||||
clearCache();
|
||||
if (getParentMessageSource() instanceof ReloadableResourceBundleMessageSource) {
|
||||
((ReloadableResourceBundleMessageSource) getParentMessageSource()).clearCacheIncludingAncestors();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return getClass().getName() + ": basenames=[" + StringUtils.arrayToCommaDelimitedString(this.basenames) + "]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PropertiesHolder for caching.
|
||||
* Stores the last-modified timestamp of the source file for efficient
|
||||
* change detection, and the timestamp of the last refresh attempt
|
||||
* (updated every time the cache entry gets re-validated).
|
||||
*/
|
||||
protected class PropertiesHolder {
|
||||
|
||||
private Properties properties;
|
||||
|
||||
private long fileTimestamp = -1;
|
||||
|
||||
private long refreshTimestamp = -1;
|
||||
|
||||
/** Cache to hold already generated MessageFormats per message code */
|
||||
private final Map cachedMessageFormats = new HashMap();
|
||||
|
||||
public PropertiesHolder(Properties properties, long fileTimestamp) {
|
||||
this.properties = properties;
|
||||
this.fileTimestamp = fileTimestamp;
|
||||
}
|
||||
|
||||
public PropertiesHolder() {
|
||||
}
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public long getFileTimestamp() {
|
||||
return fileTimestamp;
|
||||
}
|
||||
|
||||
public void setRefreshTimestamp(long refreshTimestamp) {
|
||||
this.refreshTimestamp = refreshTimestamp;
|
||||
}
|
||||
|
||||
public long getRefreshTimestamp() {
|
||||
return refreshTimestamp;
|
||||
}
|
||||
|
||||
public String getProperty(String code) {
|
||||
if (this.properties == null) {
|
||||
return null;
|
||||
}
|
||||
return this.properties.getProperty(code);
|
||||
}
|
||||
|
||||
public MessageFormat getMessageFormat(String code, Locale locale) {
|
||||
if (this.properties == null) {
|
||||
return null;
|
||||
}
|
||||
synchronized (this.cachedMessageFormats) {
|
||||
Map localeMap = (Map) this.cachedMessageFormats.get(code);
|
||||
if (localeMap != null) {
|
||||
MessageFormat result = (MessageFormat) localeMap.get(locale);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
String msg = this.properties.getProperty(code);
|
||||
if (msg != null) {
|
||||
if (localeMap == null) {
|
||||
localeMap = new HashMap();
|
||||
this.cachedMessageFormats.put(code, localeMap);
|
||||
}
|
||||
MessageFormat result = createMessageFormat(msg, locale);
|
||||
localeMap.put(locale, result);
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.support;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.context.MessageSource} implementation that
|
||||
* accesses resource bundles using specified basenames. This class relies
|
||||
* on the underlying JDK's {@link java.util.ResourceBundle} implementation,
|
||||
* in combination with the JDK's standard message parsing provided by
|
||||
* {@link java.text.MessageFormat}.
|
||||
*
|
||||
* <p>This MessageSource caches both the accessed ResourceBundle instances and
|
||||
* the generated MessageFormats for each message. It also implements rendering of
|
||||
* no-arg messages without MessageFormat, as supported by the AbstractMessageSource
|
||||
* base class. The caching provided by this MessageSource is significantly faster
|
||||
* than the built-in caching of the <code>java.util.ResourceBundle</code> class.
|
||||
*
|
||||
* <p>Unfortunately, <code>java.util.ResourceBundle</code> caches loaded bundles
|
||||
* forever: Reloading a bundle during VM execution is <i>not</i> possible.
|
||||
* As this MessageSource relies on ResourceBundle, it faces the same limitation.
|
||||
* Consider {@link ReloadableResourceBundleMessageSource} for an alternative
|
||||
* that is capable of refreshing the underlying bundle files.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #setBasenames
|
||||
* @see ReloadableResourceBundleMessageSource
|
||||
* @see java.util.ResourceBundle
|
||||
* @see java.text.MessageFormat
|
||||
*/
|
||||
public class ResourceBundleMessageSource extends AbstractMessageSource implements BeanClassLoaderAware {
|
||||
|
||||
private String[] basenames = new String[0];
|
||||
|
||||
private ClassLoader bundleClassLoader;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/**
|
||||
* Cache to hold loaded ResourceBundles.
|
||||
* This Map is keyed with the bundle basename, which holds a Map that is
|
||||
* keyed with the Locale and in turn holds the ResourceBundle instances.
|
||||
* This allows for very efficient hash lookups, significantly faster
|
||||
* than the ResourceBundle class's own cache.
|
||||
*/
|
||||
private final Map cachedResourceBundles = new HashMap();
|
||||
|
||||
/**
|
||||
* Cache to hold already generated MessageFormats.
|
||||
* This Map is keyed with the ResourceBundle, which holds a Map that is
|
||||
* keyed with the message code, which in turn holds a Map that is keyed
|
||||
* with the Locale and holds the MessageFormat values. This allows for
|
||||
* very efficient hash lookups without concatenated keys.
|
||||
* @see #getMessageFormat
|
||||
*/
|
||||
private final Map cachedBundleMessageFormats = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Set a single basename, following {@link java.util.ResourceBundle} conventions:
|
||||
* essentially, a fully-qualified classpath location. If it doesn't contain a
|
||||
* package qualifier (such as <code>org.mypackage</code>), it will be resolved
|
||||
* from the classpath root.
|
||||
* <p>Messages will normally be held in the "/lib" or "/classes" directory of
|
||||
* a web application's WAR structure. They can also be held in jar files on
|
||||
* the class path.
|
||||
* <p>Note that ResourceBundle names are effectively classpath locations: As a
|
||||
* consequence, the JDK's standard ResourceBundle treats dots as package separators.
|
||||
* This means that "test.theme" is effectively equivalent to "test/theme",
|
||||
* just like it is for programmatic <code>java.util.ResourceBundle</code> usage.
|
||||
* @see #setBasenames
|
||||
* @see java.util.ResourceBundle#getBundle(String)
|
||||
*/
|
||||
public void setBasename(String basename) {
|
||||
setBasenames(new String[] {basename});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an array of basenames, each following {@link java.util.ResourceBundle}
|
||||
* conventions: essentially, a fully-qualified classpath location. If it
|
||||
* doesn't contain a package qualifier (such as <code>org.mypackage</code>),
|
||||
* it will be resolved from the classpath root.
|
||||
* <p>The associated resource bundles will be checked sequentially
|
||||
* when resolving a message code. Note that message definitions in a
|
||||
* <i>previous</i> resource bundle will override ones in a later bundle,
|
||||
* due to the sequential lookup.
|
||||
* <p>Note that ResourceBundle names are effectively classpath locations: As a
|
||||
* consequence, the JDK's standard ResourceBundle treats dots as package separators.
|
||||
* This means that "test.theme" is effectively equivalent to "test/theme",
|
||||
* just like it is for programmatic <code>java.util.ResourceBundle</code> usage.
|
||||
* @see #setBasename
|
||||
* @see java.util.ResourceBundle#getBundle(String)
|
||||
*/
|
||||
public void setBasenames(String[] basenames) {
|
||||
if (basenames != null) {
|
||||
this.basenames = new String[basenames.length];
|
||||
for (int i = 0; i < basenames.length; i++) {
|
||||
String basename = basenames[i];
|
||||
Assert.hasText(basename, "Basename must not be empty");
|
||||
this.basenames[i] = basename.trim();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.basenames = new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ClassLoader to load resource bundles with.
|
||||
* <p>Default is the containing BeanFactory's
|
||||
* {@link org.springframework.beans.factory.BeanClassLoaderAware bean ClassLoader},
|
||||
* or the default ClassLoader determined by
|
||||
* {@link org.springframework.util.ClassUtils#getDefaultClassLoader()}
|
||||
* if not running within a BeanFactory.
|
||||
*/
|
||||
public void setBundleClassLoader(ClassLoader classLoader) {
|
||||
this.bundleClassLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ClassLoader to load resource bundles with.
|
||||
* <p>Default is the containing BeanFactory's bean ClassLoader.
|
||||
* @see #setBundleClassLoader
|
||||
*/
|
||||
protected ClassLoader getBundleClassLoader() {
|
||||
return (this.bundleClassLoader != null ? this.bundleClassLoader : this.beanClassLoader);
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves the given message code as key in the registered resource bundles,
|
||||
* returning the value found in the bundle as-is (without MessageFormat parsing).
|
||||
*/
|
||||
protected String resolveCodeWithoutArguments(String code, Locale locale) {
|
||||
String result = null;
|
||||
for (int i = 0; result == null && i < this.basenames.length; i++) {
|
||||
ResourceBundle bundle = getResourceBundle(this.basenames[i], locale);
|
||||
if (bundle != null) {
|
||||
result = getStringOrNull(bundle, code);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given message code as key in the registered resource bundles,
|
||||
* using a cached MessageFormat instance per message code.
|
||||
*/
|
||||
protected MessageFormat resolveCode(String code, Locale locale) {
|
||||
MessageFormat messageFormat = null;
|
||||
for (int i = 0; messageFormat == null && i < this.basenames.length; i++) {
|
||||
ResourceBundle bundle = getResourceBundle(this.basenames[i], locale);
|
||||
if (bundle != null) {
|
||||
messageFormat = getMessageFormat(bundle, code, locale);
|
||||
}
|
||||
}
|
||||
return messageFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a ResourceBundle for the given basename and code,
|
||||
* fetching already generated MessageFormats from the cache.
|
||||
* @param basename the basename of the ResourceBundle
|
||||
* @param locale the Locale to find the ResourceBundle for
|
||||
* @return the resulting ResourceBundle, or <code>null</code> if none
|
||||
* found for the given basename and Locale
|
||||
*/
|
||||
protected ResourceBundle getResourceBundle(String basename, Locale locale) {
|
||||
synchronized (this.cachedResourceBundles) {
|
||||
Map localeMap = (Map) this.cachedResourceBundles.get(basename);
|
||||
if (localeMap != null) {
|
||||
ResourceBundle bundle = (ResourceBundle) localeMap.get(locale);
|
||||
if (bundle != null) {
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ResourceBundle bundle = doGetBundle(basename, locale);
|
||||
if (localeMap == null) {
|
||||
localeMap = new HashMap();
|
||||
this.cachedResourceBundles.put(basename, localeMap);
|
||||
}
|
||||
localeMap.put(locale, bundle);
|
||||
return bundle;
|
||||
}
|
||||
catch (MissingResourceException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("ResourceBundle [" + basename + "] not found for MessageSource: " + ex.getMessage());
|
||||
}
|
||||
// Assume bundle not found
|
||||
// -> do NOT throw the exception to allow for checking parent message source.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the resource bundle for the given basename and Locale.
|
||||
* @param basename the basename to look for
|
||||
* @param locale the Locale to look for
|
||||
* @return the corresponding ResourceBundle
|
||||
* @throws MissingResourceException if no matching bundle could be found
|
||||
* @see java.util.ResourceBundle#getBundle(String, java.util.Locale, ClassLoader)
|
||||
* @see #getBundleClassLoader()
|
||||
*/
|
||||
protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {
|
||||
return ResourceBundle.getBundle(basename, locale, getBundleClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a MessageFormat for the given bundle and code,
|
||||
* fetching already generated MessageFormats from the cache.
|
||||
* @param bundle the ResourceBundle to work on
|
||||
* @param code the message code to retrieve
|
||||
* @param locale the Locale to use to build the MessageFormat
|
||||
* @return the resulting MessageFormat, or <code>null</code> if no message
|
||||
* defined for the given code
|
||||
* @throws MissingResourceException if thrown by the ResourceBundle
|
||||
*/
|
||||
protected MessageFormat getMessageFormat(ResourceBundle bundle, String code, Locale locale)
|
||||
throws MissingResourceException {
|
||||
|
||||
synchronized (this.cachedBundleMessageFormats) {
|
||||
Map codeMap = (Map) this.cachedBundleMessageFormats.get(bundle);
|
||||
Map localeMap = null;
|
||||
if (codeMap != null) {
|
||||
localeMap = (Map) codeMap.get(code);
|
||||
if (localeMap != null) {
|
||||
MessageFormat result = (MessageFormat) localeMap.get(locale);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String msg = getStringOrNull(bundle, code);
|
||||
if (msg != null) {
|
||||
if (codeMap == null) {
|
||||
codeMap = new HashMap();
|
||||
this.cachedBundleMessageFormats.put(bundle, codeMap);
|
||||
}
|
||||
if (localeMap == null) {
|
||||
localeMap = new HashMap();
|
||||
codeMap.put(code, localeMap);
|
||||
}
|
||||
MessageFormat result = createMessageFormat(msg, locale);
|
||||
localeMap.put(locale, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getStringOrNull(ResourceBundle bundle, String key) {
|
||||
try {
|
||||
return bundle.getString(key);
|
||||
}
|
||||
catch (MissingResourceException ex) {
|
||||
// Assume key not found
|
||||
// -> do NOT throw the exception to allow for checking parent message source.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the configuration of this MessageSource.
|
||||
*/
|
||||
public String toString() {
|
||||
return getClass().getName() + ": basenames=[" +
|
||||
StringUtils.arrayToCommaDelimitedString(this.basenames) + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* FactoryBean that creates a Map with String keys and Resource values from
|
||||
* properties, interpreting passed-in String values as resource locations.
|
||||
*
|
||||
* <p>Extends PropertiesFactoryBean to inherit the capability of defining
|
||||
* local properties and loading from properties files.
|
||||
*
|
||||
* <p>Implements the ResourceLoaderAware interface to automatically use
|
||||
* the context ResourceLoader if running in an ApplicationContext.
|
||||
* Uses DefaultResourceLoader else.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Keith Donald
|
||||
* @since 1.0.2
|
||||
* @see org.springframework.core.io.DefaultResourceLoader
|
||||
*/
|
||||
public class ResourceMapFactoryBean extends PropertiesFactoryBean implements ResourceLoaderAware {
|
||||
|
||||
private String resourceBasePath = "";
|
||||
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
|
||||
/**
|
||||
* Set a base path to prepend to each resource location value
|
||||
* in the properties file.
|
||||
* <p>E.g.: resourceBasePath="/images", value="/test.gif"
|
||||
* -> location="/images/test.gif"
|
||||
*/
|
||||
public void setResourceBasePath(String resourceBasePath) {
|
||||
this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : "");
|
||||
}
|
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
|
||||
}
|
||||
|
||||
|
||||
public Class getObjectType() {
|
||||
return Map.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Map instance, populated with keys and Resource values.
|
||||
*/
|
||||
protected Object createInstance() throws IOException {
|
||||
Map resourceMap = new HashMap();
|
||||
Properties props = mergeProperties();
|
||||
for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
|
||||
String key = (String) en.nextElement();
|
||||
String location = props.getProperty(key);
|
||||
resourceMap.put(key, getResource(location));
|
||||
}
|
||||
return resourceMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the Resource handle for the given location,
|
||||
* prepeding the resource base path.
|
||||
* @param location the resource location
|
||||
* @return the Resource handle
|
||||
* @see org.springframework.core.io.ResourceLoader#getResource(String)
|
||||
*/
|
||||
protected Resource getResource(String location) {
|
||||
return this.resourceLoader.getResource(this.resourceBasePath + location);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.context.ApplicationContext} implementation
|
||||
* which supports programmatic registration of beans and messages,
|
||||
* rather than reading bean definitions from external configuration sources.
|
||||
* Mainly useful for testing.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #registerSingleton
|
||||
* @see #registerPrototype
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public class StaticApplicationContext extends GenericApplicationContext {
|
||||
|
||||
private final StaticMessageSource staticMessageSource;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new StaticApplicationContext.
|
||||
* @see #registerSingleton
|
||||
* @see #registerPrototype
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public StaticApplicationContext() throws BeansException {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new StaticApplicationContext with the given parent.
|
||||
* @see #registerSingleton
|
||||
* @see #registerPrototype
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public StaticApplicationContext(ApplicationContext parent) throws BeansException {
|
||||
super(parent);
|
||||
|
||||
// Initialize and register a StaticMessageSource.
|
||||
this.staticMessageSource = new StaticMessageSource();
|
||||
getBeanFactory().registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.staticMessageSource);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the internal StaticMessageSource used by this context.
|
||||
* Can be used to register messages on it.
|
||||
* @see #addMessage
|
||||
*/
|
||||
public final StaticMessageSource getStaticMessageSource() {
|
||||
return this.staticMessageSource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a singleton bean with the underlying bean factory.
|
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly.
|
||||
* @see #getDefaultListableBeanFactory
|
||||
*/
|
||||
public void registerSingleton(String name, Class clazz) throws BeansException {
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
bd.setBeanClass(clazz);
|
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a singleton bean with the underlying bean factory.
|
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly.
|
||||
* @see #getDefaultListableBeanFactory
|
||||
*/
|
||||
public void registerSingleton(String name, Class clazz, MutablePropertyValues pvs) throws BeansException {
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
bd.setBeanClass(clazz);
|
||||
bd.setPropertyValues(pvs);
|
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a prototype bean with the underlying bean factory.
|
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly.
|
||||
* @see #getDefaultListableBeanFactory
|
||||
*/
|
||||
public void registerPrototype(String name, Class clazz) throws BeansException {
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
bd.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd.setBeanClass(clazz);
|
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a prototype bean with the underlying bean factory.
|
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly.
|
||||
* @see #getDefaultListableBeanFactory
|
||||
*/
|
||||
public void registerPrototype(String name, Class clazz, MutablePropertyValues pvs) throws BeansException {
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
bd.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd.setBeanClass(clazz);
|
||||
bd.setPropertyValues(pvs);
|
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given message with the given code.
|
||||
* @param code lookup code
|
||||
* @param locale locale message should be found within
|
||||
* @param defaultMessage message associated with this lookup code
|
||||
* @see #getStaticMessageSource
|
||||
*/
|
||||
public void addMessage(String code, Locale locale, String defaultMessage) {
|
||||
getStaticMessageSource().addMessage(code, locale, defaultMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.springframework.context.support;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link org.springframework.context.MessageSource}
|
||||
* which allows messages to be registered programmatically.
|
||||
* This MessageSource supports basic internationalization.
|
||||
*
|
||||
* <p>Intended for testing rather than for use in production systems.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class StaticMessageSource extends AbstractMessageSource {
|
||||
|
||||
/** Map from 'code + locale' keys to message Strings */
|
||||
private final Map messages = new HashMap();
|
||||
|
||||
|
||||
protected MessageFormat resolveCode(String code, Locale locale) {
|
||||
return (MessageFormat) this.messages.get(code + "_" + locale.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given message with the given code.
|
||||
* @param code the lookup code
|
||||
* @param locale the locale that the message should be found within
|
||||
* @param msg the message associated with this lookup code
|
||||
*/
|
||||
public void addMessage(String code, Locale locale, String msg) {
|
||||
Assert.notNull(code, "Code must not be null");
|
||||
Assert.notNull(locale, "Locale must not be null");
|
||||
Assert.notNull(msg, "Message must not be null");
|
||||
this.messages.put(code + "_" + locale.toString(), createMessageFormat(msg, locale));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added message [" + msg + "] for code [" + code + "] and Locale [" + locale + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given message values with the given keys as codes.
|
||||
* @param messages the messages to register, with messages codes
|
||||
* as keys and message texts as values
|
||||
* @param locale the locale that the messages should be found within
|
||||
*/
|
||||
public void addMessages(Map messages, Locale locale) {
|
||||
Assert.notNull(messages, "Messages Map must not be null");
|
||||
for (Iterator it = messages.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
addMessage(entry.getKey().toString(), locale, entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return getClass().getName() + ": " + this.messages;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Classes supporting the org.springframework.context package,
|
||||
such as abstract base classes for ApplicationContext
|
||||
implementations and a MessageSource implementation.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.springframework.context.weaving;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
|
||||
/**
|
||||
* Post-processor that registers AspectJ's
|
||||
* {@link org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter}
|
||||
* with the Spring application context's default
|
||||
* {@link org.springframework.instrument.classloading.LoadTimeWeaver}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.5
|
||||
*/
|
||||
public class AspectJWeavingEnabler
|
||||
implements BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, Ordered {
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private LoadTimeWeaver loadTimeWeaver;
|
||||
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
|
||||
this.loadTimeWeaver = loadTimeWeaver;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
LoadTimeWeaver weaverToUse = this.loadTimeWeaver;
|
||||
if (weaverToUse == null && InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
|
||||
weaverToUse = new InstrumentationLoadTimeWeaver(this.beanClassLoader);
|
||||
}
|
||||
weaverToUse.addTransformer(new AspectJClassBypassingClassFileTransformer(
|
||||
new ClassPreProcessorAgentAdapter()));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decorator to suppress processing AspectJ classes, hence avoiding potential LinkageErrors.
|
||||
* OC4J and Tomcat (in Glassfish) definitely need such bypassing of AspectJ classes.
|
||||
*/
|
||||
private static class AspectJClassBypassingClassFileTransformer implements ClassFileTransformer {
|
||||
|
||||
private final ClassFileTransformer delegate;
|
||||
|
||||
public AspectJClassBypassingClassFileTransformer(ClassFileTransformer delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||
|
||||
if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) {
|
||||
return classfileBuffer;
|
||||
}
|
||||
return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.springframework.context.weaving;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.instrument.InstrumentationSavingAgent;
|
||||
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.oc4j.OC4JLoadTimeWeaver;
|
||||
import org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver;
|
||||
|
||||
/**
|
||||
* Default {@link LoadTimeWeaver} bean for use in an application context,
|
||||
* decorating an automatically detected internal <code>LoadTimeWeaver</code>.
|
||||
*
|
||||
* <p>Typically registered for the default bean name
|
||||
* "<code>loadTimeWeaver</code>"; the most convenient way to achieve this is
|
||||
* Spring's <code><context:load-time-weaver></code> XML tag.
|
||||
*
|
||||
* <p>This class implements a runtime environment check for obtaining the
|
||||
* appropriate weaver implementation: As of Spring 2.5, it detects Sun's
|
||||
* GlassFish, Oracle's OC4J, BEA's WebLogic 10,
|
||||
* {@link InstrumentationSavingAgent Spring's VM agent} and any
|
||||
* {@link ClassLoader} supported by Spring's {@link ReflectiveLoadTimeWeaver}
|
||||
* (for example the
|
||||
* {@link org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader}).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.5
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
|
||||
*/
|
||||
public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLoaderAware, DisposableBean {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private LoadTimeWeaver loadTimeWeaver;
|
||||
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);
|
||||
if (serverSpecificLoadTimeWeaver != null) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Determined server-specific load-time weaver: " +
|
||||
serverSpecificLoadTimeWeaver.getClass().getName());
|
||||
}
|
||||
this.loadTimeWeaver = serverSpecificLoadTimeWeaver;
|
||||
}
|
||||
else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
|
||||
logger.info("Found Spring's JVM agent for instrumentation");
|
||||
this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
|
||||
logger.info("Using a reflective load-time weaver for class loader: " +
|
||||
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver " +
|
||||
"or start your Java virtual machine with Spring's agent: -javaagent:spring-agent.jar");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method never fails, allowing to try other possible ways to use an
|
||||
* server-agnostic weaver. This non-failure logic is required since
|
||||
* determining a load-time weaver based on the ClassLoader name alone may
|
||||
* legitimately fail due to other mismatches. Specific case in point: the
|
||||
* use of WebLogicLoadTimeWeaver works for WLS 10 but fails due to the lack
|
||||
* of a specific method (addInstanceClassPreProcessor) for any earlier
|
||||
* versions even though the ClassLoader name is the same.
|
||||
*/
|
||||
protected LoadTimeWeaver createServerSpecificLoadTimeWeaver(ClassLoader classLoader) {
|
||||
try {
|
||||
if (classLoader.getClass().getName().startsWith("weblogic")) {
|
||||
return new WebLogicLoadTimeWeaver(classLoader);
|
||||
}
|
||||
else if (classLoader.getClass().getName().startsWith("oracle")) {
|
||||
return new OC4JLoadTimeWeaver(classLoader);
|
||||
}
|
||||
else if (classLoader.getClass().getName().startsWith("com.sun.enterprise")) {
|
||||
return new GlassFishLoadTimeWeaver(classLoader);
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (this.loadTimeWeaver instanceof InstrumentationLoadTimeWeaver) {
|
||||
logger.info("Removing all registered transformers for class loader: " +
|
||||
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
|
||||
((InstrumentationLoadTimeWeaver) this.loadTimeWeaver).removeTransformers();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
this.loadTimeWeaver.addTransformer(transformer);
|
||||
}
|
||||
|
||||
public ClassLoader getInstrumentableClassLoader() {
|
||||
return this.loadTimeWeaver.getInstrumentableClassLoader();
|
||||
}
|
||||
|
||||
public ClassLoader getThrowawayClassLoader() {
|
||||
return this.loadTimeWeaver.getThrowawayClassLoader();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.weaving;
|
||||
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any object that wishes to be notified
|
||||
* of the application context's default {@link LoadTimeWeaver}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
|
||||
*/
|
||||
public interface LoadTimeWeaverAware {
|
||||
|
||||
/**
|
||||
* Set the {@link LoadTimeWeaver} of this object's containing
|
||||
* {@link org.springframework.context.ApplicationContext ApplicationContext}.
|
||||
* <p>Invoked after the population of normal bean properties but before an
|
||||
* initialization callback like
|
||||
* {@link org.springframework.beans.factory.InitializingBean InitializingBean's}
|
||||
* {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet() afterPropertiesSet()}
|
||||
* or a custom init-method. Invoked after
|
||||
* {@link org.springframework.context.ApplicationContextAware ApplicationContextAware's}
|
||||
* {@link org.springframework.context.ApplicationContextAware#setApplicationContext setApplicationContext(..)}.
|
||||
* <p><b>NOTE:</b> This method will only be called if there actually is a
|
||||
* <code>LoadTimeWeaver</code> available in the application context. If
|
||||
* there is none, the method will simply not get invoked, assuming that the
|
||||
* implementing object is able to activate its weaving dependency accordingly.
|
||||
* @param loadTimeWeaver the <code>LoadTimeWeaver</code> instance (never <code>null</code>)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext
|
||||
*/
|
||||
void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.context.weaving;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
|
||||
* implementation that passes the context's default {@link LoadTimeWeaver}
|
||||
* to beans that implement the {@link LoadTimeWeaverAware} interface.
|
||||
*
|
||||
* <p>{@link org.springframework.context.ApplicationContext Application contexts}
|
||||
* will automatically register this with their underlying
|
||||
* {@link BeanFactory bean factory}, provided that a default
|
||||
* <code>LoadTimeWeaver</code> is actually available.
|
||||
*
|
||||
* <p>Applications should not use this class directly.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see LoadTimeWeaverAware
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
|
||||
*/
|
||||
public class LoadTimeWeaverAwareProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
|
||||
private LoadTimeWeaver loadTimeWeaver;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new <code>LoadTimeWeaverAwareProcessor</code> that will
|
||||
* auto-retrieve the {@link LoadTimeWeaver} from the containing
|
||||
* {@link BeanFactory}, expecting a bean named
|
||||
* {@link ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME "loadTimeWeaver"}.
|
||||
*/
|
||||
public LoadTimeWeaverAwareProcessor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>LoadTimeWeaverAwareProcessor</code> for the given
|
||||
* {@link LoadTimeWeaver}.
|
||||
* <p>If the given <code>loadTimeWeaver</code> is <code>null</code>, then a
|
||||
* <code>LoadTimeWeaver</code> will be auto-retrieved from the containing
|
||||
* {@link BeanFactory}, expecting a bean named
|
||||
* {@link ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME "loadTimeWeaver"}.
|
||||
* @param loadTimeWeaver the specific <code>LoadTimeWeaver</code> that is to be used; can be <code>null</code>
|
||||
*/
|
||||
public LoadTimeWeaverAwareProcessor(LoadTimeWeaver loadTimeWeaver) {
|
||||
this.loadTimeWeaver = loadTimeWeaver;
|
||||
}
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof LoadTimeWeaverAware) {
|
||||
LoadTimeWeaver ltw = this.loadTimeWeaver;
|
||||
if (ltw == null) {
|
||||
Assert.state(this.beanFactory != null,
|
||||
"BeanFactory required if no LoadTimeWeaver explicitly specified");
|
||||
ltw = (LoadTimeWeaver) this.beanFactory.getBean(
|
||||
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class);
|
||||
}
|
||||
((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String name) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Load-time weaving support for a Spring application context, building on Spring's
|
||||
{@link org.springframework.instrument.classloading.LoadTimeWeaver} abstraction.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* 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.springframework.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.ejb.EJBHome;
|
||||
import javax.ejb.EJBObject;
|
||||
import javax.naming.NamingException;
|
||||
import javax.rmi.PortableRemoteObject;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.remoting.RemoteConnectFailureException;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
import org.springframework.remoting.rmi.RmiClientInterceptorUtils;
|
||||
|
||||
/**
|
||||
* Base class for interceptors proxying remote Stateless Session Beans.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>Such an interceptor must be the last interceptor in the advice chain.
|
||||
* In this case, there is no target object.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public abstract class AbstractRemoteSlsbInvokerInterceptor extends AbstractSlsbInvokerInterceptor {
|
||||
|
||||
private Class homeInterface;
|
||||
|
||||
private boolean refreshHomeOnConnectFailure = false;
|
||||
|
||||
private volatile boolean homeAsComponent = false;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set a home interface that this invoker will narrow to before performing
|
||||
* the parameterless SLSB <code>create()</code> call that returns the actual
|
||||
* SLSB proxy.
|
||||
* <p>Default is none, which will work on all J2EE servers that are not based
|
||||
* on CORBA. A plain <code>javax.ejb.EJBHome</code> interface is known to be
|
||||
* sufficient to make a WebSphere 5.0 Remote SLSB work. On other servers,
|
||||
* the specific home interface for the target SLSB might be necessary.
|
||||
*/
|
||||
public void setHomeInterface(Class homeInterface) {
|
||||
if (homeInterface != null && !homeInterface.isInterface()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Home interface class [" + homeInterface.getClass() + "] is not an interface");
|
||||
}
|
||||
this.homeInterface = homeInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to refresh the EJB home on connect failure.
|
||||
* Default is "false".
|
||||
* <p>Can be turned on to allow for hot restart of the EJB server.
|
||||
* If a cached EJB home throws an RMI exception that indicates a
|
||||
* remote connect failure, a fresh home will be fetched and the
|
||||
* invocation will be retried.
|
||||
* @see java.rmi.ConnectException
|
||||
* @see java.rmi.ConnectIOException
|
||||
* @see java.rmi.NoSuchObjectException
|
||||
*/
|
||||
public void setRefreshHomeOnConnectFailure(boolean refreshHomeOnConnectFailure) {
|
||||
this.refreshHomeOnConnectFailure = refreshHomeOnConnectFailure;
|
||||
}
|
||||
|
||||
protected boolean isHomeRefreshable() {
|
||||
return this.refreshHomeOnConnectFailure;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This overridden lookup implementation performs a narrow operation
|
||||
* after the JNDI lookup, provided that a home interface is specified.
|
||||
* @see #setHomeInterface
|
||||
* @see javax.rmi.PortableRemoteObject#narrow
|
||||
*/
|
||||
protected Object lookup() throws NamingException {
|
||||
Object homeObject = super.lookup();
|
||||
if (this.homeInterface != null) {
|
||||
try {
|
||||
homeObject = PortableRemoteObject.narrow(homeObject, this.homeInterface);
|
||||
}
|
||||
catch (ClassCastException ex) {
|
||||
throw new RemoteLookupFailureException(
|
||||
"Could not narrow EJB home stub to home interface [" + this.homeInterface.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
return homeObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for EJB3-style home object that serves as EJB component directly.
|
||||
*/
|
||||
protected Method getCreateMethod(Object home) throws EjbAccessException {
|
||||
if (this.homeAsComponent) {
|
||||
return null;
|
||||
}
|
||||
if (!(home instanceof EJBHome)) {
|
||||
// An EJB3 Session Bean...
|
||||
this.homeAsComponent = true;
|
||||
return null;
|
||||
}
|
||||
return super.getCreateMethod(home);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches an EJB home object and delegates to <code>doInvoke</code>.
|
||||
* <p>If configured to refresh on connect failure, it will call
|
||||
* {@link #refreshAndRetry} on corresponding RMI exceptions.
|
||||
* @see #getHome
|
||||
* @see #doInvoke
|
||||
* @see #refreshAndRetry
|
||||
*/
|
||||
public Object invokeInContext(MethodInvocation invocation) throws Throwable {
|
||||
try {
|
||||
return doInvoke(invocation);
|
||||
}
|
||||
catch (RemoteConnectFailureException ex) {
|
||||
return handleRemoteConnectFailure(invocation, ex);
|
||||
}
|
||||
catch (RemoteException ex) {
|
||||
if (isConnectFailure(ex)) {
|
||||
return handleRemoteConnectFailure(invocation, ex);
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given RMI exception indicates a connect failure.
|
||||
* <p>The default implementation delegates to RmiClientInterceptorUtils.
|
||||
* @param ex the RMI exception to check
|
||||
* @return whether the exception should be treated as connect failure
|
||||
* @see org.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure
|
||||
*/
|
||||
protected boolean isConnectFailure(RemoteException ex) {
|
||||
return RmiClientInterceptorUtils.isConnectFailure(ex);
|
||||
}
|
||||
|
||||
private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {
|
||||
if (this.refreshHomeOnConnectFailure) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not connect to remote EJB [" + getJndiName() + "] - retrying", ex);
|
||||
}
|
||||
else if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not connect to remote EJB [" + getJndiName() + "] - retrying");
|
||||
}
|
||||
return refreshAndRetry(invocation);
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the EJB home object and retry the given invocation.
|
||||
* Called by invoke on connect failure.
|
||||
* @param invocation the AOP method invocation
|
||||
* @return the invocation result, if any
|
||||
* @throws Throwable in case of invocation failure
|
||||
* @see #invoke
|
||||
*/
|
||||
protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
|
||||
try {
|
||||
refreshHome();
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new RemoteLookupFailureException("Failed to locate remote EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
return doInvoke(invocation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform the given invocation on the current EJB home.
|
||||
* Template method to be implemented by subclasses.
|
||||
* @param invocation the AOP method invocation
|
||||
* @return the invocation result, if any
|
||||
* @throws Throwable in case of invocation failure
|
||||
* @see #getHome
|
||||
* @see #newSessionBeanInstance
|
||||
*/
|
||||
protected abstract Object doInvoke(MethodInvocation invocation) throws Throwable;
|
||||
|
||||
|
||||
/**
|
||||
* Return a new instance of the stateless session bean.
|
||||
* To be invoked by concrete remote SLSB invoker subclasses.
|
||||
* <p>Can be overridden to change the algorithm.
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #create
|
||||
*/
|
||||
protected Object newSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Trying to create reference to remote EJB");
|
||||
}
|
||||
Object ejbInstance = create();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Obtained reference to remote EJB: " + ejbInstance);
|
||||
}
|
||||
return ejbInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given EJB instance.
|
||||
* To be invoked by concrete remote SLSB invoker subclasses.
|
||||
* @param ejb the EJB instance to remove
|
||||
* @see javax.ejb.EJBObject#remove
|
||||
*/
|
||||
protected void removeSessionBeanInstance(EJBObject ejb) {
|
||||
if (ejb != null && !this.homeAsComponent) {
|
||||
try {
|
||||
ejb.remove();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.warn("Could not invoke 'remove' on remote EJB proxy", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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.springframework.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.jndi.JndiObjectLocator;
|
||||
|
||||
/**
|
||||
* Base class for AOP interceptors invoking local or remote Stateless Session Beans.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>Such an interceptor must be the last interceptor in the advice chain.
|
||||
* In this case, there is no direct target object: The call is handled in a
|
||||
* special way, getting executed on an EJB instance retrieved via an EJB home.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public abstract class AbstractSlsbInvokerInterceptor extends JndiObjectLocator
|
||||
implements MethodInterceptor {
|
||||
|
||||
private boolean lookupHomeOnStartup = true;
|
||||
|
||||
private boolean cacheHome = true;
|
||||
|
||||
private boolean exposeAccessContext = false;
|
||||
|
||||
/**
|
||||
* The EJB's home object, potentially cached.
|
||||
* The type must be Object as it could be either EJBHome or EJBLocalHome.
|
||||
*/
|
||||
private Object cachedHome;
|
||||
|
||||
/**
|
||||
* The no-arg create() method required on EJB homes, potentially cached.
|
||||
*/
|
||||
private Method createMethod;
|
||||
|
||||
private final Object homeMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to look up the EJB home object on startup.
|
||||
* Default is "true".
|
||||
* <p>Can be turned off to allow for late start of the EJB server.
|
||||
* In this case, the EJB home object will be fetched on first access.
|
||||
* @see #setCacheHome
|
||||
*/
|
||||
public void setLookupHomeOnStartup(boolean lookupHomeOnStartup) {
|
||||
this.lookupHomeOnStartup = lookupHomeOnStartup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to cache the EJB home object once it has been located.
|
||||
* Default is "true".
|
||||
* <p>Can be turned off to allow for hot restart of the EJB server.
|
||||
* In this case, the EJB home object will be fetched for each invocation.
|
||||
* @see #setLookupHomeOnStartup
|
||||
*/
|
||||
public void setCacheHome(boolean cacheHome) {
|
||||
this.cacheHome = cacheHome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to expose the JNDI environment context for all access to the target
|
||||
* EJB, i.e. for all method invocations on the exposed object reference.
|
||||
* <p>Default is "false", i.e. to only expose the JNDI context for object lookup.
|
||||
* Switch this flag to "true" in order to expose the JNDI environment (including
|
||||
* the authorization context) for each EJB invocation, as needed by WebLogic
|
||||
* for EJBs with authorization requirements.
|
||||
*/
|
||||
public void setExposeAccessContext(boolean exposeAccessContext) {
|
||||
this.exposeAccessContext = exposeAccessContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches EJB home on startup, if necessary.
|
||||
* @see #setLookupHomeOnStartup
|
||||
* @see #refreshHome
|
||||
*/
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
super.afterPropertiesSet();
|
||||
if (this.lookupHomeOnStartup) {
|
||||
// look up EJB home and create method
|
||||
refreshHome();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the cached home object, if applicable.
|
||||
* Also caches the create method on the home object.
|
||||
* @throws NamingException if thrown by the JNDI lookup
|
||||
* @see #lookup
|
||||
* @see #getCreateMethod
|
||||
*/
|
||||
protected void refreshHome() throws NamingException {
|
||||
synchronized (this.homeMonitor) {
|
||||
Object home = lookup();
|
||||
if (this.cacheHome) {
|
||||
this.cachedHome = home;
|
||||
this.createMethod = getCreateMethod(home);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the create method of the given EJB home object.
|
||||
* @param home the EJB home object
|
||||
* @return the create method
|
||||
* @throws EjbAccessException if the method couldn't be retrieved
|
||||
*/
|
||||
protected Method getCreateMethod(Object home) throws EjbAccessException {
|
||||
try {
|
||||
// Cache the EJB create() method that must be declared on the home interface.
|
||||
return home.getClass().getMethod("create", (Class[]) null);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new EjbAccessException("EJB home [" + home + "] has no no-arg create() method");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EJB home object to use. Called for each invocation.
|
||||
* <p>Default implementation returns the home created on initialization,
|
||||
* if any; else, it invokes lookup to get a new proxy for each invocation.
|
||||
* <p>Can be overridden in subclasses, for example to cache a home object
|
||||
* for a given amount of time before recreating it, or to test the home
|
||||
* object whether it is still alive.
|
||||
* @return the EJB home object to use for an invocation
|
||||
* @throws NamingException if proxy creation failed
|
||||
* @see #lookup
|
||||
* @see #getCreateMethod
|
||||
*/
|
||||
protected Object getHome() throws NamingException {
|
||||
if (!this.cacheHome || (this.lookupHomeOnStartup && !isHomeRefreshable())) {
|
||||
return (this.cachedHome != null ? this.cachedHome : lookup());
|
||||
}
|
||||
else {
|
||||
synchronized (this.homeMonitor) {
|
||||
if (this.cachedHome == null) {
|
||||
this.cachedHome = lookup();
|
||||
this.createMethod = getCreateMethod(this.cachedHome);
|
||||
}
|
||||
return this.cachedHome;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the cached EJB home object is potentially
|
||||
* subject to on-demand refreshing. Default is "false".
|
||||
*/
|
||||
protected boolean isHomeRefreshable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepares the thread context if necessar, and delegates to
|
||||
* {@link #invokeInContext}.
|
||||
*/
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
Context ctx = (this.exposeAccessContext ? getJndiTemplate().getContext() : null);
|
||||
try {
|
||||
return invokeInContext(invocation);
|
||||
}
|
||||
finally {
|
||||
getJndiTemplate().releaseContext(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the given invocation on the current EJB home,
|
||||
* within the thread context being prepared accordingly.
|
||||
* Template method to be implemented by subclasses.
|
||||
* @param invocation the AOP method invocation
|
||||
* @return the invocation result, if any
|
||||
* @throws Throwable in case of invocation failure
|
||||
*/
|
||||
protected abstract Object invokeInContext(MethodInvocation invocation) throws Throwable;
|
||||
|
||||
|
||||
/**
|
||||
* Invokes the <code>create()</code> method on the cached EJB home object.
|
||||
* @return a new EJBObject or EJBLocalObject
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
*/
|
||||
protected Object create() throws NamingException, InvocationTargetException {
|
||||
try {
|
||||
Object home = getHome();
|
||||
Method createMethodToUse = this.createMethod;
|
||||
if (createMethodToUse == null) {
|
||||
createMethodToUse = getCreateMethod(home);
|
||||
}
|
||||
if (createMethodToUse == null) {
|
||||
return home;
|
||||
}
|
||||
// Invoke create() method on EJB home object.
|
||||
return createMethodToUse.invoke(home, (Object[]) null);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new EjbAccessException("Could not access EJB home create() method", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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.ejb.access;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Exception that gets thrown when an EJB stub cannot be accessed properly.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class EjbAccessException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Constructor for EjbAccessException.
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public EjbAccessException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for EjbAccessException.
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause
|
||||
*/
|
||||
public EjbAccessException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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.springframework.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.ejb.CreateException;
|
||||
import javax.ejb.EJBLocalHome;
|
||||
import javax.ejb.EJBLocalObject;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
/**
|
||||
* Invoker for a local Stateless Session Bean.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>Caches the home object, since a local EJB home can never go stale.
|
||||
* See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the lookupHomeOnStartup
|
||||
* property to false, in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
*/
|
||||
public class LocalSlsbInvokerInterceptor extends AbstractSlsbInvokerInterceptor {
|
||||
|
||||
private volatile boolean homeAsComponent = false;
|
||||
|
||||
|
||||
/**
|
||||
* This implementation "creates" a new EJB instance for each invocation.
|
||||
* Can be overridden for custom invocation strategies.
|
||||
* <p>Alternatively, override {@link #getSessionBeanInstance} and
|
||||
* {@link #releaseSessionBeanInstance} to change EJB instance creation,
|
||||
* for example to hold a single shared EJB instance.
|
||||
*/
|
||||
public Object invokeInContext(MethodInvocation invocation) throws Throwable {
|
||||
Object ejb = null;
|
||||
try {
|
||||
ejb = getSessionBeanInstance();
|
||||
Method method = invocation.getMethod();
|
||||
if (method.getDeclaringClass().isInstance(ejb)) {
|
||||
// directly implemented
|
||||
return method.invoke(ejb, invocation.getArguments());
|
||||
}
|
||||
else {
|
||||
// not directly implemented
|
||||
Method ejbMethod = ejb.getClass().getMethod(method.getName(), method.getParameterTypes());
|
||||
return ejbMethod.invoke(ejb, invocation.getArguments());
|
||||
}
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
Throwable targetEx = ex.getTargetException();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method of local EJB [" + getJndiName() + "] threw exception", targetEx);
|
||||
}
|
||||
if (targetEx instanceof CreateException) {
|
||||
throw new EjbAccessException("Could not create local EJB [" + getJndiName() + "]", targetEx);
|
||||
}
|
||||
else {
|
||||
throw targetEx;
|
||||
}
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new EjbAccessException("Failed to locate local EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new EjbAccessException("Could not access method [" + invocation.getMethod().getName() +
|
||||
"] of local EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
finally {
|
||||
if (ejb instanceof EJBLocalObject) {
|
||||
releaseSessionBeanInstance((EJBLocalObject) ejb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for EJB3-style home object that serves as EJB component directly.
|
||||
*/
|
||||
protected Method getCreateMethod(Object home) throws EjbAccessException {
|
||||
if (this.homeAsComponent) {
|
||||
return null;
|
||||
}
|
||||
if (!(home instanceof EJBLocalHome)) {
|
||||
// An EJB3 Session Bean...
|
||||
this.homeAsComponent = true;
|
||||
return null;
|
||||
}
|
||||
return super.getCreateMethod(home);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an EJB instance to delegate the call to.
|
||||
* Default implementation delegates to newSessionBeanInstance.
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #newSessionBeanInstance
|
||||
*/
|
||||
protected Object getSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
return newSessionBeanInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the given EJB instance.
|
||||
* Default implementation delegates to removeSessionBeanInstance.
|
||||
* @param ejb the EJB instance to release
|
||||
* @see #removeSessionBeanInstance
|
||||
*/
|
||||
protected void releaseSessionBeanInstance(EJBLocalObject ejb) {
|
||||
removeSessionBeanInstance(ejb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the stateless session bean.
|
||||
* Can be overridden to change the algorithm.
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #create
|
||||
*/
|
||||
protected Object newSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Trying to create reference to local EJB");
|
||||
}
|
||||
Object ejbInstance = create();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Obtained reference to local EJB: " + ejbInstance);
|
||||
}
|
||||
return ejbInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given EJB instance.
|
||||
* @param ejb the EJB instance to remove
|
||||
* @see javax.ejb.EJBLocalObject#remove()
|
||||
*/
|
||||
protected void removeSessionBeanInstance(EJBLocalObject ejb) {
|
||||
if (ejb != null && !this.homeAsComponent) {
|
||||
try {
|
||||
ejb.remove();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.warn("Could not invoke 'remove' on local EJB proxy", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.ejb.access;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Convenient factory for local Stateless Session Bean (SLSB) proxies.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>If you want control over interceptor chaining, use an AOP ProxyFactoryBean
|
||||
* with LocalSlsbInvokerInterceptor rather than rely on this class.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the "lookupHomeOnStartup"
|
||||
* property to "false", in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Colin Sampaleanu
|
||||
* @since 09.05.2003
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
*/
|
||||
public class LocalStatelessSessionProxyFactoryBean extends LocalSlsbInvokerInterceptor
|
||||
implements FactoryBean, BeanClassLoaderAware {
|
||||
|
||||
/** The business interface of the EJB we're proxying */
|
||||
private Class businessInterface;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/** EJBLocalObject */
|
||||
private Object proxy;
|
||||
|
||||
|
||||
/**
|
||||
* Set the business interface of the EJB we're proxying.
|
||||
* This will normally be a super-interface of the EJB local component interface.
|
||||
* Using a business methods interface is a best practice when implementing EJBs.
|
||||
* @param businessInterface set the business interface of the EJB
|
||||
*/
|
||||
public void setBusinessInterface(Class businessInterface) {
|
||||
this.businessInterface = businessInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the business interface of the EJB we're proxying.
|
||||
*/
|
||||
public Class getBusinessInterface() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
super.afterPropertiesSet();
|
||||
if (this.businessInterface == null) {
|
||||
throw new IllegalArgumentException("businessInterface is required");
|
||||
}
|
||||
this.proxy = new ProxyFactory(this.businessInterface, this).getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* 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.springframework.ejb.access;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
import javax.ejb.CreateException;
|
||||
import javax.ejb.EJBObject;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
import org.springframework.remoting.rmi.RmiClientInterceptorUtils;
|
||||
|
||||
/**
|
||||
* Basic invoker for a remote Stateless Session Bean.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>"Creates" a new EJB instance for each invocation, or caches the session
|
||||
* bean instance for all invocations (see {@link #setCacheSessionBean}).
|
||||
* See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the "lookupHomeOnStartup"
|
||||
* property to "false", in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* <p>This invoker is typically used with an RMI business interface, which serves
|
||||
* as super-interface of the EJB component interface. Alternatively, this invoker
|
||||
* can also proxy a remote SLSB with a matching non-RMI business interface, i.e. an
|
||||
* interface that mirrors the EJB business methods but does not declare RemoteExceptions.
|
||||
* In the latter case, RemoteExceptions thrown by the EJB stub will automatically get
|
||||
* converted to Spring's unchecked RemoteAccessException.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 09.05.2003
|
||||
* @see org.springframework.remoting.RemoteAccessException
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
* @see AbstractRemoteSlsbInvokerInterceptor#setRefreshHomeOnConnectFailure
|
||||
*/
|
||||
public class SimpleRemoteSlsbInvokerInterceptor extends AbstractRemoteSlsbInvokerInterceptor
|
||||
implements DisposableBean {
|
||||
|
||||
private boolean cacheSessionBean = false;
|
||||
|
||||
private Object beanInstance;
|
||||
|
||||
private final Object beanInstanceMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to cache the actual session bean object.
|
||||
* <p>Off by default for standard EJB compliance. Turn this flag
|
||||
* on to optimize session bean access for servers that are
|
||||
* known to allow for caching the actual session bean object.
|
||||
* @see #setCacheHome
|
||||
*/
|
||||
public void setCacheSessionBean(boolean cacheSessionBean) {
|
||||
this.cacheSessionBean = cacheSessionBean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation "creates" a new EJB instance for each invocation.
|
||||
* Can be overridden for custom invocation strategies.
|
||||
* <p>Alternatively, override {@link #getSessionBeanInstance} and
|
||||
* {@link #releaseSessionBeanInstance} to change EJB instance creation,
|
||||
* for example to hold a single shared EJB component instance.
|
||||
*/
|
||||
protected Object doInvoke(MethodInvocation invocation) throws Throwable {
|
||||
Object ejb = null;
|
||||
try {
|
||||
ejb = getSessionBeanInstance();
|
||||
return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, ejb);
|
||||
}
|
||||
catch (NamingException ex) {
|
||||
throw new RemoteLookupFailureException("Failed to locate remote EJB [" + getJndiName() + "]", ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
Throwable targetEx = ex.getTargetException();
|
||||
if (targetEx instanceof RemoteException) {
|
||||
RemoteException rex = (RemoteException) targetEx;
|
||||
throw RmiClientInterceptorUtils.convertRmiAccessException(
|
||||
invocation.getMethod(), rex, isConnectFailure(rex), getJndiName());
|
||||
}
|
||||
else if (targetEx instanceof CreateException) {
|
||||
throw RmiClientInterceptorUtils.convertRmiAccessException(
|
||||
invocation.getMethod(), targetEx, "Could not create remote EJB [" + getJndiName() + "]");
|
||||
}
|
||||
throw targetEx;
|
||||
}
|
||||
finally {
|
||||
if (ejb instanceof EJBObject) {
|
||||
releaseSessionBeanInstance((EJBObject) ejb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an EJB component instance to delegate the call to.
|
||||
* <p>The default implementation delegates to {@link #newSessionBeanInstance}.
|
||||
* @return the EJB component instance
|
||||
* @throws NamingException if thrown by JNDI
|
||||
* @throws InvocationTargetException if thrown by the create method
|
||||
* @see #newSessionBeanInstance
|
||||
*/
|
||||
protected Object getSessionBeanInstance() throws NamingException, InvocationTargetException {
|
||||
if (this.cacheSessionBean) {
|
||||
synchronized (this.beanInstanceMonitor) {
|
||||
if (this.beanInstance == null) {
|
||||
this.beanInstance = newSessionBeanInstance();
|
||||
}
|
||||
return this.beanInstance;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return newSessionBeanInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the given EJB instance.
|
||||
* <p>The default implementation delegates to {@link #removeSessionBeanInstance}.
|
||||
* @param ejb the EJB component instance to release
|
||||
* @see #removeSessionBeanInstance
|
||||
*/
|
||||
protected void releaseSessionBeanInstance(EJBObject ejb) {
|
||||
if (!this.cacheSessionBean) {
|
||||
removeSessionBeanInstance(ejb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cached session bean instance, if necessary.
|
||||
*/
|
||||
protected void refreshHome() throws NamingException {
|
||||
super.refreshHome();
|
||||
if (this.cacheSessionBean) {
|
||||
synchronized (this.beanInstanceMonitor) {
|
||||
this.beanInstance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the cached session bean instance, if necessary.
|
||||
*/
|
||||
public void destroy() {
|
||||
if (this.cacheSessionBean) {
|
||||
synchronized (this.beanInstanceMonitor) {
|
||||
if (this.beanInstance instanceof EJBObject) {
|
||||
removeSessionBeanInstance((EJBObject) this.beanInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.ejb.access;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Convenient factory for remote SLSB proxies.
|
||||
* Designed for EJB 2.x, but works for EJB 3 Session Beans as well.
|
||||
*
|
||||
* <p>See {@link org.springframework.jndi.JndiObjectLocator} for info on
|
||||
* how to specify the JNDI location of the target EJB.
|
||||
*
|
||||
* <p>If you want control over interceptor chaining, use an AOP ProxyFactoryBean
|
||||
* with SimpleRemoteSlsbInvokerInterceptor rather than rely on this class.
|
||||
*
|
||||
* <p>In a bean container, this class is normally best used as a singleton. However,
|
||||
* if that bean container pre-instantiates singletons (as do the XML ApplicationContext
|
||||
* variants) you may have a problem if the bean container is loaded before the EJB
|
||||
* container loads the target EJB. That is because by default the JNDI lookup will be
|
||||
* performed in the init method of this class and cached, but the EJB will not have been
|
||||
* bound at the target location yet. The best solution is to set the lookupHomeOnStartup
|
||||
* property to false, in which case the home will be fetched on first access to the EJB.
|
||||
* (This flag is only true by default for backwards compatibility reasons).
|
||||
*
|
||||
* <p>This proxy factory is typically used with an RMI business interface, which serves
|
||||
* as super-interface of the EJB component interface. Alternatively, this factory
|
||||
* can also proxy a remote SLSB with a matching non-RMI business interface, i.e. an
|
||||
* interface that mirrors the EJB business methods but does not declare RemoteExceptions.
|
||||
* In the latter case, RemoteExceptions thrown by the EJB stub will automatically get
|
||||
* converted to Spring's unchecked RemoteAccessException.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Colin Sampaleanu
|
||||
* @author Juergen Hoeller
|
||||
* @since 09.05.2003
|
||||
* @see org.springframework.remoting.RemoteAccessException
|
||||
* @see AbstractSlsbInvokerInterceptor#setLookupHomeOnStartup
|
||||
* @see AbstractSlsbInvokerInterceptor#setCacheHome
|
||||
* @see AbstractRemoteSlsbInvokerInterceptor#setRefreshHomeOnConnectFailure
|
||||
*/
|
||||
public class SimpleRemoteStatelessSessionProxyFactoryBean extends SimpleRemoteSlsbInvokerInterceptor
|
||||
implements FactoryBean, BeanClassLoaderAware {
|
||||
|
||||
/** The business interface of the EJB we're proxying */
|
||||
private Class businessInterface;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
/** EJBObject */
|
||||
private Object proxy;
|
||||
|
||||
|
||||
/**
|
||||
* Set the business interface of the EJB we're proxying.
|
||||
* This will normally be a super-interface of the EJB remote component interface.
|
||||
* Using a business methods interface is a best practice when implementing EJBs.
|
||||
* <p>You can also specify a matching non-RMI business interface, i.e. an interface
|
||||
* that mirrors the EJB business methods but does not declare RemoteExceptions.
|
||||
* In this case, RemoteExceptions thrown by the EJB stub will automatically get
|
||||
* converted to Spring's generic RemoteAccessException.
|
||||
* @param businessInterface the business interface of the EJB
|
||||
*/
|
||||
public void setBusinessInterface(Class businessInterface) {
|
||||
this.businessInterface = businessInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the business interface of the EJB we're proxying.
|
||||
*/
|
||||
public Class getBusinessInterface() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws NamingException {
|
||||
super.afterPropertiesSet();
|
||||
if (this.businessInterface == null) {
|
||||
throw new IllegalArgumentException("businessInterface is required");
|
||||
}
|
||||
this.proxy = new ProxyFactory(this.businessInterface, this).getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return this.businessInterface;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
This package contains classes that allow easy access to EJBs.
|
||||
The basis are AOP interceptors run before and after the EJB invocation.
|
||||
In particular, the classes in this package allow transparent access
|
||||
to stateless session beans (SLSBs) with local interfaces, avoiding
|
||||
the need for application code using them to use EJB-specific APIs
|
||||
and JNDI lookups, and work with business interfaces that could be
|
||||
implemented without using EJB. This provides a valuable decoupling
|
||||
of client (such as web components) and business objects (which may
|
||||
or may not be EJBs). This gives us the choice of introducing EJB
|
||||
into an application (or removing EJB from an application) without
|
||||
affecting code using business objects.
|
||||
|
||||
<p>The motivation for the classes in this package are discussed in Chapter 11 of
|
||||
<a href="http://www.amazon.com/exec/obidos/tg/detail/-/0764543857/">Expert One-On-One J2EE Design and Development</a>
|
||||
by Rod Johnson (Wrox, 2002).
|
||||
|
||||
<p>However, the implementation and naming of classes in this package has changed.
|
||||
It now uses FactoryBeans and AOP, rather than the custom bean definitions described in
|
||||
<i>Expert One-on-One J2EE</i>.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.ejb.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class for BeanDefinitionParsers which build
|
||||
* JNDI-locating beans, supporting an optional "jndiEnvironment"
|
||||
* bean property, populated from an "environment" XML sub-element.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class AbstractJndiLocatingBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
|
||||
|
||||
public static final String ENVIRONMENT = "environment";
|
||||
|
||||
public static final String ENVIRONMENT_REF = "environment-ref";
|
||||
|
||||
public static final String JNDI_ENVIRONMENT = "jndiEnvironment";
|
||||
|
||||
|
||||
protected boolean isEligibleAttribute(String attributeName) {
|
||||
return (super.isEligibleAttribute(attributeName) && !ENVIRONMENT_REF.equals(attributeName));
|
||||
}
|
||||
|
||||
protected void postProcess(BeanDefinitionBuilder definitionBuilder, Element element) {
|
||||
Object envValue = DomUtils.getChildElementValueByTagName(element, ENVIRONMENT);
|
||||
if (envValue != null) {
|
||||
// Specific environment settings defined, overriding any shared properties.
|
||||
definitionBuilder.addPropertyValue(JNDI_ENVIRONMENT, envValue);
|
||||
}
|
||||
else {
|
||||
// Check whether there is a reference to shared environment properties...
|
||||
String envRef = element.getAttribute(ENVIRONMENT_REF);
|
||||
if (StringUtils.hasLength(envRef)) {
|
||||
definitionBuilder.addPropertyValue(JNDI_ENVIRONMENT, new RuntimeBeanReference(envRef));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.ejb.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.NamespaceHandler}
|
||||
* for the '<code>jee</code>' namespace.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
*/
|
||||
public class JeeNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("jndi-lookup", new JndiLookupBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("local-slsb", new LocalStatelessSessionBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("remote-slsb", new RemoteStatelessSessionBeanDefinitionParser());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.ejb.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.jndi.JndiObjectFactoryBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple {@link org.springframework.beans.factory.xml.BeanDefinitionParser} implementation that
|
||||
* translates <code>jndi-lookup</code> tag into {@link JndiObjectFactoryBean} definitions.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see JndiObjectFactoryBean
|
||||
*/
|
||||
class JndiLookupBeanDefinitionParser extends AbstractJndiLocatingBeanDefinitionParser {
|
||||
|
||||
public static final String DEFAULT_VALUE = "default-value";
|
||||
|
||||
public static final String DEFAULT_REF = "default-ref";
|
||||
|
||||
public static final String DEFAULT_OBJECT = "defaultObject";
|
||||
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return JndiObjectFactoryBean.class;
|
||||
}
|
||||
|
||||
protected boolean isEligibleAttribute(String attributeName) {
|
||||
return (super.isEligibleAttribute(attributeName) &&
|
||||
!DEFAULT_VALUE.equals(attributeName) && !DEFAULT_REF.equals(attributeName));
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
super.doParse(element, parserContext, builder);
|
||||
|
||||
String defaultValue = element.getAttribute(DEFAULT_VALUE);
|
||||
String defaultRef = element.getAttribute(DEFAULT_REF);
|
||||
if (StringUtils.hasLength(defaultValue)) {
|
||||
if (StringUtils.hasLength(defaultRef)) {
|
||||
parserContext.getReaderContext().error("<jndi-lookup> element is only allowed to contain either " +
|
||||
"'default-value' attribute OR 'default-ref' attribute, not both", element);
|
||||
}
|
||||
builder.addPropertyValue(DEFAULT_OBJECT, defaultValue);
|
||||
}
|
||||
else if (StringUtils.hasLength(defaultRef)) {
|
||||
builder.addPropertyValue(DEFAULT_OBJECT, new RuntimeBeanReference(defaultRef));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.ejb.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser}
|
||||
* implementation for parsing '<code>local-slsb</code>' tags and
|
||||
* creating {@link LocalStatelessSessionProxyFactoryBean} definitions.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
class LocalStatelessSessionBeanDefinitionParser extends AbstractJndiLocatingBeanDefinitionParser {
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean";
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue