001: /*
002: License $Id: JoPropertyServiceBuilder.java,v 1.10 2005/01/19 18:31:04 hendriks73 Exp $
003:
004: Copyright (c) 2001-2005 tagtraum industries.
005:
006: LGPL
007: ====
008:
009: jo! is free software; you can redistribute it and/or
010: modify it under the terms of the GNU Lesser General Public
011: License as published by the Free Software Foundation; either
012: version 2.1 of the License, or (at your option) any later version.
013:
014: jo! 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. See the GNU
017: Lesser General Public License for more details.
018:
019: You should have received a copy of the GNU Lesser General Public
020: License along with this library; if not, write to the Free Software
021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022:
023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
024:
025:
026: Sun license
027: ===========
028:
029: This release contains software by Sun Microsystems. Therefore
030: the following conditions have to be met, too. They apply to the
031: files
032:
033: - lib/mail.jar
034: - lib/activation.jar
035: - lib/jsse.jar
036: - lib/jcert.jar
037: - lib/jaxp.jar
038: - lib/crimson.jar
039: - lib/servlet.jar
040: - lib/jnet.jar
041: - lib/jaas.jar
042: - lib/jaasmod.jar
043:
044: contained in this release.
045:
046: a. Licensee may not modify the Java Platform
047: Interface (JPI, identified as classes contained within the javax
048: package or any subpackages of the javax package), by creating additional
049: classes within the JPI or otherwise causing the addition to or modification
050: of the classes in the JPI. In the event that Licensee creates any
051: Java-related API and distribute such API to others for applet or
052: application development, you must promptly publish broadly, an accurate
053: specification for such API for free use by all developers of Java-based
054: software.
055:
056: b. Software is confidential copyrighted information of Sun and
057: title to all copies is retained by Sun and/or its licensors. Licensee
058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
059: reverse engineer Software. Software may not be leased, assigned, or
060: sublicensed, in whole or in part. Software is not designed or intended
061: for use in on-line control of aircraft, air traffic, aircraft navigation
062: or aircraft communications; or in the design, construction, operation or
063: maintenance of any nuclear facility. Licensee warrants that it will not
064: use or redistribute the Software for such purposes.
065:
066: c. Software is provided "AS IS," without a warranty
067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
070:
071: d. This License is effective until terminated. Licensee may
072: terminate this License at any time by destroying all copies of Software.
073: This License will terminate immediately without notice from Sun if Licensee
074: fails to comply with any provision of this License. Upon such termination,
075: Licensee must destroy all copies of Software.
076:
077: e. Software, including technical data, is subject to U.S.
078: export control laws, including the U.S. Export Administration Act and its
079: associated regulations, and may be subject to export or import regulations
080: in other countries. Licensee agrees to comply strictly with all such
081: regulations and acknowledges that it has the responsibility to obtain
082: licenses to export, re-export, or import Software. Software may not be
083: downloaded, or otherwise exported or re-exported (i) into, or to a national
084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
087: Commerce Department's Table of Denial Orders.
088:
089:
090: Feedback
091: ========
092:
093: We encourage your feedback and suggestions and want to use your feedback to
094: improve the Software. Send all such feedback to:
095: <feedback@tagtraum.com>
096:
097: For more information on tagtraum industries and jo!
098: please see <http://www.tagtraum.com/>.
099:
100:
101: */
102: package com.tagtraum.jo.builder;
103:
104: import com.tagtraum.framework.log.C_Log;
105: import com.tagtraum.framework.log.Log;
106: import com.tagtraum.framework.log.LogFileWriter;
107: import com.tagtraum.framework.log.LogWriter;
108: import com.tagtraum.framework.recycler.Recycler;
109: import com.tagtraum.framework.server.I_SSLListener;
110: import com.tagtraum.framework.server.I_TCPListener;
111: import com.tagtraum.framework.util.*;
112: import com.tagtraum.jo.*;
113: import com.tagtraum.jo.security.I_JoAccessController;
114: import com.tagtraum.jo.security.I_JoAuthentificator;
115: import com.tagtraum.jo.security.I_JoRoleManager;
116:
117: import java.io.FileOutputStream;
118: import java.io.IOException;
119: import java.io.PrintStream;
120: import java.net.InetAddress;
121: import java.net.MalformedURLException;
122: import java.net.URL;
123: import java.net.UnknownHostException;
124: import java.util.*;
125:
126: /**
127: * Builds a service from property files.
128: *
129: * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
130: * @version 1.1beta1 $Id: JoPropertyServiceBuilder.java,v 1.10 2005/01/19 18:31:04 hendriks73 Exp $
131: */
132: public class JoPropertyServiceBuilder extends JoPropertyBuilder
133: implements I_JoServiceBuilder, C_Jo {
134:
135: /**
136: * Source-Version
137: */
138: public static String vcid = "$Id: JoPropertyServiceBuilder.java,v 1.10 2005/01/19 18:31:04 hendriks73 Exp $";
139: private I_JoHostBuilder hostBuilder;
140: private String serviceName;
141:
142: public boolean needsRebuild() {
143: return false;
144: }
145:
146: public void rebuild(Object obj) throws BuildException {
147: throw new BuildException(getClass().getName()
148: + ".rebuild() is not implemented.");
149: }
150:
151: public Object build() throws BuildException {
152: I_JoServletService service = null;
153: try {
154: Properties theProperties = loadProperties(new URL(getURL(),
155: "server.properties"));
156: service = buildService(getName(), theProperties, getURL());
157: buildListeners(new URL(getURL(), "listener.properties"),
158: service);
159: addMimeTypes(new URL(getURL(), "mime.properties"), service);
160: hostBuilder = (I_JoHostBuilder) Recycler.getNamedRecycler(
161: service.getName()).get(C_FactoryKey_HostBuilder);
162: hostBuilder.setService(service);
163: buildHosts(service, new URL(getURL(), "hosts.properties"));
164: } catch (BuildException be) {
165: throw be;
166: } catch (Throwable t) {
167: throw new BuildException(t);
168: }
169: return service;
170: }
171:
172: public void buildHosts(I_JoServletService service, URL aURL)
173: throws IOException, BuildException {
174: Properties properties = loadProperties(aURL);
175: Enumeration e = properties.propertyNames();
176: while (e.hasMoreElements()) {
177: String key = (String) e.nextElement();
178: if (key.endsWith(".hostnames")) {
179: int idx = key.indexOf('.');
180: String keyName = key.substring(0, idx);
181: if (idx + ".hostnames".length() == key.length()) {
182: hostBuilder.setName(keyName);
183: hostBuilder.setURL(aURL);
184: service.addHost((I_JoHost) hostBuilder.build());
185: }
186: }
187: }
188: }
189:
190: public I_JoServletService buildService(String aName,
191: Properties properties, URL baseURL) throws IOException,
192: FactoryException, BuildException {
193: serviceName = properties.getProperty(aName + ".name");
194: if (serviceName == null) {
195: serviceName = "jo";
196: Log.getLog(serviceName).log(
197: "Couldn't parse '" + aName
198: + ".name'. Using default value: "
199: + serviceName, C_Log.METHOD);
200: }
201:
202: // stderr
203: String theStdErr = properties.getProperty(aName + ".stderr");
204: URL theStdErrURL = new URL(baseURL, "stderr.log");
205: if (theStdErr != null) {
206: theStdErrURL = URLHelper.make(baseURL, StringHelper
207: .replaceWithSystemProperty(theStdErr));
208: System.setErr(new PrintStream(new FileOutputStream(
209: PlatformHelper.getOSSpecificPath(theStdErrURL
210: .getFile()), true), true));
211: }
212:
213: // stdout
214: String theStdOut = properties.getProperty(aName + ".stdout");
215: URL theStdOutURL = new URL(baseURL, "stdout.log");
216: if (theStdOut != null) {
217: theStdOutURL = URLHelper.make(baseURL, StringHelper
218: .replaceWithSystemProperty(theStdOut));
219: System.setOut(new PrintStream(new FileOutputStream(
220: PlatformHelper.getOSSpecificPath(theStdOutURL
221: .getFile()), true), true));
222: }
223:
224: // log
225: String theEventLogName = properties.getProperty(aName + ".log");
226: URL theLogURL = null;
227: if (theEventLogName == null) {
228: theLogURL = new URL(baseURL, "server.log");
229: } else if (!theEventLogName.equalsIgnoreCase("NONE")) {
230: theLogURL = URLHelper.make(baseURL, StringHelper
231: .replaceWithSystemProperty(theEventLogName));
232: }
233:
234: if (theLogURL != null) {
235: // logbuffer
236: int theLogBuffer = parseInt(aName + ".logbuffer",
237: properties.getProperty(aName + ".logbuffer"), 1);
238: try {
239: LogWriter theLogWriter = new LogFileWriter(
240: PlatformHelper.getOSSpecificPath(theLogURL
241: .getFile()), true, theLogBuffer);
242: Log.getLog(serviceName).addI_LogEventListener(
243: theLogWriter);
244: } catch (IOException ioe) {
245: Log.getLog(getName())
246: .log(
247: "Failed to create log for service "
248: + serviceName + ": " + ioe,
249: C_Log.ERROR);
250: }
251: }
252:
253: // loglevel
254: Log.getLog(serviceName).setLevel(
255: parseInt(aName + ".loglevel", properties
256: .getProperty(aName + ".loglevel"), Log.getLog(
257: serviceName).getLevel()));
258:
259: // version
260: int theMajorVersion = parseInt(aName + ".majorversion",
261: properties.getProperty(aName + ".majorversion"), 0);
262: int theMinorVersion = parseInt(aName + ".minorversion",
263: properties.getProperty(aName + ".minorversion"), 0);
264:
265: // Threads
266: int theMaxHandlerThreads = parseInt(aName
267: + ".maxhandlerthreads", properties.getProperty(aName
268: + ".maxhandlerthreads"), 50);
269: int theMinHandlerThreads = parseInt(aName
270: + ".minhandlerthreads", properties.getProperty(aName
271: + ".minhandlerthreads"), 5);
272:
273: // idle timeout for thread reduction
274: int theSoTimeout = parseInt(aName + ".so_timeout", properties
275: .getProperty(aName + ".so_timeout"), 30000);
276:
277: // keep alive
278: int theKeepAlive = parseInt(aName + ".keepalive", properties
279: .getProperty(aName + ".keepalive"), C_DefaultKeepAlive);
280:
281: // max requests per connection
282: int theMaxRequests = parseInt(aName + ".maxrequests",
283: properties.getProperty(aName + ".maxrequests"),
284: C_DefaultMaxRequests);
285:
286: // File Cache
287: int theMaxEntrySize = parseInt(aName + ".maxcacheentrysize",
288: properties.getProperty(aName + ".maxcacheentrysize"),
289: C_DefaultMaxEntrySize);
290: int theCacheCapacity = parseInt(aName + ".cachecapacity",
291: properties.getProperty(aName + ".cachecapacity"),
292: C_DefaultCacheCapacity);
293: int theStrongRefCapacity = parseInt(aName
294: + ".strongrefcapacity", properties.getProperty(aName
295: + ".strongrefcapacity"), C_DefaultStrongRefCapacity);
296:
297: // This feature does not work yet and is not documented
298: String userName = null;
299: String groupName = null;
300: if (System.getProperty("os.name").toLowerCase().indexOf("win") == -1) {
301: userName = properties.getProperty(aName + ".user");
302: Log.getLog(serviceName).log(
303: "Will try to set username to: " + userName,
304: C_Log.FORTYTWO);
305:
306: groupName = properties.getProperty(aName + ".group");
307: Log.getLog(serviceName).log(
308: "Will try to set groupname to: " + groupName,
309: C_Log.FORTYTWO);
310: }
311:
312: // handlerclass
313: String theHandlerClassname = properties.getProperty(aName
314: + ".handlerclassname");
315: if (theHandlerClassname == null) {
316: theHandlerClassname = C_FactoryKey_Handler;
317:
318: Log
319: .getLog(serviceName)
320: .log(
321: "Couldn't parse '"
322: + aName
323: + ".handlerclassname'. Using default value: "
324: + theHandlerClassname, C_Log.METHOD);
325: }
326:
327: // factory
328: String theFactoryURL = properties.getProperty(aName
329: + ".factory");
330: setFactory(serviceName, theFactoryURL, baseURL);
331:
332: // instantiate service
333: I_JoServletService service = (I_JoServletService) Recycler
334: .getNamedRecycler(serviceName).get(
335: C_FactoryKey_ServletService);
336: service.setBuilder(this );
337:
338: service.setName(serviceName);
339: service.setHandlerClassname(theHandlerClassname);
340: service.setMaxHandlerThreads(theMaxHandlerThreads);
341: service.setMinHandlerThreads(theMinHandlerThreads);
342: service.setSoTimeout(theSoTimeout);
343: service.setMajorVersion(theMajorVersion);
344: service.setMinorVersion(theMinorVersion);
345: service.setConfigURL(getURL());
346: service.setMaxRequests(theMaxRequests);
347: service.setKeepAlive(theKeepAlive);
348: setAuthentificators(properties, service);
349: service.setAccessController((I_JoAccessController) Recycler
350: .getNamedRecycler(service.getName()).get(
351: C_FactoryKey_AccessController));
352: service.setRoleManager((I_JoRoleManager) Recycler
353: .getNamedRecycler(service.getName()).get(
354: C_FactoryKey_RoleManager));
355: service.getFileCache().setCapacity(theCacheCapacity);
356: service.getFileCache().setMaxEntrySize(theMaxEntrySize);
357: service.getFileCache().setStrongRefCapacity(
358: theStrongRefCapacity);
359: service.setUserId(userName);
360: service.setGroupId(groupName);
361:
362: buildRequestInterceptors(properties, service);
363:
364: if (Log.getLog(service.getName()).isLog(C_Log.MODULE)) {
365: Log.getLog(service.getName()).log(
366: "Built service '" + serviceName + "'.",
367: C_Log.MODULE);
368: }
369:
370: return service;
371: }
372:
373: private void buildRequestInterceptors(Properties properties,
374: I_JoServletService service) {
375: SortedMap orderMap = new TreeMap();
376: for (Enumeration e = properties.keys(); e.hasMoreElements();) {
377: String key = (String) e.nextElement();
378: if (key.startsWith(service.getName()
379: + ".requestinterceptor.")) {
380: String name = key
381: .substring((service.getName() + ".requestinterceptor.")
382: .length());
383: if (name.indexOf('.') == -1) {
384: createRequestInterceptor(service, name, properties,
385: orderMap);
386: }
387: }
388: }
389: registerRequestInterceptorWithService(service, orderMap);
390: }
391:
392: private void createRequestInterceptor(I_JoServletService service,
393: String name, Properties properties, SortedMap orderMap) {
394: try {
395: // OK we got the name, now instantiate the thing
396: String classname = properties.getProperty(service.getName()
397: + ".requestinterceptor." + name);
398: RequestInterceptor requestInterceptor = (RequestInterceptor) Recycler
399: .getNamedRecycler(service.getName()).get(classname);
400: String parameters = properties.getProperty(service
401: .getName()
402: + ".requestinterceptor." + name + ".parameters");
403: Integer order = new Integer(properties.getProperty(service
404: .getName()
405: + ".requestinterceptor." + name + ".order"));
406: HashMap parameterMap = getRequestInterceptorParameters(
407: service, parameters, name);
408: requestInterceptor.init(new RequestInterceptorConfig(
409: service, name, parameterMap));
410: List orderList = (List) orderMap.get(order);
411: if (orderList == null)
412: orderList = new ArrayList();
413: orderList.add(requestInterceptor);
414: orderMap.put(order, orderList);
415: } catch (Exception ex) {
416: if (Log.getLog(service.getName()).isLog(C_Log.ERROR)) {
417: Log.getLog(service.getName()).log(
418: "Failed to initialize requestinterceptor "
419: + name, C_Log.ERROR);
420: Log.getLog(service.getName()).log(ex, C_Log.ERROR);
421: }
422: }
423: }
424:
425: private void registerRequestInterceptorWithService(
426: I_JoServletService service, SortedMap orderMap) {
427: for (Iterator i = orderMap.values().iterator(); i.hasNext();) {
428: List list = (List) i.next();
429: for (Iterator ri = list.iterator(); ri.hasNext();) {
430: service.addRequestInterceptor((RequestInterceptor) ri
431: .next());
432: }
433: }
434: }
435:
436: private HashMap getRequestInterceptorParameters(
437: I_JoServletService service, String parameters, String name) {
438: HashMap parameterMap = new HashMap();
439: if (parameters != null) {
440: StringTokenizer st = new StringTokenizer(parameters, ",");
441: while (st.hasMoreTokens()) {
442: String token = st.nextToken();
443: int idx = token.indexOf('=');
444: if (idx != -1 && idx < token.length() - 1) {
445: String parameterName = token.substring(0, idx);
446: String parameterValue = token.substring(idx + 1);
447: parameterMap.put(parameterName, parameterValue);
448: } else {
449: Log.getLog(service.getName()).log(
450: "Syntax error for requestinterceptor-parameters "
451: + service.getName()
452: + ".requestinterceptor." + name
453: + ".parameters: " + token,
454: C_Log.ERROR);
455: }
456: }
457: }
458: return parameterMap;
459: }
460:
461: private void setAuthentificators(Properties properties,
462: I_JoServletService service) throws FactoryException {
463: for (Enumeration e = properties.keys(); e.hasMoreElements();) {
464: String key = (String) e.nextElement();
465: if (key.startsWith(service.getName() + ".authentificator.")) {
466: String authMethod = key
467: .substring(key.lastIndexOf('.') + 1);
468: I_JoAuthentificator authentificator = (I_JoAuthentificator) Recycler
469: .getNamedRecycler(service.getName()).get(
470: properties.getProperty(key));
471: service.addAuthentificator(authMethod, authentificator);
472: }
473: }
474: }
475:
476: public void buildListeners(URL baseURL, I_JoServletService service)
477: throws FactoryException {
478: try {
479: Properties properties = loadProperties(baseURL);
480: for (Enumeration e = properties.propertyNames(); e
481: .hasMoreElements();) {
482: String key = (String) e.nextElement();
483: if (key.endsWith(".port")) {
484: int idx = key.indexOf('.');
485: String listenerName = key.substring(0, idx);
486: buildListener(properties, listenerName, service,
487: baseURL);
488: }
489: }
490: } catch (IOException ioe) {
491: Log.getLog(service.getName()).log(ioe, C_Log.ERROR);
492: }
493: }
494:
495: private void buildListener(Properties properties,
496: String listenerName, I_JoServletService service, URL baseURL)
497: throws UnknownHostException, FactoryException,
498: MalformedURLException {
499: String listenerClassname = properties.getProperty(listenerName
500: + ".classname");
501: if (listenerClassname == null || listenerClassname.equals("")) {
502: listenerClassname = C_FactoryKey_Listener;
503: }
504:
505: I_TCPListener listener = (I_TCPListener) Recycler
506: .getNamedRecycler(service.getName()).get(
507: listenerClassname);
508: listener.setName(listenerName);
509: listener.setPort(parseInt(listenerName + ".port", properties
510: .getProperty(listenerName + ".port"), 8080));
511: listener.setBacklog(parseInt(listenerName + ".backlog",
512: properties.getProperty(listenerName + ".backlog"), 50));
513: listener.setBindAddress(InetAddress.getByName(properties
514: .getProperty(listenerName + ".bindaddress")));
515: listener.setService(service);
516:
517: // special parameters for SSL
518: if (listener instanceof I_SSLListener) {
519: setSSLParameters((I_SSLListener) listener, baseURL,
520: properties);
521: }
522:
523: // register listener with service
524: service.addListener(listener);
525:
526: if (Log.getLog(service.getName()).isLog(C_Log.MODULE)) {
527: Log.getLog(service.getName()).log(
528: "Built listener '" + listenerName + "'.",
529: C_Log.MODULE);
530: }
531: }
532:
533: private void setSSLParameters(I_SSLListener listener, URL baseURL,
534: Properties properties) throws MalformedURLException {
535: Log.getLog(listener.getService().getName()).log(
536: "Setting parameters for SSL", C_Log.METHOD);
537: // passphrase
538: listener.setPassphrase(properties.getProperty(listener
539: .getName()
540: + ".passphrase"));
541: // protocol
542: listener.setProtocol(properties.getProperty(listener.getName()
543: + ".protocol"));
544: // keystoreURL
545: String keyStoreURLName = properties.getProperty(listener
546: .getName()
547: + ".keystore");
548: URL keyStoreURL = new URL(baseURL, "keys");
549: if (keyStoreURLName != null) {
550: keyStoreURL = new URL(baseURL, keyStoreURLName);
551: }
552: listener.setKeyStoreURL(keyStoreURL);
553:
554: // keystoreFormat
555: listener.setKeyStoreFormat(properties.getProperty(listener
556: .getName()
557: + ".keystoreformat", "JKS"));
558:
559: // needClientAuth
560: listener.setNeedClientAuth(new Boolean(properties
561: .getProperty(listener.getName() + ".needClientAuth"))
562: .booleanValue());
563: }
564:
565: public void addMimeTypes(URL aURL, I_JoServletService aService) {
566: try {
567: Properties theProperties = loadProperties(aURL);
568: Enumeration e = theProperties.propertyNames();
569: while (e.hasMoreElements()) {
570: String theKey = (String) e.nextElement();
571: aService.addMimeType(theKey, theProperties
572: .getProperty(theKey));
573: }
574: } catch (IOException ioe) {
575: Log.getLog(aService.getName()).log(ioe, C_Log.ERROR);
576: }
577: }
578:
579: public void setFactory(String name, String factoryURL, URL baseURL)
580: throws IOException, BuildException {
581: Hashtable aliases = null;
582: try {
583: if (factoryURL == null) {
584: factoryURL = C_FilenameFactory;
585: }
586: if (factoryURL.endsWith("/")) {
587: factoryURL += C_FilenameFactory;
588: }
589: aliases = (Hashtable) loadProperties(new URL(baseURL,
590: factoryURL));
591: } catch (Exception e) {
592: if (Log.isLog(name)) {
593: Log.getLog(name).log(
594: "Using default factory configuration file.",
595: C_Log.METHOD);
596: }
597: URL url = this .getClass().getClassLoader().getResource(
598: C_FilenameFactory);
599: if (url == null) {
600: throw new BuildException(
601: "Couldn't find factory definition file.");
602: }
603: aliases = (Hashtable) loadProperties(url);
604: }
605: Recycler.getNamedRecycler(name).addAliases(aliases);
606: }
607:
608: /**
609: * Help method for parsing int value in the property file.
610: */
611: private int parseInt(String name, String value, int defaultValue) {
612: int parsedValue = defaultValue;
613: if (value == null) {
614: Log.getLog(serviceName).log(
615: "'" + name + "' is not set. Using default value: "
616: + defaultValue, C_Log.METHOD);
617: } else {
618: try {
619: parsedValue = Integer.parseInt(value);
620: } catch (Exception e) {
621: Log.getLog(serviceName).log(
622: "Couldn't parse '" + name
623: + "'. Using default value: "
624: + defaultValue, C_Log.METHOD);
625: }
626: }
627: return parsedValue;
628: }
629: }
|