Source code: org/apache/slide/common/Domain.java
1 /*
2 * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/common/Domain.java,v 1.48.2.1 2004/09/29 15:01:26 unico Exp $
3 * $Revision: 1.48.2.1 $
4 * $Date: 2004/09/29 15:01:26 $
5 *
6 * ====================================================================
7 *
8 * Copyright 1999-2002 The Apache Software Foundation
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 */
23
24 package org.apache.slide.common;
25
26 import java.io.FileInputStream;
27 import java.io.InputStream;
28 import java.util.Enumeration;
29 import java.util.Hashtable;
30 import java.util.Properties;
31 import java.util.Vector;
32 import javax.xml.parsers.SAXParser;
33 import javax.xml.parsers.SAXParserFactory;
34 import org.apache.slide.authenticate.SecurityToken;
35 import org.apache.slide.store.Store;
36 import org.apache.slide.util.conf.Configuration;
37 import org.apache.slide.util.conf.ConfigurationElement;
38 import org.apache.slide.util.conf.ConfigurationException;
39 import org.apache.slide.util.conf.Populate;
40 import org.apache.slide.util.logger.Logger;
41 import org.apache.slide.event.EventDispatcher;
42 import org.apache.slide.extractor.ExtractorManager;
43 import org.xml.sax.InputSource;
44
45 /**
46 * The Domain controls access to its registered namespaces and performs
47 * initialization and connection management on behalf of the namespaces.
48 *
49 * <p>
50 * From the client application's perspective, the domain represents the only
51 * directly accessible object. It is through this object that the client
52 * gains access to namespaces, using the static method
53 * <code>Domain.accessNamespace()</code>.
54 * <p/>
55 * <p>
56 * Since the domain acts as the root of a directory service, it is a static
57 * entity and there can be only one domain per JVM.
58 * </p>
59 * <h3>Initialization</h3>
60 * <p>
61 * When Slide is first initialized, the Domain configuration is loaded.
62 * The location of the domain configuration file is given through the
63 * <code>org.apache.slide.domain</code> property in the Slide properties, or
64 * can be specified as argument to the static <code>Domain.init()</code>
65 * method.
66 * </p>
67 * <p>
68 * The domain configuration is written by an administrator and describes how
69 * each namespace is to be initialized. It includes information like:
70 * <ul>
71 * <li>
72 * The low-level services the namespace uses (structure store, content
73 * store, etc.)
74 * </li>
75 * <li>
76 * The namespace base topology, which includes the location of the base
77 * actions and paths in the namespace.
78 * </li>
79 * </ul>
80 * </p>
81 * <h3>Access and Security</h3>
82 * <p>
83 * After initialization is complete, the client application can request
84 * access to the domain. It uses one of the two methods:
85 * <ul>
86 * <li>
87 * {@link #accessNamespace Domain.accessNamespace(SecurityToken
88 securityObject, String namespace)}
89 * <br>
90 * Used to access a specific namespace. This method returns a
91 * <code>NamespaceAccessToken</code>, which thereafter must be used by
92 * the client application to perform operations on the namespace.
93 * <br><br>
94 * </li>
95 * <li>
96 * {@link #accessDomain Domain.accessDomain(SecurityToken
97 securityObject)}
98 * <br>
99 * Enumerates the registered namespaces with this domain. This allows
100 * application to browse the list of available namespaces.
101 * </li>
102 * </ul>
103 * </p>
104 * <p>
105 * The Domain uses an object (argument <code>securityObject</code>) to
106 * decide whether or not the client should be granted access. A good
107 * candidate is a reference to the client servlet or servlet context.<br><br>
108 * <i><small>Note: Currently, access control on namespaces is not
109 * implemented.</small></i>
110 * </p>
111 *
112 * @version $Revision: 1.48.2.1 $
113 */
114 public final class Domain {
115
116
117 // -------------------------------------------------------------- Constants
118
119
120 private final static String LOG_CHANNEL = Domain.class.getName();
121
122
123 // ----------------------------------------------------- Instance Variables
124
125
126 /**
127 * Compatibility with the new embedded domain.
128 */
129 private static EmbeddedDomain domain;
130
131
132 /**
133 * Namespaces hashtable.
134 */
135 private static Hashtable namespaces;
136
137 private static boolean namespacesInitialized = false;
138
139 /**
140 * Active namespaces hashtable.
141 */
142 private static Hashtable activeNamespaces;
143
144
145 /**
146 * Slide logger.
147 */
148 private static Logger logger;
149
150
151 /**
152 * Default namespace.
153 */
154 private static String defaultNamespace;
155
156
157 /**
158 * Domain parameters
159 */
160 private static Hashtable parameters;
161
162 // --------------------------------------------------------- Public Methods
163
164
165 /**
166 * Tests if the domain has been initialized before.
167 *
168 * @return boolean True if the domain has already been initialized
169 */
170 public static boolean isInitialized() {
171
172 return ((domain != null) || (namespaces != null));
173
174 }
175
176 /**
177 * Return true, if all namespaces have been initialized.
178 */
179 public static boolean namespacesAreInitialized() {
180 return namespacesInitialized;
181 }
182
183 /**
184 * Set the domain as having been initialized before.
185 */
186 public static void setInitialized(boolean initialized) {
187 if (initialized) {
188 if( namespaces == null ) namespaces = new Hashtable();
189 if( activeNamespaces == null ) activeNamespaces = new Hashtable();
190 if( parameters == null ) parameters = new Hashtable();
191
192 if (logger == null) {
193 logger = new org.apache.slide.util.logger.SimpleLogger();
194 logger.setLoggerLevel(Logger.INFO);
195 }
196
197 namespacesInitialized = true;
198 }
199 else {
200 // TODO: don't know what to do here ???
201 }
202 }
203
204
205 /**
206 * Return the default namespace of this domain.
207 *
208 * @return the name of the default namespace
209 */
210 public static String getDefaultNamespace() {
211
212 if (!isInitialized())
213 selfInit();
214
215 if (domain != null)
216 return domain.getDefaultNamespace();
217
218 return defaultNamespace;
219
220 }
221
222
223 /**
224 * Access a Namespace.
225 *
226 * @param token Entity which wants access
227 * @param namespaceName Name of the namespace on which access is requested
228 * @return NamespaceAccessToken Access token to the namespace
229 */
230 public static NamespaceAccessToken accessNamespace(SecurityToken token,
231 String namespaceName) {
232
233 if (!isInitialized())
234 selfInit();
235
236 if (domain != null)
237 return domain.getNamespaceToken(namespaceName);
238
239 Namespace namespace = (Namespace) namespaces.get(namespaceName);
240 if (namespace == null)
241 return null;
242 else
243 return new NamespaceAccessTokenImpl(namespace);
244
245 }
246
247
248 /**
249 * Enumerate namespace names.
250 */
251 public static Enumeration enumerateNamespaces() {
252
253 if (!isInitialized())
254 return (new Vector()).elements();
255
256 if (domain != null)
257 return domain.enumerateNamespaces();
258
259 return (namespaces.keys());
260
261 }
262
263
264 /**
265 * Close a namespace.
266 *
267 * @param token Namespace access token
268 */
269 public static void closeNamespace(NamespaceAccessToken token) {
270 token.disconnect();
271 activeNamespaces.remove(token.getName());
272 }
273
274
275 /**
276 * Clsose a namespace.
277 *
278 * @param token Entity which wants to close the namespace
279 * @param namespaceName Name of the namespace
280 */
281 public static void closeNamespace(SecurityToken token,
282 String namespaceName) {
283 try {
284 Namespace namespace = (Namespace) namespaces.get(namespaceName);
285 namespace.disconnectServices();
286 activeNamespaces.remove(namespaceName);
287 } catch(Exception e) {
288 }
289 }
290
291
292 /**
293 * Access a Domain.
294 *
295 * @param token Service who wants access
296 * @return DomainAccessToken Access token to the domain
297 */
298 public static DomainAccessToken accessDomain(SecurityToken token) {
299 // Not implemented
300 return null;
301 }
302
303 /**
304 * holds the expanded file name of domain.xml
305 **/
306 private static String domainFileName = "Domain.xml";
307
308 /**
309 * Access the file name of domain.xml.
310 *
311 * @return String the expanded file name as a string.
312 */
313 public static String getDomainFileName() {
314 return domainFileName;
315 }
316
317
318
319 /**
320 * Domain initialization routine using Avalon configuration parser.
321 *
322 * @param configurationURL The file name to read the configuration
323 */
324 public static void init(java.net.URL configurationURL) throws Exception {
325 if (isInitialized())
326 return;
327
328 domainFileName = configurationURL.getFile();
329 init(configurationURL.openStream());
330 }
331
332 /**
333 * Domain initialization routine using Avalon configuration parser.
334 *
335 * @param configurationFileName The file name to read the configuration
336 */
337 public static void init(String configurationFileName) throws Exception {
338 if (isInitialized())
339 return;
340
341 domainFileName = configurationFileName;
342 init(new FileInputStream(configurationFileName));
343 }
344
345
346 /**
347 * Domain initialization routine using Avalon configuration parser.
348 *
349 * @param configurationInputStream The file name to read the configuration
350 */
351 public static void init(InputStream configurationInputStream)
352 throws Exception {
353
354 if (isInitialized())
355 return;
356
357 SAXParserFactory factory = SAXParserFactory.newInstance();
358 factory.setNamespaceAware(false);
359 factory.setValidating(false);
360 SAXParser parser = factory.newSAXParser();
361 Populate pop = new Populate();
362 Configuration slideConfiguration =
363 new ConfigurationElement(pop.load(new InputSource
364 (configurationInputStream), parser.getXMLReader()));
365
366 Domain.init(slideConfiguration);
367
368 }
369
370
371 /**
372 * Domain initialization routine using Avalon configuration parser.
373 *
374 * @param configuration Avalon configuration object
375 */
376 public static void init(Configuration configuration) {
377
378 if (isInitialized())
379 return;
380
381 parameters = new Hashtable();
382
383 defaultNamespace = configuration.getAttribute("default", "slide");
384 parameters.put( "default", defaultNamespace );
385
386 String loggerClass = configuration.getAttribute
387 ("logger", "org.apache.slide.util.logger.SimpleLogger");
388 parameters.put("logger", loggerClass);
389
390 try {
391 logger = (Logger) (Class.forName(loggerClass).newInstance());
392 int loggerLevel = configuration.getAttributeAsInt("logger-level", Logger.INFO);
393 logger.setLoggerLevel(loggerLevel);
394 parameters.put("logger-level", "" + loggerLevel);
395 } catch (Exception e) {
396 if (logger == null) {
397 System.err.println("Slide domain: initialization of logger failed.");
398 e.printStackTrace();
399 } else {
400 error(e);
401 }
402 throw new DomainInitializationFailedError("Logger Problem: " + e.toString());
403 }
404
405 info("Initializing Domain");
406
407 namespaces = new Hashtable();
408 activeNamespaces = new Hashtable();
409
410 // Now initializing the domain
411
412 // Loading configuration
413 Properties properties =
414 org.apache.slide.util.Configuration.getDefault();
415 info("Domain configuration : " + properties.toString());
416
417 // Loading domain parameters
418 Enumeration parametersEnum =
419 configuration.getConfigurations("parameter");
420 while( parametersEnum.hasMoreElements() ) {
421 Configuration p = (Configuration)parametersEnum.nextElement();
422 parameters.put( p.getAttribute("name"), p.getValue() );
423 }
424 info( "Domain parameters: "+String.valueOf(parameters) );
425
426 // Loading namespaces
427 Enumeration namespaceDefinitions =
428 configuration.getConfigurations("namespace");
429
430 while (namespaceDefinitions.hasMoreElements()) {
431
432 initNamespace((Configuration) namespaceDefinitions.nextElement());
433
434 }
435
436 if (namespaces.isEmpty()) {
437 throw new DomainInitializationFailedError();
438 }
439
440 namespacesInitialized = true;
441
442 Enumeration extractorConfigurations = configuration.getConfigurations("extractors");
443 if ( extractorConfigurations.hasMoreElements() ) {
444 Configuration extractorConfiguration = (Configuration)extractorConfigurations.nextElement();
445 ExtractorManager.getInstance().configure(extractorConfiguration);
446 }
447
448 Enumeration eventConfigurations = configuration.getConfigurations("events");
449 if ( eventConfigurations.hasMoreElements() ) {
450 Configuration eventConfiguration = (Configuration)eventConfigurations.nextElement();
451 EventDispatcher.getInstance().configure(eventConfiguration);
452 }
453 }
454
455
456 // --------------------------------------------------------- Logger Methods
457
458
459 /**
460 * Log.
461 *
462 * @param data The object to log.
463 * @param channel The channel name used for logging.
464 * @param level The level used for logging.
465 */
466 public static void log(Object data, String channel, int level) {
467 logger.log(data, channel, level);
468 }
469
470
471 /**
472 * Log.
473 *
474 * @param data The object to log.
475 * @param level The level used for logging.
476 */
477 public static void log(Object data, int level) {
478 logger.log(data,LOG_CHANNEL, level);
479 }
480
481
482 /**
483 * Log.
484 *
485 * @param data The object to log.
486 */
487 public static void log(Object data) {
488 logger.log(data,LOG_CHANNEL,Logger.DEBUG);
489 }
490
491
492 /**
493 * Debug.
494 *
495 * @param data The object to log
496 */
497 public static void debug(Object data) {
498 log(data,LOG_CHANNEL, Logger.DEBUG);
499 }
500
501
502 /**
503 * Error.
504 *
505 * @param data The object to log
506 */
507 public static void error(Object data) {
508 log(data,LOG_CHANNEL, Logger.ERROR);
509 }
510
511
512 /**
513 * Error.
514 *
515 * @param data The object to log
516 * @param t Throwable object
517 */
518 public static void error(Object data, Throwable t) {
519 log(data + " - " + t.getMessage(),LOG_CHANNEL, Logger.ERROR);
520 log(t,LOG_CHANNEL, Logger.ERROR);
521 }
522
523
524 /**
525 * Info.
526 *
527 * @param data The object to log
528 */
529 public static void info(Object data) {
530 log(data,LOG_CHANNEL, Logger.INFO);
531 }
532
533
534 /**
535 * Warning.
536 *
537 * @param data The object to log
538 */
539 public static void warn(Object data) {
540 log(data,LOG_CHANNEL, Logger.WARNING);
541 }
542
543
544 /**
545 * Check if the channel with the specified level is enabled for logging.
546 * This implementation ignores the channel specification
547 *
548 * @param channel The channel specification
549 * @param level The level specification
550 */
551 public static boolean isEnabled(String channel, int level) {
552 return logger.isEnabled(channel, level);
553 }
554
555
556 /**
557 * Check if the default channel with the specified level is enabled for
558 * logging.
559 *
560 * @param level The level specification
561 */
562 public static boolean isEnabled(int level) {
563 return logger.isEnabled(LOG_CHANNEL,level);
564 }
565
566
567 /**
568 * Check if the default channel with the DEBUG level is enabled for
569 * logging.
570 */
571 public static boolean isDebugEnabled() {
572 return isEnabled(LOG_CHANNEL,Logger.DEBUG);
573 }
574
575
576 /**
577 * Check if the default channel with the WARNING level is enabled for
578 * logging.
579 */
580 public static boolean isWarningEnabled() {
581 return isEnabled(LOG_CHANNEL,Logger.WARNING);
582 }
583
584
585 /**
586 * Check if the default channel with the INFO level is enabled for logging.
587 */
588 public static boolean isInfoEnabled() {
589 return isEnabled(LOG_CHANNEL,Logger.INFO);
590 }
591
592
593 /**
594 * Check if the default channel with the ERROR level is enabled for
595 * logging.
596 */
597 public static boolean isErrorEnabled() {
598 return isEnabled(LOG_CHANNEL,Logger.ERROR);
599 }
600
601
602 // -------------------------------------------------------- Package Methods
603
604
605 /**
606 * Set the embedded domain field.
607 */
608 static void setDomain(EmbeddedDomain domain) {
609 Domain.domain = domain;
610 }
611
612
613 /**
614 * Start domain (doesn't do anything yet).
615 */
616 static void start()
617 throws Exception {
618 }
619
620
621 /**
622 * Stop domain.
623 */
624 static void stop()
625 throws Exception {
626
627 Enumeration active = activeNamespaces.elements();
628 while (active.hasMoreElements()) {
629 ((Namespace) active.nextElement()).disconnectServices();
630 }
631
632 }
633
634
635 /**
636 * Add a namespace to the domain.
637 *
638 * @param namespace Namespace to be added
639 */
640 static void addNamespace(Namespace namespace) {
641 namespaces.put(namespace.getName(), namespace);
642 activeNamespaces.put(namespace.getName(), namespace);
643 }
644
645
646 /**
647 * Get a namespace.
648 *
649 * @param namespaceName Name of the namespace
650 * @return Namespace
651 */
652 static Namespace getNamespace(String namespaceName) {
653 return (Namespace) namespaces.get(namespaceName);
654 }
655
656
657 /**
658 * Get a domain parameter.
659 * @param name the parameter name
660 * @return the parameter value
661 */
662 public static String getParameter( String name ) {
663 return (String)parameters.get( name );
664 }
665
666
667 /**
668 * Get a domain parameter.
669 * @param name the parameter name
670 * @param defaultValue the default value to be returned
671 * @return the parameter value
672 */
673 public static String getParameter( String name, String defaultValue ) {
674 String result = (String)parameters.get( name );
675 if( result == null )
676 result = defaultValue;
677 return result;
678 }
679
680 /**
681 * Get a domain parameter - possibly overlaid by a store specific value.
682 *
683 * @param name the parameter name
684 * @param defaultValue the default value
685 * @param store the store to check for store-specific values
686 *
687 * @return the parameter value
688 *
689 */
690 public static String getParameter(String name, String defaultValue, Store store) {
691 String result = (String)store.getParameter(name);
692 if (result == null) {
693 result = (String)parameters.get(name);
694 if (result == null)
695 result = defaultValue;
696 }
697 return result;
698 }
699
700 /**
701 * Set the specified parameters
702 *
703 * @param parameters the parameters
704 *
705 */
706 static void setParameters( Hashtable parameters ) {
707 Domain.parameters = parameters;
708 }
709
710 /**
711 * Set the logger to be used by Slide.
712 *
713 * @param logger Logger the domain will use
714 */
715 static void setLogger(Logger logger) {
716 Domain.logger = logger;
717 }
718
719
720 /**
721 * Get the Domain logger.
722 *
723 * @return The domain logger
724 */
725 static Logger getLogger() {
726 return Domain.logger;
727 }
728
729
730 /**
731 * Default initialization of the domain.
732 */
733 static void selfInit() {
734
735 String loggerClass = "org.apache.slide.util.logger.SimpleLogger";
736
737 if (logger == null) {
738 try {
739 logger = (Logger)(Class.forName(loggerClass).newInstance());
740 logger.setLoggerLevel(Logger.INFO);
741 }
742 catch (Exception e) {
743 error(e);
744 throw new DomainInitializationFailedError
745 ("Logger Problem: " + e.toString());
746 }
747 }
748
749 info("Auto-Initializing Domain");
750
751 // Now initializing the domain
752
753 // Loading configuration
754 Properties configuration =
755 org.apache.slide.util.Configuration.getDefault();
756 info("Domain configuration : " + configuration.toString());
757
758 // First, retrieve the domain XML definition file from
759 // the configuration
760 String fileName =
761 org.apache.slide.util.Configuration.getDefault().getProperty
762 (org.apache.slide.util.Configuration.Property.DomainInitFilename,
763 "Domain.xml");
764
765 try {
766 SAXParserFactory factory = SAXParserFactory.newInstance();
767 factory.setNamespaceAware(false);
768 factory.setValidating(false);
769 SAXParser parser = factory.newSAXParser();
770
771 FileInputStream is = new FileInputStream(fileName);
772 //init(reader);
773 Populate pop = new Populate();
774 Configuration slideConfiguration =
775 new ConfigurationElement(pop.load(new InputSource(is),
776 parser.getXMLReader()));
777
778 init(slideConfiguration);
779
780 } catch (javax.xml.parsers.FactoryConfigurationError e) {
781 throw new DomainInitializationFailedError(e.getMessage());
782 } catch (Exception e) {
783 throw new DomainInitializationFailedError(e.getMessage());
784 }
785
786 info("Domain initialization complete");
787
788 }
789
790
791 // -------------------------------------------------------- Private Methods
792
793
794 /**
795 * Initializes a new namespace based on the given configuration data.
796 *
797 * @param configuration Configuration object
798 */
799 private static void initNamespace(Configuration configuration) {
800
801 try {
802
803 try {
804 info("Initializing namespace : "
805 + configuration.getAttribute("name"));
806 } catch (ConfigurationException e) {
807 error(e);
808 }
809
810 String loggerClass = configuration.getAttribute
811 ("logger", null);
812
813 Logger namespaceLogger = null;
814 if (loggerClass==null) {
815 // if there is no logger defined on the namespace
816 // use the domain logger
817 namespaceLogger=logger;
818 }
819 else {
820 try {
821 namespaceLogger =
822 (Logger) (Class.forName(loggerClass).newInstance());
823 namespaceLogger.setLoggerLevel(configuration.getAttributeAsInt
824 ("logger-level", Logger.INFO));
825 } catch (Exception e) {
826 error(e);
827 }
828 }
829
830 Namespace namespace = new Namespace();
831 namespace.setName(configuration.getAttribute("name"));
832 namespace.setLogger(namespaceLogger);
833
834 Configuration namespaceConfigurationDefinition =
835 configuration.getConfiguration("configuration");
836 namespace.loadParameters(namespaceConfigurationDefinition);
837
838 Configuration namespaceDefinition =
839 configuration.getConfiguration("definition");
840 namespace.loadDefinition(namespaceDefinition);
841 addNamespace(namespace);
842 try {
843 Configuration namespaceBaseDataDefinition =
844 configuration.getConfiguration("data");
845 namespace.loadBaseData(namespaceBaseDataDefinition);
846 } catch (ConfigurationException e) {
847 info("No basedata found for the namespace");
848 }
849
850 namespace.loadConfiguration(namespaceConfigurationDefinition);
851
852 try {
853 Configuration namespaceExtractorsDefinition =
854 configuration.getConfiguration("extractors");
855 namespace.loadExtractors(namespaceExtractorsDefinition);
856 } catch (ConfigurationException e) {
857 // ignore
858 }
859
860 // preparation to add services, please ignore now
861 try {
862 Configuration services = configuration.getConfiguration("services");
863 Enumeration s = services.getConfigurations("service");
864 while (s.hasMoreElements()) {
865 Configuration service = (Configuration)s.nextElement();
866 System.out.println("&&&&&&Name = " + service.getName());
867 System.out.println("&&&&&&className = " + service.getAttribute("classname"));
868 System.out.println("&&&&&&serviceName = " + service.getAttribute("name"));
869 Enumeration s_pars = service.getConfigurations("parameter");
870 while (s_pars.hasMoreElements()) {
871 Configuration s_par = (Configuration)s_pars.nextElement();
872 System.out.println("&&&&&&PAR Name = " + s_par.getName());
873 System.out.println("&&&&&&PAR Name = " + s_par.getAttribute("name"));
874 System.out.println("&&&&&&Par Val = " + s_par.getValue());
875 }
876 }
877 }
878 catch (ConfigurationException e){
879 // silently ignore it ==> no services
880 }
881 catch (Exception e){
882 error(e);
883 }
884 // preparation to add services, please ignore now
885
886
887
888 info("Namespace configuration complete");
889
890 } catch (Throwable t) {
891 error(t);
892 }
893
894 }
895
896
897 /**
898 * Constructor
899 *
900 */
901 }
902