You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by dk...@apache.org on 2013/08/29 18:29:56 UTC

svn commit: r1518694 - in /sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy: annotations/ impl/ impl/to/

Author: dklco
Date: Thu Aug 29 16:29:56 2013
New Revision: 1518694

URL: http://svn.apache.org/r1518694
Log:
Added an annotation for handling the invocation of Sling Services from a proxy class

Added:
    sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/annotations/SlingServiceInvocation.java
    sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/SlingServiceInvocationTO.java
Modified:
    sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/DefaultSlingProxyServiceImpl.java
    sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/SlingInvocationHandler.java
    sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/InvokedTOFactory.java

Added: sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/annotations/SlingServiceInvocation.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/annotations/SlingServiceInvocation.java?rev=1518694&view=auto
==============================================================================
--- sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/annotations/SlingServiceInvocation.java (added)
+++ sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/annotations/SlingServiceInvocation.java Thu Aug 29 16:29:56 2013
@@ -0,0 +1,69 @@
+/*
+ * 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.sling.commons.proxy.annotations;
+
+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;
+
+/**
+ * Annotation used to mark a Method as invoking another method on a Sling
+ * Service. When the method on the proxy interface is invoked, it will retrieve
+ * an instance of the Service and attempt to find a method matching the
+ * signature of the proxy method. If the first parameter of the method is the
+ * proxy interface, the proxy will inject an instance of itself.
+ * 
+ * Below are two examples, showing configurations, they assume you have a
+ * service with the interface:
+ * 
+ * <code><br/>
+ * public interface MyCustomService {<br/>
+ *   Resource doStuff();<br/>
+ *   Resource doOtherStuff(MyProxy proxy);<br/>
+ *   Resource doEvenMoreStuff(MyProxy proxy, String path);<br/>
+ * }
+ * </code>
+ * 
+ * <code><br/>
+ * &#64;SlingServiceInvocation(service = MyCustomService.class)<br/>
+ * Resource doStuff();<br/><br/>
+ * 
+ * &#64;SlingServiceInvocation(service = MyCustomService.class)<br/>
+ * Resource doOtherStuff();<br/><br/>
+ * 
+ * &#64;SlingServiceInvocation(service = MyCustomService.class)<br/>
+ * Resource doEvenMoreStuff(String path);
+ * </code>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+@Documented
+public @interface SlingServiceInvocation {
+
+	/**
+	 * The service interface to reference. This service should have a single
+	 * implementation and should have a method matching the signature of the
+	 * method upon which this annotation is added.
+	 * 
+	 * @return the service interface
+	 */
+	Class<?> service();
+}

Modified: sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/DefaultSlingProxyServiceImpl.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/DefaultSlingProxyServiceImpl.java?rev=1518694&r1=1518693&r2=1518694&view=diff
==============================================================================
--- sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/DefaultSlingProxyServiceImpl.java (original)
+++ sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/DefaultSlingProxyServiceImpl.java Thu Aug 29 16:29:56 2013
@@ -21,6 +21,7 @@ package org.apache.sling.commons.proxy.i
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Proxy;
 
+import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
@@ -29,15 +30,33 @@ import org.apache.sling.commons.proxy.an
 import org.apache.sling.commons.proxy.annotations.SlingProperty;
 import org.apache.sling.commons.proxy.annotations.SlingReference;
 import org.apache.sling.commons.proxy.impl.reflection.Annotations;
+import org.osgi.service.component.ComponentContext;
 
 /**
- * Default implementation of the {@link org.apache.sling.commons.proxy.SlingProxyService}
+ * Default implementation of the
+ * {@link org.apache.sling.commons.proxy.SlingProxyService}
  */
 @Service(value = SlingProxyService.class)
 @Component(description = "Creates ISlingProxy instances", immediate = true)
 public final class DefaultSlingProxyServiceImpl implements SlingProxyService {
 
 	/**
+	 * The sevice's context in OSGi
+	 */
+	private ComponentContext context;
+
+	/**
+	 * Called by the OSGi Container when this service is activated.
+	 * 
+	 * @param context
+	 *            the context for this service
+	 */
+	@Activate
+	protected void activate(ComponentContext context) {
+		this.context = context;
+	}
+
+	/**
 	 * Checks to see if an instance of the specified <code>type</code> can be
 	 * instantiated from the <code>resource</code>.
 	 * 
@@ -74,8 +93,7 @@ public final class DefaultSlingProxyServ
 	/*
 	 * (non-Javadoc)
 	 * 
-	 * @see
-	 * org.apache.sling.commons.proxy.SlingProxyService#getProxy(org.apache
+	 * @see org.apache.sling.commons.proxy.SlingProxyService#getProxy(org.apache
 	 * .sling.api.resource.Resource, java.lang.Class)
 	 */
 	public <AdapterType> AdapterType getProxy(Resource resource,
@@ -88,4 +106,12 @@ public final class DefaultSlingProxyServ
 		return rtn;
 	}
 
+	/**
+	 * Gets the component context for this service.
+	 * 
+	 * @return the component context
+	 */
+	public ComponentContext getContext() {
+		return context;
+	}
 }

Modified: sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/SlingInvocationHandler.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/SlingInvocationHandler.java?rev=1518694&r1=1518693&r2=1518694&view=diff
==============================================================================
--- sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/SlingInvocationHandler.java (original)
+++ sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/SlingInvocationHandler.java Thu Aug 29 16:29:56 2013
@@ -21,7 +21,9 @@ package org.apache.sling.commons.proxy.i
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
@@ -35,9 +37,10 @@ import org.apache.sling.api.resource.Val
 import org.apache.sling.commons.proxy.SlingProxyService;
 import org.apache.sling.commons.proxy.annotations.SlingChildren;
 import org.apache.sling.commons.proxy.annotations.SlingReference;
-import org.apache.sling.commons.proxy.impl.lang.JDPToStringImpl;
+import org.apache.sling.commons.proxy.annotations.SlingServiceInvocation;
 import org.apache.sling.commons.proxy.impl.lang.JDPEqualsImpl;
 import org.apache.sling.commons.proxy.impl.lang.JDPHashCodeImpl;
+import org.apache.sling.commons.proxy.impl.lang.JDPToStringImpl;
 import org.apache.sling.commons.proxy.impl.lang.MethodType;
 import org.apache.sling.commons.proxy.impl.reflection.Annotations;
 import org.apache.sling.commons.proxy.impl.to.BaseInvokedTO;
@@ -45,6 +48,9 @@ import org.apache.sling.commons.proxy.im
 import org.apache.sling.commons.proxy.impl.to.InvokedPropertyTO;
 import org.apache.sling.commons.proxy.impl.to.InvokedTO;
 import org.apache.sling.commons.proxy.impl.to.InvokedTOFactory;
+import org.apache.sling.commons.proxy.impl.to.SlingServiceInvocationTO;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,8 +71,7 @@ public class SlingInvocationHandler impl
 	private final Resource r;
 
 	/**
-	 * This caches all 'get' or 'is' method's return values. Calling 'set' will
-	 * clear that properties cached value.
+	 * This caches all 'get' or 'is' method's return values
 	 */
 	private final Map<String, Object> cache;
 
@@ -274,6 +279,78 @@ public class SlingInvocationHandler impl
 		return value;
 	}
 
+	/**
+	 * Handles the invocation of Sling Service methods.
+	 * 
+	 * @param to
+	 *            the transfer object
+	 * @return the value returned by the Sling Service if anything
+	 */
+	private Object handleServiceInvocation(SlingServiceInvocationTO to) {
+		Object value = null;
+
+		BundleContext context = ((DefaultSlingProxyServiceImpl) slingProxyService)
+				.getContext().getBundleContext();
+		ServiceReference reference = context.getServiceReference(to
+				.getService().getCanonicalName());
+		if (reference != null) {
+			Method toInvoke = null;
+			Object service = context.getService(reference);
+			for (Method m : service.getClass().getDeclaredMethods()) {
+				if (m.getName().equals(to.getMethod().getName())) {
+					final Class<?>[] params = to.getMethod()
+							.getParameterTypes();
+					if (m.getParameterTypes().equals(params)
+							&& m.getReturnType().equals(
+									to.getMethod().getReturnType())) {
+						toInvoke = m;
+						break;
+					}
+					Class<?>[] newParams = new ArrayList<Class<?>>() {
+						private static final long serialVersionUID = 1L;
+						{
+							for (Class<?> clazz : params) {
+								add(clazz);
+							}
+						}
+					}.toArray(new Class<?>[params.length]);
+					if (m.getParameterTypes().equals(newParams)
+							&& m.getReturnType().equals(
+									to.getMethod().getReturnType())) {
+						toInvoke = m;
+						break;
+					}
+				}
+			}
+			if (toInvoke != null) {
+				try {
+					value = toInvoke.invoke(service, to.getArgs());
+				} catch (IllegalArgumentException e) {
+					log.warn("Exception calling service method "
+							+ service.getClass().getCanonicalName() + "."
+							+ to.getMethod().getName() + " invalid paramters",
+							e);
+				} catch (IllegalAccessException e) {
+					log.warn("Exception calling service method "
+							+ service.getClass().getCanonicalName() + "."
+							+ to.getMethod().getName() + " illegal access", e);
+				} catch (InvocationTargetException e) {
+					log.warn("Exception calling service method "
+							+ service.getClass().getCanonicalName() + "."
+							+ to.getMethod().getName(), e);
+				}
+			} else {
+				log.warn("Unable to find method {} on service {}", to
+						.getMethod().getName(), service.getClass()
+						.getCanonicalName());
+			}
+		} else {
+			log.warn("Unable to find reference to service {}", to.getService()
+					.getCanonicalName());
+		}
+		return value;
+	}
+
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -293,13 +370,19 @@ public class SlingInvocationHandler impl
 	public Object invoke(final Object proxy, final Method method,
 			final Object[] args) throws Throwable {
 
-		final InvokedTO to = InvokedTOFactory.newInstance(proxy, method, args);
+		// TODO: this really needs to be refactored, we shouldn't constraining
+		// the method invocations by Java-Bean naming
+		final InvokedTO to = InvokedTOFactory.newInstance(method, args);
 		if (to.isGetter()) {
 			if (Annotations.methodHasAnnotation(method, SlingReference.class)) {
 				return (this.handleGetReference((BaseInvokedTO) to));
 			} else if (Annotations.methodHasAnnotation(method,
 					SlingChildren.class)) {
 				return (this.handleGetChildren((InvokedChildrenTO) to));
+			} else if (Annotations.methodHasAnnotation(method,
+					SlingServiceInvocation.class)) {
+				return (this
+						.handleServiceInvocation((SlingServiceInvocationTO) to));
 			} else {
 				return (this.handleGetProperty((InvokedPropertyTO) to));
 			}
@@ -319,6 +402,10 @@ public class SlingInvocationHandler impl
 		} else if (to.isType(MethodType.BackingResource)) {
 			return this.r;
 		}
+
+		// TODO: this probably should look for the annotation first, then if
+		// one's not found and it's not one of the white-listed methods, return
+		// an unsupported operation exception
 		throw new NoSuchMethodException("Method " + method.getName() + " DNE");
 	}
 }

Modified: sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/InvokedTOFactory.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/InvokedTOFactory.java?rev=1518694&r1=1518693&r2=1518694&view=diff
==============================================================================
--- sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/InvokedTOFactory.java (original)
+++ sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/InvokedTOFactory.java Thu Aug 29 16:29:56 2013
@@ -24,6 +24,7 @@ import org.apache.commons.lang.StringUti
 import org.apache.sling.commons.proxy.annotations.SlingChildren;
 import org.apache.sling.commons.proxy.annotations.SlingProperty;
 import org.apache.sling.commons.proxy.annotations.SlingReference;
+import org.apache.sling.commons.proxy.annotations.SlingServiceInvocation;
 import org.apache.sling.commons.proxy.impl.lang.MethodType;
 import org.apache.sling.commons.proxy.impl.reflection.Annotations;
 
@@ -33,6 +34,9 @@ import org.apache.sling.commons.proxy.im
  */
 public class InvokedTOFactory {
 
+	// TODO : I think this class should be deprecated in favor of init methods
+	// in the individual transfer objects
+
 	/**
 	 * Instantiates a new InvokedTO Object. This object will contain the
 	 * relevant invocation properties for the method invocation
@@ -45,8 +49,7 @@ public class InvokedTOFactory {
 	 *            the method arguments
 	 * @return the invocation TO
 	 */
-	public static InvokedTO newInstance(final Object proxy,
-			final Method method, final Object[] args) {
+	public static InvokedTO newInstance(final Method method, final Object[] args) {
 
 		final MethodType mt = MethodType.getMethodType(method);
 		if (mt.equals(MethodType.BackingResource)
@@ -68,7 +71,14 @@ public class InvokedTOFactory {
 			final Class<?> returnType = sc.returnType();
 
 			return new InvokedChildrenTO(method, args, path, returnType, mt);
+		} else if (Annotations.methodHasAnnotation(method,
+				SlingServiceInvocation.class)) {
+			final SlingServiceInvocation ssi = method
+					.getAnnotation(SlingServiceInvocation.class);
+			final Class<?> service = ssi.service();
+			return new SlingServiceInvocationTO(method, args, service, mt);
 		} else {
+
 			final SlingProperty sp = method.getAnnotation(SlingProperty.class);
 			if (sp == null) {
 				throw new java.lang.IllegalStateException("Method "

Added: sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/SlingServiceInvocationTO.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/SlingServiceInvocationTO.java?rev=1518694&view=auto
==============================================================================
--- sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/SlingServiceInvocationTO.java (added)
+++ sling/whiteboard/dklco/sling-proxy/src/main/java/org/apache/sling/commons/proxy/impl/to/SlingServiceInvocationTO.java Thu Aug 29 16:29:56 2013
@@ -0,0 +1,77 @@
+/*
+ * 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.sling.commons.proxy.impl.to;
+
+import java.lang.reflect.Method;
+
+import org.apache.sling.commons.proxy.impl.lang.MethodType;
+
+/**
+ * Transfer object for SlingServiceInvocation method invocations.
+ */
+public final class SlingServiceInvocationTO extends BaseInvokedTO {
+
+	/**
+	 * The service to invoke
+	 */
+	private final Class<?> service;
+
+	/**
+	 * The method arguments
+	 */
+	private Object[] args;
+
+	/**
+	 * Constructs a new Invoked Children Transfer Object.
+	 * 
+	 * @param method
+	 *            the invoked method
+	 * @param args
+	 *            the method arguments
+	 * @param service
+	 *            the service to invoke
+	 * @param mt
+	 *            the method type
+	 */
+	protected SlingServiceInvocationTO(final Method method,
+			final Object[] args, final Class<?> service, final MethodType mt) {
+		super(method, null, mt);
+		this.service = service;
+		this.args = args;
+	}
+
+	/**
+	 * Gets the parameters passed into the method
+	 * 
+	 * @return the arguments
+	 */
+	public Object[] getArgs() {
+		return args;
+	}
+
+	/**
+	 * Gets the service to invoke
+	 * 
+	 * @return the service
+	 */
+	public final Class<?> getService() {
+		return this.service;
+	}
+
+}