You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2016/10/28 07:33:06 UTC

[03/21] isis git commit: ISIS-1223 Upgrade Wicket to 7.x

ISIS-1223 Upgrade Wicket to 7.x

Copy temporarily Wicket's Guice classes to workaround issue https://issues.apache.org/jira/browse/WICKET-6020.
Once Wicket 7.2.0 is released these classes should be removed!


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/5625c6c4
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/5625c6c4
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/5625c6c4

Branch: refs/heads/master
Commit: 5625c6c4cec59c57e00cffa0159a89795b46addc
Parents: 8eab457
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Mon Nov 2 21:35:42 2015 +0100
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Mon Nov 2 21:35:42 2015 +0100

----------------------------------------------------------------------
 .../wicket/viewer/IsisWicketApplication.java    |   4 +-
 .../viewer/guice/GuiceComponentInjector.java    | 137 ++++++++++++++++
 .../viewer/guice/GuiceFieldValueFactory.java    | 161 ++++++++++++++++++
 .../viewer/guice/GuiceProxyTargetLocator.java   | 162 +++++++++++++++++++
 4 files changed, 461 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/5625c6c4/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index 401a4b5..a04290e 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -46,7 +46,6 @@ import org.apache.wicket.SharedResources;
 import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
 import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
 import org.apache.wicket.core.request.mapper.MountedMapper;
-import org.apache.wicket.guice.GuiceComponentInjector;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.filter.JavaScriptFilteredIntoFooterHeaderResponse;
 import org.apache.wicket.markup.html.IHeaderContributor;
@@ -100,6 +99,7 @@ import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistryAccessor;
 import org.apache.isis.viewer.wicket.ui.pages.accmngt.AccountConfirmationMap;
 import org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
+import org.apache.isis.viewer.wicket.viewer.guice.GuiceComponentInjector;
 import org.apache.isis.viewer.wicket.viewer.integration.isis.DeploymentTypeWicketAbstract;
 import org.apache.isis.viewer.wicket.viewer.integration.isis.WicketServer;
 import org.apache.isis.viewer.wicket.viewer.integration.isis.WicketServerPrototype;
