001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.remoteable;
014
015import static javax.servlet.http.HttpServletResponse.*;
016import static org.apache.juneau.http.HttpMethodName.*;
017
018import java.util.*;
019import java.util.concurrent.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.dto.*;
023import org.apache.juneau.parser.*;
024import org.apache.juneau.rest.*;
025import org.apache.juneau.rest.annotation.*;
026
027/**
028 * @deprecated Use {@link org.apache.juneau.rest.remote.RrpcServlet}
029 */
030@Deprecated
031public abstract class RemoteableServlet extends BasicRestServlet {
032
033   private static final long serialVersionUID = 8207041758485477718L;
034
035   private final Map<String,Class<?>> classNameMap = new ConcurrentHashMap<>();
036
037   //--------------------------------------------------------------------------------
038   // Abstract methods
039   //--------------------------------------------------------------------------------
040
041   /**
042    * Returns the list of interfaces to their implementation objects.
043    *
044    * <p>
045    * This class is called often and not cached, so any caching should occur in the subclass if necessary.
046    *
047    * @return The service map.
048    * @throws Exception
049    */
050   protected abstract Map<Class<?>,Object> getServiceMap() throws Exception;
051
052   //--------------------------------------------------------------------------------
053   // REST methods
054   //--------------------------------------------------------------------------------
055
056   /**
057    * [GET /] - Get the list of all remote interfaces.
058    *
059    * @param req The HTTP servlet request.
060    * @return The list of links to the remote interfaces.
061    * @throws Exception
062    */
063   @RestMethod(name=GET, path="/")
064   public List<LinkString> getInterfaces(RestRequest req) throws Exception {
065      List<LinkString> l = new LinkedList<>();
066      boolean useAll = ! useOnlyAnnotated();
067      for (Class<?> c : getServiceMap().keySet()) {
068         if (useAll || getContext().getBeanContext().getClassMeta(c).isRemoteable())
069            l.add(new LinkString(c.getName(), "{0}/{1}", req.getRequestURI(), c.getName()));
070      }
071      return l;
072   }
073
074   /**
075    * [GET /{javaInterface] - Get the list of all remoteable methods on the specified interface name.
076    *
077    * @param javaInterface The Java interface name.
078    * @return The methods defined on the interface.
079    * @throws Exception
080    */
081   @RestMethod(name=GET, path="/{javaInterface}")
082   public Collection<String> listMethods(@Path String javaInterface) throws Exception {
083      return getMethods(javaInterface).keySet();
084   }
085
086   /**
087    * [POST /{javaInterface}/{javaMethod}] - Invoke the specified service method.
088    *
089    * @param req The HTTP request.
090    * @param javaInterface The Java interface name.
091    * @param javaMethod The Java method name or signature.
092    * @return The results from invoking the specified Java method.
093    * @throws Exception
094    */
095   @RestMethod(name=POST, path="/{javaInterface}/{javaMethod}")
096   public Object invoke(RestRequest req, @Path String javaInterface, @Path String javaMethod) throws Exception {
097
098      // Find the parser.
099      ReaderParser p = req.getBody().getReaderParser();
100      if (p == null)
101         throw new RestException(SC_UNSUPPORTED_MEDIA_TYPE, "Could not find parser for media type ''{0}''", req.getHeaders().getContentType());
102      Class<?> c = getInterfaceClass(javaInterface);
103
104      // Find the service.
105      Object service = getServiceMap().get(c);
106      if (service == null)
107         throw new RestException(SC_NOT_FOUND, "Service not found");
108
109      // Find the method.
110      java.lang.reflect.Method m = getMethods(javaInterface).get(javaMethod);
111      if (m == null)
112         throw new RestException(SC_NOT_FOUND, "Method not found");
113
114      // Parse the args and invoke the method.
115      Object[] params = p.parseArgs(req.getReader(), m.getGenericParameterTypes());
116      return m.invoke(service, params);
117   }
118
119
120   //--------------------------------------------------------------------------------
121   // Other methods
122   //--------------------------------------------------------------------------------
123
124   private boolean useOnlyAnnotated() {
125      return getContext().getBooleanProperty(RemoteableServiceProperties.REMOTEABLE_includeOnlyRemotableMethods, false);
126   }
127
128   private Map<String,java.lang.reflect.Method> getMethods(String javaInterface) throws Exception {
129      Class<?> c = getInterfaceClass(javaInterface);
130      ClassMeta<?> cm = getContext().getBeanContext().getClassMeta(c);
131      return (useOnlyAnnotated() ? cm.getRemoteableMethods() : cm.getPublicMethods());
132   }
133
134   /**
135    * Return the <code>Class</code> given it's name if it exists in the services map.
136    */
137   private Class<?> getInterfaceClass(String javaInterface) throws Exception {
138      Class<?> c = classNameMap.get(javaInterface);
139      if (c == null) {
140         for (Class<?> c2 : getServiceMap().keySet())
141            if (c2.getName().equals(javaInterface)) {
142               classNameMap.put(javaInterface, c2);
143               return c2;
144            }
145         throw new RestException(SC_NOT_FOUND, "Interface class not found");
146      }
147      return c;
148   }
149}