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.HashMap; 021 import java.util.Map; 022 023 import org.apache.camel.Endpoint; 024 import org.apache.camel.Exchange; 025 import org.apache.camel.HeaderFilterStrategyAware; 026 import org.apache.camel.impl.DefaultComponent; 027 import org.apache.camel.spi.HeaderFilterStrategy; 028 import org.apache.camel.util.CamelContextHelper; 029 import org.apache.camel.util.URISupport; 030 import org.apache.camel.util.UnsafeUriCharactersEncoder; 031 import org.apache.commons.logging.Log; 032 import org.apache.commons.logging.LogFactory; 033 import org.restlet.Component; 034 import org.restlet.Guard; 035 import org.restlet.Restlet; 036 import org.restlet.Server; 037 import org.restlet.data.ChallengeScheme; 038 import org.restlet.data.Method; 039 import org.restlet.data.Protocol; 040 041 /** 042 * A Camel component embedded Restlet that produces and consumes exchanges. 043 * 044 * @version $Revision: 743835 $ 045 */ 046 public class RestletComponent extends DefaultComponent<Exchange> implements HeaderFilterStrategyAware { 047 private static final Log LOG = LogFactory.getLog(RestletComponent.class); 048 049 private final Map<String, Server> servers = new HashMap<String, Server>(); 050 private final Map<String, MethodBasedRouter> routers = new HashMap<String, MethodBasedRouter>(); 051 private final Component component = new Component(); 052 private HeaderFilterStrategy headerFilterStrategy = new RestletHeaderFilterStrategy(); 053 054 @Override 055 @SuppressWarnings("unchecked") 056 protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception { 057 058 RestletBinding restletBinding = null; 059 // lookup binding in registry if provided 060 String ref = getAndRemoveParameter(parameters, "restletBindingRef", String.class); 061 if (ref != null) { 062 restletBinding = CamelContextHelper.mandatoryLookup(getCamelContext(), ref, RestletBinding.class); 063 } 064 065 if (restletBinding == null) { 066 restletBinding = new DefaultRestletBinding(); 067 } 068 069 if (restletBinding instanceof HeaderFilterStrategyAware) { 070 ((HeaderFilterStrategyAware)restletBinding).setHeaderFilterStrategy(headerFilterStrategy); 071 } 072 073 Map<String, String> realm = null; 074 ref = getAndRemoveParameter(parameters, "restletRealmRef", String.class); 075 if (ref != null) { 076 realm = CamelContextHelper.mandatoryLookup(getCamelContext(), ref, Map.class); 077 } 078 079 Method method = getAndRemoveParameter(parameters, "restletMethod", Method.class); 080 081 // construct URI so we can use it to get the splitted information 082 URI u = new URI(UnsafeUriCharactersEncoder.encode(remaining)); 083 String protocol = u.getScheme(); 084 085 String uriPattern = u.getPath(); 086 if (parameters.size() > 0) { 087 uriPattern = uriPattern + "?" + URISupport.createQueryString(parameters); 088 } 089 090 int port = 0; 091 String host = u.getHost(); 092 if (u.getPort() > 0) { 093 port = u.getPort(); 094 } 095 096 RestletEndpoint result = new RestletEndpoint(this, remaining, restletBinding); 097 result.setProtocol(protocol); 098 result.setUriPattern(uriPattern); 099 result.setHost(host); 100 if (port > 0) { 101 result.setPort(port); 102 } 103 if (method != null) { 104 result.setRestletMethod(method); 105 } 106 if (realm != null) { 107 result.setRealm(realm); 108 } 109 110 return result; 111 } 112 113 @Override 114 protected void doStart() throws Exception { 115 super.doStart(); 116 component.start(); 117 } 118 119 @Override 120 protected void doStop() throws Exception { 121 component.stop(); 122 // just clear maps, component will stop the servers and routes 123 servers.clear(); 124 routers.clear(); 125 super.doStop(); 126 } 127 128 public HeaderFilterStrategy getHeaderFilterStrategy() { 129 return headerFilterStrategy; 130 } 131 132 public void setHeaderFilterStrategy(HeaderFilterStrategy strategy) { 133 this.headerFilterStrategy = strategy; 134 } 135 136 public void connect(RestletConsumer consumer) throws Exception { 137 RestletEndpoint endpoint = (RestletEndpoint)consumer.getEndpoint(); 138 addServerIfNeccessary(endpoint); 139 MethodBasedRouter router = getMethodRouter(endpoint.getUriPattern()); 140 141 Map<String, String> realm = endpoint.getRealm(); 142 Restlet target = consumer.getRestlet(); 143 if (realm != null && realm.size() > 0) { 144 Guard guard = new Guard(component.getContext().createChildContext(), 145 ChallengeScheme.HTTP_BASIC, "Camel-Restlet Endpoint Realm"); 146 for (Map.Entry<String, String> entry : realm.entrySet()) { 147 guard.getSecrets().put(entry.getKey(), entry.getValue().toCharArray()); 148 } 149 guard.setNext(target); 150 target = guard; 151 if (LOG.isDebugEnabled()) { 152 LOG.debug("Target has been set to guard: " + guard); 153 } 154 } 155 156 router.addRoute(endpoint.getRestletMethod(), target); 157 158 if (!router.hasBeenAttached()) { 159 component.getDefaultHost().attach(endpoint.getUriPattern(), router); 160 if (LOG.isDebugEnabled()) { 161 LOG.debug("Attached methodRouter uriPattern: " + endpoint.getUriPattern()); 162 } 163 } 164 165 if (LOG.isDebugEnabled()) { 166 LOG.debug("Attached restlet uriPattern: " + endpoint.getUriPattern() + " method: " + endpoint.getRestletMethod()); 167 } 168 } 169 170 public void disconnect(RestletConsumer consumer) throws Exception { 171 RestletEndpoint endpoint = (RestletEndpoint)consumer.getEndpoint(); 172 MethodBasedRouter router = getMethodRouter(endpoint.getUriPattern()); 173 router.removeRoute(endpoint.getRestletMethod()); 174 175 if (LOG.isDebugEnabled()) { 176 LOG.debug("Detached restlet uriPattern: " + endpoint.getUriPattern() + " method: " + endpoint.getRestletMethod()); 177 } 178 } 179 180 private MethodBasedRouter getMethodRouter(String uriPattern) { 181 synchronized (routers) { 182 MethodBasedRouter result = routers.get(uriPattern); 183 if (result == null) { 184 result = new MethodBasedRouter(uriPattern); 185 if (LOG.isDebugEnabled()) { 186 LOG.debug("Added method based router: " + result); 187 } 188 routers.put(uriPattern, result); 189 } 190 return result; 191 } 192 } 193 194 private void addServerIfNeccessary(RestletEndpoint endpoint) throws Exception { 195 String key = buildKey(endpoint); 196 Server server; 197 synchronized (servers) { 198 server = servers.get(key); 199 if (server == null) { 200 server = component.getServers().add(Protocol.valueOf(endpoint.getProtocol()), endpoint.getPort()); 201 servers.put(key, server); 202 if (LOG.isDebugEnabled()) { 203 LOG.debug("Added server: " + key); 204 } 205 server.start(); 206 } 207 } 208 } 209 210 private static String buildKey(RestletEndpoint endpoint) { 211 return endpoint.getHost() + ":" + endpoint.getPort(); 212 } 213 214 } 215