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;
+       }
+
+}


Reply via email to