001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.camel.component.restlet; 018 019 import java.net.URI; 020 import java.util.ArrayList; 021 import java.util.HashMap; 022 import java.util.List; 023 import java.util.Map; 024 025 import org.apache.camel.Endpoint; 026 import org.apache.camel.impl.HeaderFilterStrategyComponent; 027 import org.apache.camel.util.URISupport; 028 import org.apache.camel.util.UnsafeUriCharactersEncoder; 029 import org.apache.commons.logging.Log; 030 import org.apache.commons.logging.LogFactory; 031 import org.restlet.Component; 032 import org.restlet.Guard; 033 import org.restlet.Restlet; 034 import org.restlet.Server; 035 import org.restlet.data.ChallengeScheme; 036 import org.restlet.data.Method; 037 import org.restlet.data.Protocol; 038 039 /** 040 * A Camel component embedded Restlet that produces and consumes exchanges. 041 * 042 * @version $Revision: 799322 $ 043 */ 044 public class RestletComponent extends HeaderFilterStrategyComponent { 045 private static final Log LOG = LogFactory.getLog(RestletComponent.class); 046 047 private final Map<String, Server> servers = new HashMap<String, Server>(); 048 private final Map<String, MethodBasedRouter> routers = new HashMap<String, MethodBasedRouter>(); 049 private final Component component = new Component(); 050 051 @Override 052 @SuppressWarnings("unchecked") 053 protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception { 054 055 RestletEndpoint result = new RestletEndpoint(this, remaining); 056 setEndpointHeaderFilterStrategy(result); 057 setProperties(result, parameters); 058 059 // construct URI so we can use it to get the splitted information 060 URI u = new URI(UnsafeUriCharactersEncoder.encode(remaining)); 061 String protocol = u.getScheme(); 062 063 String uriPattern = u.getPath(); 064 if (parameters.size() > 0) { 065 uriPattern = uriPattern + "?" + URISupport.createQueryString(parameters); 066 } 067 068 int port = 0; 069 String host = u.getHost(); 070 if (u.getPort() > 0) { 071 port = u.getPort(); 072 } 073 074 result.setProtocol(protocol); 075 result.setUriPattern(uriPattern); 076 result.setHost(host); 077 if (port > 0) { 078 result.setPort(port); 079 } 080 081 return result; 082 } 083 084 @Override 085 protected void doStart() throws Exception { 086 super.doStart(); 087 component.start(); 088 } 089 090 @Override 091 protected void doStop() throws Exception { 092 component.stop(); 093 // routers map entries are removed as consumer stops and servers map 094 // is not touch so to keep in sync with component's servers 095 super.doStop(); 096 } 097 098 @Override 099 protected boolean useIntrospectionOnEndpoint() { 100 // we invoke setProperties ourselves so we can construct "user" uri on 101 // on the remaining parameters 102 return false; 103 } 104 105 public void connect(RestletConsumer consumer) throws Exception { 106 RestletEndpoint endpoint = (RestletEndpoint)consumer.getEndpoint(); 107 addServerIfNeccessary(endpoint); 108 109 if (endpoint.getUriPattern() != null && endpoint.getUriPattern().length() > 0) { 110 attachUriPatternToRestlet(endpoint.getUriPattern(), endpoint, consumer.getRestlet()); 111 } 112 113 if (endpoint.getRestletUriPatterns() != null) { 114 for (String uriPattern : endpoint.getRestletUriPatterns()) { 115 attachUriPatternToRestlet(uriPattern, endpoint, consumer.getRestlet()); 116 } 117 } 118 } 119 120 public void disconnect(RestletConsumer consumer) throws Exception { 121 RestletEndpoint endpoint = (RestletEndpoint)consumer.getEndpoint(); 122 123 List<MethodBasedRouter> routers = new ArrayList<MethodBasedRouter>(); 124 125 if (endpoint.getUriPattern() != null && endpoint.getUriPattern().length() > 0) { 126 routers.add(getMethodRouter(endpoint.getUriPattern())); 127 } 128 129 if (endpoint.getRestletUriPatterns() != null) { 130 for (String uriPattern : endpoint.getRestletUriPatterns()) { 131 routers.add(getMethodRouter(uriPattern)); 132 } 133 } 134 135 for (MethodBasedRouter router : routers) { 136 if (endpoint.getRestletMethods() != null) { 137 Method[] methods = endpoint.getRestletMethods(); 138 for (Method method : methods) { 139 router.removeRoute(method); 140 } 141 } else { 142 router.removeRoute(endpoint.getRestletMethod()); 143 } 144 145 if (LOG.isDebugEnabled()) { 146 LOG.debug("Detached restlet uriPattern: " + router.getUriPattern() 147 + " method: " + endpoint.getRestletMethod()); 148 } 149 } 150 } 151 152 private MethodBasedRouter getMethodRouter(String uriPattern) { 153 synchronized (routers) { 154 MethodBasedRouter result = routers.get(uriPattern); 155 if (result == null) { 156 result = new MethodBasedRouter(uriPattern); 157 if (LOG.isDebugEnabled()) { 158 LOG.debug("Added method based router: " + result); 159 } 160 routers.put(uriPattern, result); 161 } 162 return result; 163 } 164 } 165 166 private void addServerIfNeccessary(RestletEndpoint endpoint) throws Exception { 167 String key = buildKey(endpoint); 168 Server server; 169 synchronized (servers) { 170 server = servers.get(key); 171 if (server == null) { 172 server = component.getServers().add(Protocol.valueOf(endpoint.getProtocol()), endpoint.getPort()); 173 servers.put(key, server); 174 if (LOG.isDebugEnabled()) { 175 LOG.debug("Added server: " + key); 176 } 177 server.start(); 178 } 179 } 180 } 181 182 private static String buildKey(RestletEndpoint endpoint) { 183 return endpoint.getHost() + ":" + endpoint.getPort(); 184 } 185 186 private void attachUriPatternToRestlet(String uriPattern, RestletEndpoint endpoint, Restlet target) { 187 MethodBasedRouter router = getMethodRouter(uriPattern); 188 189 Map<String, String> realm = endpoint.getRestletRealm(); 190 if (realm != null && realm.size() > 0) { 191 Guard guard = new Guard(component.getContext().createChildContext(), 192 ChallengeScheme.HTTP_BASIC, "Camel-Restlet Endpoint Realm"); 193 for (Map.Entry<String, String> entry : realm.entrySet()) { 194 guard.getSecrets().put(entry.getKey(), entry.getValue().toCharArray()); 195 } 196 guard.setNext(target); 197 target = guard; 198 if (LOG.isDebugEnabled()) { 199 LOG.debug("Target has been set to guard: " + guard); 200 } 201 } 202 203 if (endpoint.getRestletMethods() != null) { 204 Method[] methods = endpoint.getRestletMethods(); 205 for (Method method : methods) { 206 router.addRoute(method, target); 207 if (LOG.isDebugEnabled()) { 208 LOG.debug("Attached restlet uriPattern: " + uriPattern + " method: " + method); 209 } 210 } 211 } else { 212 router.addRoute(endpoint.getRestletMethod(), target); 213 if (LOG.isDebugEnabled()) { 214 LOG.debug("Attached restlet uriPattern: " + uriPattern + " method: " + endpoint.getRestletMethod()); 215 } 216 } 217 218 if (!router.hasBeenAttached()) { 219 component.getDefaultHost().attach(uriPattern, router); 220 if (LOG.isDebugEnabled()) { 221 LOG.debug("Attached methodRouter uriPattern: " + uriPattern); 222 } 223 } 224 } 225 226 } 227