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.cometd;
018
019 import java.util.HashMap;
020 import java.util.Map;
021
022 import org.apache.camel.Endpoint;
023 import org.apache.camel.impl.DefaultComponent;
024 import org.apache.commons.logging.Log;
025 import org.apache.commons.logging.LogFactory;
026 import org.mortbay.cometd.AbstractBayeux;
027 import org.mortbay.cometd.continuation.ContinuationCometdServlet;
028 import org.mortbay.jetty.Connector;
029 import org.mortbay.jetty.Server;
030 import org.mortbay.jetty.handler.ContextHandlerCollection;
031 import org.mortbay.jetty.nio.SelectChannelConnector;
032 import org.mortbay.jetty.security.SslSocketConnector;
033 import org.mortbay.jetty.servlet.Context;
034 import org.mortbay.jetty.servlet.ServletHolder;
035
036 /**
037 * Component for Jetty Cometd
038 *
039 * @version $Revision:520964 $
040 */
041 public class CometdComponent extends DefaultComponent {
042 private static final transient Log LOG = LogFactory.getLog(CometdComponent.class);
043
044 private final Map<String, ConnectorRef> connectors = new HashMap<String, ConnectorRef>();
045
046 private Server server;
047 private String sslKeyPassword;
048 private String sslPassword;
049 private String sslKeystore;
050 private SslSocketConnector sslSocketConnector;
051
052 class ConnectorRef {
053 Connector connector;
054 ContinuationCometdServlet servlet;
055 int refCount;
056
057 public ConnectorRef(Connector connector,
058 ContinuationCometdServlet servlet) {
059 this.connector = connector;
060 this.servlet = servlet;
061 increment();
062 }
063
064 public int increment() {
065 return ++refCount;
066 }
067
068 public int decrement() {
069 return --refCount;
070 }
071 }
072
073 public CometdComponent() {
074 }
075
076 @Override
077 protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
078 setProperties(this, parameters);
079 return new CometdEndpoint(this, uri, remaining, parameters);
080 }
081
082 /**
083 * Connects the URL specified on the endpoint to the specified processor.
084 */
085 public void connect(CometdProducerConsumer prodcon) throws Exception {
086 // Make sure that there is a connector for the requested endpoint.
087 CometdEndpoint endpoint = (CometdEndpoint) prodcon.getEndpoint();
088 String connectorKey = endpoint.getProtocol() + ":" + endpoint.getUri().getHost() + ":" + endpoint.getPort();
089
090 synchronized (connectors) {
091 ConnectorRef connectorRef = connectors.get(connectorKey);
092 if (connectorRef == null) {
093 Connector connector;
094 if ("cometds".equals(endpoint.getProtocol())) {
095 connector = getSslSocketConnector();
096 } else {
097 connector = new SelectChannelConnector();
098 }
099 connector.setPort(endpoint.getPort());
100 connector.setHost(endpoint.getUri().getHost());
101 if ("localhost".equalsIgnoreCase(endpoint.getUri().getHost())) {
102 LOG.warn("You use localhost interface! It means that no external connections will be available."
103 + " Don't you want to use 0.0.0.0 instead (all network interfaces)?");
104 }
105 getServer().addConnector(connector);
106
107 ContinuationCometdServlet servlet = createServletForConnector(connector, endpoint);
108 connectorRef = new ConnectorRef(connector, servlet);
109 connector.start();
110
111 connectors.put(connectorKey, connectorRef);
112 } else {
113 connectorRef.increment();
114 }
115 AbstractBayeux bayeux = connectorRef.servlet.getBayeux();
116 bayeux.setJSONCommented(endpoint.isJsonCommented());
117 prodcon.setBayeux(bayeux);
118 }
119 }
120
121 /**
122 * Disconnects the URL specified on the endpoint from the specified
123 * processor.
124 */
125 public void disconnect(CometdProducerConsumer prodcon) throws Exception {
126 CometdEndpoint endpoint = prodcon.getEndpoint();
127
128 String connectorKey = endpoint.getProtocol() + ":" + endpoint.getUri().getHost() + ":" + endpoint.getPort();
129
130 synchronized (connectors) {
131 ConnectorRef connectorRef = connectors.get(connectorKey);
132 if (connectorRef != null) {
133 if (connectorRef.decrement() == 0) {
134 getServer().removeConnector(connectorRef.connector);
135 connectorRef.connector.stop();
136 connectors.remove(connectorKey);
137 }
138 }
139 }
140 }
141
142 protected ContinuationCometdServlet createServletForConnector(Connector connector, CometdEndpoint endpoint) throws Exception {
143 ContinuationCometdServlet servlet = new ContinuationCometdServlet();
144
145 Context context = new Context(server, "/", Context.NO_SECURITY | Context.NO_SESSIONS);
146 context.setConnectorNames(new String[] {connector.getName()});
147
148 ServletHolder holder = new ServletHolder();
149 holder.setServlet(servlet);
150 context.setResourceBase(endpoint.getResourceBase());
151 context.addServlet(holder, "/cometd/*");
152 context.addServlet("org.mortbay.jetty.servlet.DefaultServlet", "/");
153
154 connector.start();
155 context.start();
156
157 holder.setInitParameter("timeout", Integer.toString(endpoint.getTimeout()));
158 holder.setInitParameter("interval", Integer.toString(endpoint.getInterval()));
159 holder.setInitParameter("maxInterval", Integer.toString(endpoint.getMaxInterval()));
160 holder.setInitParameter("multiFrameInterval", Integer.toString(endpoint.getMultiFrameInterval()));
161 holder.setInitParameter("JSONCommented", Boolean.toString(endpoint.isJsonCommented()));
162 holder.setInitParameter("logLevel", Integer.toString(endpoint.getLogLevel()));
163
164 return servlet;
165 }
166
167 public synchronized SslSocketConnector getSslSocketConnector() {
168 if (sslSocketConnector == null) {
169 sslSocketConnector = new SslSocketConnector();
170 // with default null values, jetty ssl system properties
171 // and console will be read by jetty implementation
172 sslSocketConnector.setPassword(sslPassword);
173 sslSocketConnector.setKeyPassword(sslKeyPassword);
174 if (sslKeystore != null) {
175 sslSocketConnector.setKeystore(sslKeystore);
176 }
177 }
178 return sslSocketConnector;
179 }
180
181 public Server getServer() throws Exception {
182 if (server == null) {
183 server = createServer();
184 }
185 return server;
186 }
187
188 public void setServer(Server server) {
189 this.server = server;
190 }
191
192 public String getSslKeyPassword() {
193 return sslKeyPassword;
194 }
195
196 public String getSslPassword() {
197 return sslPassword;
198 }
199
200 public String getSslKeystore() {
201 return sslKeystore;
202 }
203
204 public void setSslKeyPassword(String sslKeyPassword) {
205 this.sslKeyPassword = sslKeyPassword;
206 }
207
208 public void setSslPassword(String sslPassword) {
209 this.sslPassword = sslPassword;
210 }
211
212 public void setSslKeystore(String sslKeystore) {
213 this.sslKeystore = sslKeystore;
214 }
215
216 protected Server createServer() throws Exception {
217 Server server = new Server();
218 ContextHandlerCollection collection = new ContextHandlerCollection();
219 collection.setServer(server);
220 server.addHandler(collection);
221 server.start();
222
223 return server;
224 }
225
226 @Override
227 protected void doStop() throws Exception {
228 for (ConnectorRef connectorRef : connectors.values()) {
229 connectorRef.connector.stop();
230 }
231 connectors.clear();
232
233 if (server != null) {
234 server.stop();
235 }
236 super.doStop();
237 }
238
239 @Override
240 protected void doStart() throws Exception {
241 super.doStart();
242 }
243
244 }