All Downloads are FREE. Search and download functionalities are using the official Maven repository.

wicket.spring.injection.annot.SpringComponentInjector Maven / Gradle / Ivy

package wicket.spring.injection.annot;

import java.io.FileNotFoundException;
import java.io.Serializable;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;

import wicket.Application;
import wicket.MetaDataKey;
import wicket.Session;
import wicket.application.IComponentInstantiationListener;
import wicket.injection.ComponentInjector;
import wicket.injection.web.InjectorHolder;
import wicket.model.Model;
import wicket.protocol.http.WebApplication;
import wicket.protocol.http.portlet.PortletApplication;
import wicket.spring.ISpringContextLocator;

/**
 * {@link IComponentInstantiationListener} that injects component properties
 * annotated with {@link SpringBean} annotations.
 * 
 * To install in yourapplication.init() call
 * addComponentInstantiationListener(new SpringComponentInjector(this));
 * 
 * Non-wicket components such as {@link Session}, {@link Model}, and any other
 * pojo can be injected by calling
 * InjectorHolder.getInjector().inject(this) in their
 * constructor.
 * 
 * @author Igor Vaynberg (ivaynberg)
 * @author Justin Lee
 * 
 */
public class SpringComponentInjector extends ComponentInjector {

	/**
	 * Metadata key used to store application context holder in application's
	 * metadata
	 */
	private static MetaDataKey CONTEXT_KEY = new MetaDataKey(
			ApplicationContextHolder.class) {

		private static final long serialVersionUID = 1L;

	};

	/**
	 * Constructor used when spring application context is declared in the
	 * spring standard way and can be located through
	 * {@link WebApplicationContextUtils#getRequiredWebApplicationContext(ServletContext)}
	 * 
	 * @param webapp
	 *            wicket web application
	 */
	public SpringComponentInjector(WebApplication webapp) {
		// locate application context through spring's default location
		// mechanism and pass it on to the proper constructor
		this(webapp, WebApplicationContextUtils
				.getRequiredWebApplicationContext(webapp.getWicketServlet()
						.getServletContext()));
	}

	/**
	 * Constructor
	 * 
	 * @param webapp
	 *            wicket web application
	 * @param ctx
	 *            spring's application context
	 */
	public SpringComponentInjector(WebApplication webapp, ApplicationContext ctx) {
		if (webapp == null) {
			throw new IllegalArgumentException(
					"Argument [[webapp]] cannot be null");
		}

		if (ctx == null) {
			throw new IllegalArgumentException(
					"Argument [[ctx]] cannot be null");
		}

		// store context in application's metadata ...
		webapp.setMetaData(CONTEXT_KEY, new ApplicationContextHolder(ctx));

		// ... and create and register the annotation aware injector
		InjectorHolder
				.setInjector(new AnnotSpringInjector(new ContextLocator()));
	}

	/**
	 * Constructor for portlet applications
	 * 
	 * @param portletapp
	 */
	public SpringComponentInjector(PortletApplication portletapp) {
		GenericApplicationContext ctx = new GenericApplicationContext();

		// locate spring's application context ...
		String configLocation = portletapp.getWicketPortlet().getInitParameter(
				"contextConfigLocation");
		Resource resource = null;
		try {
			resource = new UrlResource(ResourceUtils.getURL(configLocation));
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e.getMessage());
		}

		new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(resource);
		ctx.refresh();

		// ... store it in application's metadata ...
		portletapp.setMetaData(CONTEXT_KEY, new ApplicationContextHolder(ctx));

		// ... and create and register the annotation aware injector
		InjectorHolder
				.setInjector(new AnnotSpringInjector(new ContextLocator()));
	}

	/**
	 * This is a holder for the application context. The reason we need a holder
	 * is that metadata only supports storing serializable objects but
	 * application context is not. The holder acts as a serializable wrapper for
	 * the context. Notice that although holder implements serializable it
	 * really is not because it has a reference to non serializable context -
	 * but this is ok because metadata objects in application are never
	 * serialized.
	 * 
	 * @author ivaynberg
	 * 
	 */
	private static class ApplicationContextHolder implements Serializable {
		private static final long serialVersionUID = 1L;

		private final ApplicationContext context;

		/**
		 * Constructor
		 * 
		 * @param context
		 */
		public ApplicationContextHolder(ApplicationContext context) {
			this.context = context;
		}

		/**
		 * @return the context
		 */
		public ApplicationContext getContext() {
			return context;
		}
	}

	/**
	 * A context locator that locates the context in application's metadata.
	 * This locator also keeps a transient cache of the lookup.
	 * 
	 * @author ivaynberg
	 * 
	 */
	private static class ContextLocator implements ISpringContextLocator {
		private transient ApplicationContext context;

		private static final long serialVersionUID = 1L;

		public ApplicationContext getSpringContext() {
			if (context == null) {
				context = ((ApplicationContextHolder) Application.get()
						.getMetaData(CONTEXT_KEY)).getContext();
			}
			return context;
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy