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/>
+ * @SlingServiceInvocation(service = MyCustomService.class)<br/>
+ * Resource doStuff();<br/><br/>
+ *
+ * @SlingServiceInvocation(service = MyCustomService.class)<br/>
+ * Resource doOtherStuff();<br/><br/>
+ *
+ * @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;
+ }
+
+}