001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.resin;
031:
032: import com.caucho.config.program.ConfigProgram;
033: import java.io.*;
034: import java.net.*;
035: import java.util.*;
036:
037: import com.caucho.config.*;
038: import com.caucho.config.types.*;
039: import com.caucho.lifecycle.*;
040: import com.caucho.server.cluster.*;
041: import com.caucho.server.connection.*;
042: import com.caucho.server.host.*;
043: import com.caucho.server.http.*;
044: import com.caucho.server.port.*;
045: import com.caucho.server.resin.*;
046: import com.caucho.server.webapp.*;
047: import com.caucho.vfs.*;
048: import com.caucho.webbeans.context.*;
049:
050: /**
051: * Embeddable version of the Resin server.
052: *
053: * <code><pre>
054: * ResinEmbed resin = new ResinEmbed();
055: *
056: * HttpEmbed http = new HttpEmbed(8080);
057: * resin.addPort(http);
058: *
059: * WebAppEmbed webApp = new WebAppEmbed("/foo", "/home/ferg/ws/foo");
060: *
061: * resin.addWebApp(webApp);
062: *
063: * resin.start();
064: *
065: * resin.join();
066: * </pre></code>
067: */
068: public class ResinEmbed {
069: private static final String EMBED_CONF = "classpath:com/caucho/resin/resin-embed.xml";
070:
071: private Resin _resin = new Resin();
072: private Cluster _cluster;
073: private ClusterServer _clusterServer;
074: private Host _host;
075: private Server _server;
076:
077: private String _serverHeader;
078:
079: private final ArrayList<BeanEmbed> _beanList = new ArrayList<BeanEmbed>();
080:
081: private final ArrayList<WebAppEmbed> _webAppList = new ArrayList<WebAppEmbed>();
082:
083: private Lifecycle _lifecycle = new Lifecycle();
084:
085: /**
086: * Creates a new resin server.
087: */
088: public ResinEmbed() {
089: this (EMBED_CONF);
090: }
091:
092: /**
093: * Creates a new resin server.
094: */
095: public ResinEmbed(String configFile) {
096: try {
097: Config config = new Config();
098:
099: config.configure(_resin, Vfs.lookup(configFile));
100: } catch (Exception e) {
101: throw ConfigException.create(e);
102: }
103:
104: _cluster = _resin.findCluster("");
105: _clusterServer = _cluster.findServer("");
106: }
107:
108: //
109: // Configuration/Injection methods
110: //
111:
112: /**
113: * Adds a port to the server, e.g. a HTTP port.
114: *
115: * @param port the embedded port to add to the server
116: */
117: public void addPort(PortEmbed port) {
118: port.bindTo(_clusterServer);
119: }
120:
121: /**
122: * Sets a list of ports.
123: */
124: public void setPorts(PortEmbed[] ports) {
125: for (PortEmbed port : ports)
126: addPort(port);
127: }
128:
129: /**
130: * Sets the server header
131: */
132: public void setServerHeader(String serverName) {
133: _serverHeader = serverName;
134: }
135:
136: /**
137: * Adds a web-app to the server.
138: */
139: public void addWebApp(WebAppEmbed webApp) {
140: if (webApp == null)
141: throw new NullPointerException();
142:
143: _webAppList.add(webApp);
144: }
145:
146: /**
147: * Sets a list of webapps
148: */
149: public void setWebApps(WebAppEmbed[] webApps) {
150: for (WebAppEmbed webApp : webApps)
151: addWebApp(webApp);
152: }
153:
154: /**
155: * Adds a web bean.
156: */
157: public void addBean(BeanEmbed bean) {
158: _beanList.add(bean);
159:
160: if (_lifecycle.isActive()) {
161: Thread thread = Thread.currentThread();
162: ClassLoader oldLoader = thread.getContextClassLoader();
163:
164: try {
165: thread.setContextClassLoader(_server.getClassLoader());
166:
167: bean.configure();
168: } catch (RuntimeException e) {
169: throw e;
170: } catch (Throwable e) {
171: throw ConfigException.create(e);
172: } finally {
173: thread.setContextClassLoader(oldLoader);
174: }
175: }
176: }
177:
178: //
179: // Lifecycle
180: //
181:
182: /**
183: * Starts the embedded server
184: */
185: public void start() {
186: if (!_lifecycle.toActive())
187: return;
188:
189: Thread thread = Thread.currentThread();
190: ClassLoader oldLoader = thread.getContextClassLoader();
191:
192: try {
193: _resin.start();
194: _server = _resin.getServer();
195:
196: thread.setContextClassLoader(_server.getClassLoader());
197:
198: if (_serverHeader != null)
199: _server.setServerHeader(_serverHeader);
200:
201: for (BeanEmbed beanEmbed : _beanList) {
202: beanEmbed.configure();
203: }
204:
205: HostConfig hostConfig = new HostConfig();
206: _server.addHost(hostConfig);
207: _host = _server.getHost("", 0);
208:
209: thread.setContextClassLoader(_host.getClassLoader());
210:
211: for (WebAppEmbed webApp : _webAppList) {
212: WebAppConfig config = new WebAppConfig();
213: config.setContextPath(webApp.getContextPath());
214: config.setRootDirectory(new RawString(webApp
215: .getRootDirectory()));
216:
217: config.addBuilderProgram(new WebAppProgram(webApp));
218:
219: _host.addWebApp(config);
220: }
221: } catch (Exception e) {
222: throw ConfigException.create(e);
223: } finally {
224: thread.setContextClassLoader(oldLoader);
225: }
226: }
227:
228: /**
229: * Stops the embedded server
230: */
231: public void stop() {
232: if (!_lifecycle.toStop())
233: return;
234:
235: try {
236: _resin.stop();
237: } catch (RuntimeException e) {
238: throw e;
239: } catch (Throwable e) {
240: throw ConfigException.create(e);
241: }
242: }
243:
244: /**
245: * Waits for the Resin process to exit.
246: */
247: public void join() {
248: while (!_resin.isClosed()) {
249: try {
250: Thread.sleep(1000);
251: } catch (Exception e) {
252: }
253: }
254: }
255:
256: /**
257: * Destroys the embedded server
258: */
259: public void destroy() {
260: if (!_lifecycle.toDestroy())
261: return;
262:
263: try {
264: _resin.destroy();
265: } catch (RuntimeException e) {
266: throw e;
267: } catch (Throwable e) {
268: throw ConfigException.create(e);
269: }
270: }
271:
272: //
273: // Testing API
274: //
275:
276: /**
277: * Sends a HTTP request to the embedded server for testing.
278: *
279: * @param is input stream containing the HTTP request
280: * @param os output stream to receive the request
281: */
282: public void request(InputStream is, OutputStream os)
283: throws IOException {
284: start();
285:
286: TestConnection conn = createConnection();
287:
288: conn.request(is, os);
289: }
290:
291: /**
292: * Sends a HTTP request to the embedded server for testing.
293: *
294: * @param httpRequest HTTP request string, e.g. "GET /test.jsp"
295: * @param os output stream to receive the request
296: */
297: public void request(String httpRequest, OutputStream os)
298: throws IOException {
299: start();
300:
301: TestConnection conn = createConnection();
302:
303: conn.request(httpRequest, os);
304: }
305:
306: /**
307: * Sends a HTTP request to the embedded server for testing.
308: *
309: * @param httpRequest HTTP request string, e.g. "GET /test.jsp"
310: *
311: * @return the HTTP result string
312: */
313: public String request(String httpRequest) throws IOException {
314: start();
315:
316: TestConnection conn = createConnection();
317:
318: return conn.request(httpRequest);
319: }
320:
321: /**
322: * Creates a test connection to the server
323: */
324: private TestConnection createConnection() {
325: TestConnection conn = new TestConnection();
326:
327: return conn;
328: }
329:
330: protected void finalize() throws Throwable {
331: super .finalize();
332:
333: destroy();
334: }
335:
336: /**
337: * Basic embedding server.
338: */
339: public static void main(String[] args) throws Exception {
340: ResinEmbed resin = new ResinEmbed();
341:
342: for (int i = 0; i < args.length; i++) {
343: if (args[i].startsWith("--port=")) {
344: int port = Integer.parseInt(args[i].substring("--port="
345: .length()));
346:
347: HttpEmbed http = new HttpEmbed(port);
348: resin.addPort(http);
349: } else if (args[i].startsWith("--deploy:")) {
350: String valueString = args[i].substring("--deploy:"
351: .length());
352:
353: String[] values = valueString.split("[=,]");
354:
355: String role = null;
356:
357: for (int j = 0; j < values.length; j += 2) {
358: if (values[j].equals("role"))
359: role = values[j + 1];
360: }
361:
362: WebAppLocalDeployEmbed webApp = new WebAppLocalDeployEmbed();
363: if (role != null)
364: webApp.setRole(role);
365:
366: resin.addWebApp(webApp);
367: }
368: }
369:
370: resin.start();
371:
372: resin.join();
373: }
374:
375: /**
376: * Test HTTP connection
377: */
378: private class TestConnection {
379: StreamConnection _conn;
380: HttpRequest _request;
381: VfsStream _vfsStream;
382: ReadStream _readStream;
383: WriteStream _writeStream;
384: InetAddress _localAddress;
385: InetAddress _remoteAddress;
386: int _port = 6666;
387: char[] _chars = new char[1024];
388: byte[] _bytes = new byte[1024];
389:
390: TestConnection() {
391: _conn = new StreamConnection();
392: // _conn.setVirtualHost(_virtualHost);
393:
394: _request = new HttpRequest(_resin.getServer(), _conn);
395: _request.init();
396:
397: _vfsStream = new VfsStream(null, null);
398: _readStream = new ReadStream();
399: _writeStream = new WriteStream();
400:
401: // _conn.setSecure(_isSecure);
402:
403: try {
404: _localAddress = InetAddress.getByName("127.0.0.1");
405: _remoteAddress = InetAddress.getByName("127.0.0.1");
406: } catch (IOException e) {
407: }
408: }
409:
410: public HttpRequest getRequest() {
411: return _request;
412: }
413:
414: public void setVirtualHost(String virtualHost) {
415: _conn.setVirtualHost(virtualHost);
416: }
417:
418: public void setPort(int port) {
419: if (port > 0)
420: _port = port;
421: }
422:
423: public void setLocalIP(String ip) throws IOException {
424: _localAddress = InetAddress.getByName(ip);
425: }
426:
427: public void setRemoteIP(String ip) throws IOException {
428: _remoteAddress = InetAddress.getByName(ip);
429: }
430:
431: public void setSecure(boolean isSecure) {
432: _conn.setSecure(isSecure);
433: }
434:
435: public String request(String input) throws IOException {
436: OutputStream os = new ByteArrayOutputStream();
437:
438: request(input, os);
439:
440: return os.toString();
441: }
442:
443: public boolean allocateKeepalive() {
444: return true;
445: }
446:
447: public void request(String input, OutputStream os)
448: throws IOException {
449: ByteArrayInputStream is;
450:
451: int len = input.length();
452: if (_chars.length < len) {
453: _chars = new char[len];
454: _bytes = new byte[len];
455: }
456:
457: input.getChars(0, len, _chars, 0);
458: for (int i = 0; i < len; i++)
459: _bytes[i] = (byte) _chars[i];
460:
461: is = new ByteArrayInputStream(_bytes, 0, len);
462:
463: request(is, os);
464: }
465:
466: public void request(InputStream is, OutputStream os)
467: throws IOException {
468: Thread.yield();
469:
470: WriteStream out = Vfs.openWrite(os);
471: out.setDisableClose(true);
472:
473: ClassLoader oldLoader = Thread.currentThread()
474: .getContextClassLoader();
475: try {
476: _vfsStream.init(is, os);
477: _conn.setStream(is, os);
478: _conn.setLocalAddress(_localAddress);
479: _conn.setLocalPort(_port);
480: _conn.setRemoteAddress(_remoteAddress);
481: _conn.setRemotePort(9666);
482: // _conn.setSecure(_isSecure);
483:
484: try {
485: Thread.sleep(10);
486: } catch (Exception e) {
487: }
488:
489: while (_request.handleRequest()) {
490: out.flush();
491: }
492: } catch (EOFException e) {
493: } finally {
494: out.flush();
495:
496: Thread.currentThread().setContextClassLoader(oldLoader);
497: }
498: }
499:
500: public void close() {
501: }
502: }
503:
504: static class WebAppProgram extends ConfigProgram {
505: private final WebAppEmbed _config;
506:
507: WebAppProgram(WebAppEmbed webAppConfig) {
508: _config = webAppConfig;
509: }
510:
511: /**
512: * Configures the object.
513: */
514: @Override
515: public void inject(Object bean, ConfigContext env)
516: throws ConfigException {
517: _config.configure((WebApp) bean);
518: }
519: }
520: }
|