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}