@@ -689,8 +689,6 @@ public class IsisWicketApplication
 
 
     protected void initWicketComponentInjection(final Injector injector) {
-        // if serializable, then brings in dependency on cglib, and in turn asm.
-        // This would block us from migrating to DN 4.0.x
         getComponentInstantiationListeners().add(new GuiceComponentInjector(this, injector, false));
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/5625c6c4/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceComponentInjector.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceComponentInjector.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceComponentInjector.java
new file mode 100644
index 0000000..b80ba1d
--- /dev/null
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceComponentInjector.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.isis.viewer.wicket.viewer.guice;
+
+import com.google.inject.Guice;
+import com.google.inject.ImplementedBy;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.Stage;
+import org.apache.wicket.Application;
+import org.apache.wicket.Component;
+import org.apache.wicket.IBehaviorInstantiationListener;
+import org.apache.wicket.Session;
+import org.apache.wicket.application.IComponentInstantiationListener;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.guice.GuiceInjectorHolder;
+import org.apache.wicket.injection.IFieldValueFactory;
+import org.apache.wicket.model.Model;
+
+/**
+ * Injects field members of components and behaviors using Guice.
+ * <p>
+ * Add this to your application in its {@link Application#init()} method like so:
+ * 
+ * <pre>
+ * getComponentInstantiationListeners().add(new GuiceComponentInjector(this));
+ * </pre>
+ * 
+ * <p>
+ * There are different constructors for this object depending on how you want to wire things. See
+ * the javadoc for the constructors for more information.
+ * </p>
+ * <p>
+ * Only Wicket {@link Component}s and {@link Behavior}s are automatically injected, other classes
+ * such as {@link Session}, {@link Model}, and any other POJO can be injected by calling
+ * <code>Injector.get().inject(this)</code> in their constructor.
+ * </p>
+ * 
+ * @author Alastair Maw
+ */
+public class GuiceComponentInjector extends org.apache.wicket.injection.Injector
+	implements
+		IComponentInstantiationListener,
+		IBehaviorInstantiationListener
+{
+	private final IFieldValueFactory fieldValueFactory;
+
+	/**
+	 * Creates a new Wicket GuiceComponentInjector instance.
+	 * <p>
+	 * Internally this will create a new Guice {@link Injector} instance, with no {@link Module}
+	 * instances. This is only useful if your beans have appropriate {@link ImplementedBy}
+	 * annotations on them so that they can be automatically picked up with no extra configuration
+	 * code.
+	 * 
+	 * @param app
+	 */
+	public GuiceComponentInjector(final Application app)
+	{
+		this(app, new Module[0]);
+	}
+
+	/**
+	 * Creates a new Wicket GuiceComponentInjector instance, using the supplied Guice {@link Module}
+	 * instances to create a new Guice {@link Injector} instance internally.
+	 * 
+	 * @param app
+	 * @param modules
+	 */
+	public GuiceComponentInjector(final Application app, final Module... modules)
+	{
+		this(app, Guice.createInjector(app.usesDeploymentConfig() ? Stage.PRODUCTION
+			: Stage.DEVELOPMENT, modules), true);
+	}
+
+	/**
+	 * Constructor
+	 * 
+	 * @param app
+	 * @param injector
+	 */
+	public GuiceComponentInjector(final Application app, final Injector injector)
+	{
+		this(app, injector, true);
+	}
+
+	/**
+	 * Creates a new Wicket GuiceComponentInjector instance, using the provided Guice
+	 * {@link Injector} instance.
+	 * 
+	 * @param app
+	 * @param injector
+	 * @param wrapInProxies
+	 *            whether or not wicket should wrap dependencies with specialized proxies that can
+	 *            be safely serialized. in most cases this should be set to true.
+	 */
+	public GuiceComponentInjector(final Application app, final Injector injector,
+		final boolean wrapInProxies)
+	{
+		app.setMetaData(GuiceInjectorHolder.INJECTOR_KEY, new GuiceInjectorHolder(injector));
+		fieldValueFactory = new GuiceFieldValueFactory(wrapInProxies);
+		app.getBehaviorInstantiationListeners().add(this);
+		bind(app);
+	}
+
+	@Override
+	public void inject(final Object object)
+	{
+		inject(object, fieldValueFactory);
+	}
+
+	@Override
+	public void onInstantiation(final Component component)
+	{
+		inject(component);
+	}
+
+	@Override
+	public void onInstantiation(Behavior behavior)
+	{
+		inject(behavior);
+	}
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/5625c6c4/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceFieldValueFactory.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceFieldValueFactory.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceFieldValueFactory.java
new file mode 100644
index 0000000..70d3568
--- /dev/null
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceFieldValueFactory.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.isis.viewer.wicket.viewer.guice;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.inject.Qualifier;
+
+import org.apache.wicket.injection.IFieldValueFactory;
+import org.apache.wicket.proxy.LazyInitProxyFactory;
+
+import com.google.inject.BindingAnnotation;
+import com.google.inject.Inject;
+import org.apache.wicket.util.lang.Generics;
+
+/**
+ *
+ */
+public class GuiceFieldValueFactory implements IFieldValueFactory
+{
+	private final ConcurrentMap<GuiceProxyTargetLocator, Object> cache = Generics.newConcurrentHashMap();
+	private static final Object NULL_SENTINEL = new Object();
+
+	private final boolean wrapInProxies;
+
+	/**
+	 * Construct.
+	 *
+	 * @param wrapInProxies
+	 */
+	GuiceFieldValueFactory(final boolean wrapInProxies)
+	{
+		this.wrapInProxies = wrapInProxies;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Object getFieldValue(final Field field, final Object fieldOwner)
+	{
+		Object target = null;
+
+		if (supportsField(field))
+		{
+			Inject injectAnnotation = field.getAnnotation(Inject.class);
+			javax.inject.Inject javaxInjectAnnotation = field.getAnnotation(javax.inject.Inject.class);
+			if (!Modifier.isStatic(field.getModifiers()) && (injectAnnotation != null || javaxInjectAnnotation != null))
+			{
+				try
+				{
+					boolean optional = injectAnnotation != null && injectAnnotation.optional();
+					Annotation bindingAnnotation = findBindingAnnotation(field.getAnnotations());
+					final GuiceProxyTargetLocator locator = new GuiceProxyTargetLocator(field, bindingAnnotation, optional);
+
+					Object cachedValue = cache.get(locator);
+					if (cachedValue != null)
+					{
+						return cachedValue == NULL_SENTINEL ? null : cachedValue;
+					}
+
+					target = locator.locateProxyTarget();
+					if (target == null)
+					{
+						// Optional without a binding, return null
+					}
+					else
+					{
+						if (wrapInProxies)
+						{
+							target = LazyInitProxyFactory.createProxy(field.getType(), locator);
+						}
+					}
+
+					if (locator.isSingletonScope())
+					{
+						Object tmpTarget = cache.putIfAbsent(locator, target == null ? NULL_SENTINEL : target);
+						if (tmpTarget != null)
+						{
+							target = tmpTarget;
+						}
+					}
+
+					if (!field.isAccessible())
+					{
+						field.setAccessible(true);
+					}
+				}
+				catch (MoreThanOneBindingException e)
+				{
+					throw new RuntimeException(
+							"Can't have more than one BindingAnnotation on field " + field.getName() +
+									" of class " + fieldOwner.getClass().getName());
+				}
+			}
+		}
+
+		return target == NULL_SENTINEL ? null : target;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean supportsField(final Field field)
+	{
+		return field.isAnnotationPresent(Inject.class) || field.isAnnotationPresent(javax.inject.Inject.class);
+	}
+
+	/**
+	 *
+	 * @param annotations
+	 * @return Annotation
+	 * @throws MoreThanOneBindingException
+	 */
+	private Annotation findBindingAnnotation(final Annotation[] annotations)
+			throws MoreThanOneBindingException
+	{
+		Annotation bindingAnnotation = null;
+
+		// Work out if we have a BindingAnnotation on this parameter.
+		for (Annotation annotation : annotations)
+		{
+			if (annotation.annotationType().getAnnotation(BindingAnnotation.class) != null ||
+					annotation.annotationType().getAnnotation(Qualifier.class) != null)
+			{
+				if (bindingAnnotation != null)
+				{
+					throw new MoreThanOneBindingException();
+				}
+				bindingAnnotation = annotation;
+			}
+		}
+		return bindingAnnotation;
+	}
+
+	/**
+	 *
+	 */
+	public static class MoreThanOneBindingException extends Exception
+	{
+		private static final long serialVersionUID = 1L;
+	}
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/5625c6c4/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceProxyTargetLocator.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceProxyTargetLocator.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceProxyTargetLocator.java
new file mode 100644
index 0000000..dcf11e7
--- /dev/null
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/guice/GuiceProxyTargetLocator.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.isis.viewer.wicket.viewer.guice;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+
+import com.google.inject.ConfigurationException;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Scopes;
+import com.google.inject.TypeLiteral;
+import org.apache.wicket.Application;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.guice.GuiceInjectorHolder;
+import org.apache.wicket.proxy.IProxyTargetLocator;
+import org.apache.wicket.core.util.lang.WicketObjects;
+import org.apache.wicket.util.lang.Objects;
+
+class GuiceProxyTargetLocator implements IProxyTargetLocator
+{
+	private static final long serialVersionUID = 1L;
+
+	private final Annotation bindingAnnotation;
+
+	private final boolean optional;
+
+	private final String className;
+
+	private final String fieldName;
+
+	private Boolean isSingletonCache = null;
+
+	public GuiceProxyTargetLocator(final Field field, final Annotation bindingAnnotation,
+								   final boolean optional)
+	{
+		this.bindingAnnotation = bindingAnnotation;
+		this.optional = optional;
+		className = field.getDeclaringClass().getName();
+		fieldName = field.getName();
+	}
+
+	@Override
+	public Object locateProxyTarget()
+	{
+		Injector injector = getInjector();
+
+		final Key<?> key = newGuiceKey();
+
+		// if the Inject annotation is marked optional and no binding is found
+		// then skip this injection (WICKET-2241)
+		if (optional)
+		{
+			// Guice 2.0 throws a ConfigurationException if no binding is find while 1.0 simply
+			// returns null.
+			try
+			{
+				if (injector.getBinding(key) == null)
+				{
+					return null;
+				}
+			}
+			catch (RuntimeException e)
+			{
+				return null;
+			}
+		}
+
+		return injector.getInstance(key);
+	}
+
+	private Key<?> newGuiceKey()
+	{
+		final Type type;
+		try
+		{
+			Class<?> clazz = WicketObjects.resolveClass(className);
+			final Field field = clazz.getDeclaredField(fieldName);
+			type = field.getGenericType();
+		}
+		catch (Exception e)
+		{
+			throw new WicketRuntimeException("Error accessing member: " + fieldName +
+				" of class: " + className, e);
+		}
+
+		// using TypeLiteral to retrieve the key gives us automatic support for
+		// Providers and other injectable TypeLiterals
+		if (bindingAnnotation == null)
+		{
+			return Key.get(TypeLiteral.get(type));
+		}
+		else
+		{
+			return Key.get(TypeLiteral.get(type), bindingAnnotation);
+		}
+	}
+
+	public boolean isSingletonScope()
+	{
+		if (isSingletonCache == null)
+		{
+			try
+			{
+				isSingletonCache = Scopes.isSingleton(getInjector().getBinding(newGuiceKey()));
+			}
+			catch (ConfigurationException ex)
+			{
+				// No binding, if optional can pretend this is null singleton
+				if (optional)
+					isSingletonCache = true;
+				else
+					throw ex;
+			}
+		}
+		return isSingletonCache;
+	}
+
+	private Injector getInjector()
+	{
+		final GuiceInjectorHolder holder = Application.get().getMetaData(
+			GuiceInjectorHolder.INJECTOR_KEY);
+
+		return holder.getInjector();
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if (this == o)
+			return true;
+		if (!(o instanceof GuiceProxyTargetLocator))
+			return false;
+		GuiceProxyTargetLocator that = (GuiceProxyTargetLocator) o;
+		return Objects.equal(optional, that.optional) &&
+				Objects.equal(bindingAnnotation, that.bindingAnnotation) &&
+				Objects.equal(className, that.className) &&
+				Objects.equal(fieldName, that.fieldName);
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return Objects.hashCode(bindingAnnotation, optional, className, fieldName);
+	}
+
+}