001    package org.apache.fulcrum.yaafi.framework.factory;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.io.File;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.util.Enumeration;
026    import java.util.Hashtable;
027    
028    import org.apache.avalon.framework.configuration.Configuration;
029    import org.apache.avalon.framework.configuration.DefaultConfiguration;
030    import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
031    import org.apache.avalon.framework.context.Context;
032    import org.apache.avalon.framework.context.DefaultContext;
033    import org.apache.avalon.framework.logger.ConsoleLogger;
034    import org.apache.avalon.framework.logger.Logger;
035    import org.apache.avalon.framework.service.ServiceManager;
036    import org.apache.fulcrum.yaafi.framework.constant.AvalonMerlinConstants;
037    import org.apache.fulcrum.yaafi.framework.container.ServiceConstants;
038    import org.apache.fulcrum.yaafi.framework.util.InputStreamLocator;
039    import org.apache.fulcrum.yaafi.framework.util.Validate;
040    import org.apache.fulcrum.yaafi.framework.crypto.CryptoStreamFactory;
041    
042    /**
043     * Helper class to capture configuration related stuff. The are two ways
044     * for setting up the configuration:
045     * <ul>
046     *  <li>set all parameters manually</li>
047     *  <li>use a containerConfiguration file and provide the remaining settings</li>
048     * </ul>
049     *
050     * The Avalon context and configuration are created by
051     * <ul>
052     *  <li>createFinalContext()</li>
053     *  <li>createFinalConfiguration()</li>
054     * </ul>
055     *
056     *  @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
057     */
058    
059    public class ServiceContainerConfiguration
060    {
061        /** our default implementation class of the service container */
062        private String serviceContainerClazzName;
063    
064        /** the location of the component role file */
065        private String componentRolesLocation;
066    
067        /** is the component role file encrypted? */
068        private String isComponentRolesEncrypted;
069    
070        /** the location of the component configuration file */
071        private String componentConfigurationLocation;
072    
073        /** is the component configuration file encrypted? */
074        private String isComponentConfigurationEncrypted;
075    
076        /** the location of the paramaters file */
077        private String parametersLocation;
078    
079        /** is the parameters file encrypted? */
080        private String isParametersEncrypted;
081    
082        /** the user-supplied Avalon context */
083        private DefaultContext context;
084    
085        /** the Avalon logger */
086        private Logger logger;
087    
088        /** the application directory */
089        private String applicationRootDir;
090    
091        /** the temporary directory */
092        private String tempRootDir;
093    
094        /** the class loader passed in the Avalon Context */
095        private ClassLoader componentClassLoader;
096    
097        /** the type of container where YAAFI is embedded */
098        private String containerFlavour;
099    
100        /** the caller-supplied container configuration */
101        private Configuration containerConfiguration;
102    
103        /** to lookup service in the parent container */
104        private ServiceManager parentServiceManager;
105    
106        /** a list of ServiceManager maintaining their own services */
107        private String[] serviceManagerList;
108    
109        /** Constructor */
110        public ServiceContainerConfiguration()
111        {
112            this.logger = new ConsoleLogger();
113            this.containerFlavour = ServiceConstants.AVALON_CONTAINER_YAAFI;
114            this.serviceContainerClazzName = ServiceConstants.CLAZZ_NAME;
115            this.componentRolesLocation = ServiceConstants.COMPONENT_ROLE_VALUE;
116            this.isComponentRolesEncrypted = "false";
117            this.componentConfigurationLocation = ServiceConstants.COMPONENT_CONFIG_VALUE;
118            this.isComponentConfigurationEncrypted = "false";
119            this.parametersLocation = ServiceConstants.COMPONENT_PARAMETERS_VALUE;
120            this.isParametersEncrypted = "false";
121            this.context = new DefaultContext();
122            this.applicationRootDir = new File("").getAbsolutePath();
123            this.tempRootDir = System.getProperty("java.io.tmpdir",".");
124            this.componentClassLoader = this.getClass().getClassLoader();
125        }
126    
127        /**
128         * Add a new entry to the context by creating a new one.
129         * @param name the name of the new entry
130         * @param value the value of the new entry
131         */
132        public void addToContext( String name, Object value )
133        {
134            Validate.notEmpty(name,"name");
135            Validate.notNull(value,"value");
136            this.getContext().put( name, value );
137        }
138    
139        /**
140         * Add a hashtable to the context
141         * @param hashtable the Hashtable to be added
142         */
143        public void addToContext( Hashtable hashtable )
144        {
145            Validate.notNull(hashtable,"hashtable");
146    
147            String name = null;
148            Object value = null;
149            Enumeration keys = hashtable.keys();
150    
151            while( keys.hasMoreElements() )
152            {
153                name = (String) keys.nextElement();
154                value = hashtable.get( name );
155                this.addToContext( name, value );
156            }
157        }
158    
159        /**
160         * Create the final Avalon context passed to YAAFI containing
161         * <ul>
162         *   <li>user-supplied context</li>
163         *   <li>urn:avalon:home</li>
164         *   <li>urn:avalon:temp</li>
165         *   <li>urn:avalon:name</li>
166         *   <li>urn:avalon:partition</li>
167         *   <li>urn:avalon:classloader</li>
168         * </ul>
169         *
170         * @return the final Context
171         */
172    
173        public Context createFinalContext()
174        {
175            // 1) add the application root dir
176    
177            this.addToContext(
178                AvalonMerlinConstants.URN_AVALON_HOME,
179                this.getApplicationRootDir()
180                );
181    
182            // 2) add the temp root dir
183    
184            this.addToContext(
185                AvalonMerlinConstants.URN_AVALON_TEMP,
186                this.getTempRootDir()
187                );
188    
189            // 3) add the Avalon name
190    
191            this.addToContext(
192                AvalonMerlinConstants.URN_AVALON_NAME,
193                ServiceConstants.ROLE_NAME
194                );
195    
196            // 4) add the Avalon partition name
197    
198            this.addToContext(
199                AvalonMerlinConstants.URN_AVALON_PARTITION,
200                "root"
201                );
202    
203            // 5) add the class loader
204    
205            this.addToContext(
206                AvalonMerlinConstants.URN_AVALON_CLASSLOADER,
207                this.getComponentClassLoader()
208                );
209    
210            return this.getContext();
211        }
212    
213        /**
214         * Create a final configuration.
215         *
216         * @return the configuration
217         */
218        public Configuration createFinalConfiguration()
219        {
220            DefaultConfiguration result = null;
221    
222            if( this.getContainerConfiguration() != null )
223            {
224                return this.getContainerConfiguration();
225            }
226            else
227            {
228                // the root element is "fulcrum-yaafi"
229    
230                result = new DefaultConfiguration(
231                    ServiceConstants.ROLE_NAME
232                    );
233    
234                // add the following fragement
235                //
236                // <containerFlavour>merlin</containerFlavour>
237    
238                DefaultConfiguration containerFlavourConfig = new DefaultConfiguration(
239                    ServiceConstants.CONTAINERFLAVOUR_CONFIG_KEY
240                    );
241    
242                containerFlavourConfig.setValue( this.getContainerFlavour() );
243    
244                result.addChild( containerFlavourConfig );
245    
246                // add the following fragement
247                //
248                // <containerClazzName>...</containerClazzName>
249    
250                DefaultConfiguration containerClazzNameConfig = new DefaultConfiguration(
251                    ServiceConstants.CONTAINERCLAZZNAME_CONFIG_KEY
252                    );
253    
254                containerClazzNameConfig.setValue( this.getServiceContainerClazzName() );
255    
256                result.addChild( containerClazzNameConfig );
257    
258    
259                // add the following fragement
260                //
261                // <componentRoles>
262                //  <location>../conf/componentRoles.xml</location>
263                //  <isEncrypted>true</isEncrypted>
264                // </componentRoles>
265    
266                DefaultConfiguration componentRolesConfig = new DefaultConfiguration(
267                    ServiceConstants.COMPONENT_ROLE_KEYS
268                    );
269    
270                DefaultConfiguration componentRolesLocation = new DefaultConfiguration(
271                    ServiceConstants.COMPONENT_LOCATION_KEY
272                    );
273    
274                componentRolesLocation.setValue(
275                    this.getComponentRolesLocation()
276                    );
277    
278                DefaultConfiguration componentRolesIsEncrypted = new DefaultConfiguration(
279                    ServiceConstants.COMPONENT_ISENCRYPTED_KEY
280                    );
281    
282                componentRolesIsEncrypted.setValue(
283                    this.isComponentRolesEncrypted()
284                    );
285    
286                componentRolesConfig.addChild( componentRolesLocation );
287                componentRolesConfig.addChild( componentRolesIsEncrypted );
288    
289                result.addChild( componentRolesConfig );
290    
291                // add the following fragement
292                //
293                // <componentConfiguration>
294                //  <location>../conf/componentRoles.xml</location>
295                //  <isEncrypted>true</isEncrypted>
296                // </componentConfiguration>
297    
298                DefaultConfiguration componentConfigurationConfig = new DefaultConfiguration(
299                    ServiceConstants.COMPONENT_CONFIG_KEY
300                    );
301    
302                DefaultConfiguration componentConfigurationLocation = new DefaultConfiguration(
303                    ServiceConstants.COMPONENT_LOCATION_KEY
304                    );
305    
306                componentConfigurationLocation.setValue(
307                    this.getComponentConfigurationLocation()
308                    );
309    
310                DefaultConfiguration componentConfigurationIsEncrypted = new DefaultConfiguration(
311                    ServiceConstants.COMPONENT_ISENCRYPTED_KEY
312                    );
313    
314                componentConfigurationIsEncrypted.setValue(
315                    this.isComponentConfigurationEncrypted()
316                    );
317    
318                componentConfigurationConfig.addChild( componentConfigurationLocation );
319                componentConfigurationConfig.addChild( componentConfigurationIsEncrypted );
320    
321                result.addChild( componentConfigurationConfig );
322    
323                // Add the following fragement
324                //
325                // <parameters>
326                //   <location>../conf/parameters.properties</location>
327                //   <isEncrypted>true</isEncrypted>
328                // </parameters>
329    
330                DefaultConfiguration parameterConfigurationConfig = new DefaultConfiguration(
331                    ServiceConstants.COMPONENT_PARAMETERS_KEY
332                    );
333    
334                DefaultConfiguration parameterConfigurationLocation = new DefaultConfiguration(
335                    ServiceConstants.COMPONENT_LOCATION_KEY
336                    );
337    
338                parameterConfigurationLocation.setValue(
339                    this.getParametersLocation()
340                    );
341    
342                DefaultConfiguration parameterConfigurationIsEncrypted = new DefaultConfiguration(
343                    ServiceConstants.COMPONENT_ISENCRYPTED_KEY
344                    );
345    
346                parameterConfigurationIsEncrypted.setValue(
347                    this.isParametersEncrypted()
348                    );
349    
350                parameterConfigurationConfig.addChild( parameterConfigurationLocation );
351                parameterConfigurationConfig.addChild( parameterConfigurationIsEncrypted );
352    
353                result.addChild( parameterConfigurationConfig );
354    
355                // Add the following fragement
356                //
357                // <serviceManagers>
358                //   <serviceManagers>springFrameworkService</serviceManager>
359                // </serviceManagers>
360    
361                if(this.hasServiceManagerList())
362                {
363                    DefaultConfiguration serviceManagerListConfig = new DefaultConfiguration(
364                        ServiceConstants.SERVICEMANAGER_LIST_KEY
365                        );
366    
367                    for(int i=0; i<this.serviceManagerList.length; i++)
368                    {
369                        DefaultConfiguration serviceManagerConfig = new DefaultConfiguration(
370                            ServiceConstants.SERVICEMANAGER_KEY
371                            );
372    
373                        serviceManagerConfig.setValue(this.serviceManagerList[i]);
374    
375                        serviceManagerListConfig.addChild(serviceManagerConfig);
376                    }
377    
378                    result.addChild( serviceManagerListConfig );
379                }
380    
381    
382                return result;
383            }
384        }
385    
386        /////////////////////////////////////////////////////////////////////////
387        // Generated Getters/Setters
388        /////////////////////////////////////////////////////////////////////////
389    
390        /**
391         * @return Returns the serviceContainerClazzName.
392         */
393        private String getServiceContainerClazzName()
394        {
395            return this.serviceContainerClazzName;
396        }
397    
398        /**
399         * @return Returns the componentConfigurationLocation.
400         */
401        private String getComponentConfigurationLocation()
402        {
403            return componentConfigurationLocation;
404        }
405    
406        /**
407         * @param componentConfigurationLocation The componentConfigurationLocation to set.
408         */
409        public void setComponentConfigurationLocation(
410            String componentConfigurationLocation)
411        {
412            Validate.notNull(componentConfigurationLocation,"componentConfigurationLocation");
413            this.componentConfigurationLocation = componentConfigurationLocation;
414        }
415    
416        /**
417         * @return Returns the componentRolesLocation.
418         */
419        private String getComponentRolesLocation()
420        {
421            return componentRolesLocation;
422        }
423    
424        /**
425         * @param componentRolesLocation The componentRolesLocation to set.
426         */
427        public void setComponentRolesLocation(String componentRolesLocation)
428        {
429            this.componentRolesLocation = componentRolesLocation;
430        }
431    
432        /**
433         * @return Returns the context.
434         */
435        private DefaultContext getContext()
436        {
437            return context;
438        }
439    
440        /**
441         * @param context The context to set.
442         */
443        public void setContext(Context context)
444        {
445            if( context instanceof DefaultContext )
446            {
447                this.context = (DefaultContext) context;
448            }
449            else
450            {
451                this.context = new DefaultContext( context );
452            }
453        }
454    
455        /**
456         * @return Returns the isComponentConfigurationEncrypted.
457         */
458        private String isComponentConfigurationEncrypted()
459        {
460            return isComponentConfigurationEncrypted;
461        }
462    
463        /**
464         * @param isComponentConfigurationEncrypted The isComponentConfigurationEncrypted to set.
465         */
466        public void setComponentConfigurationEncrypted(
467            String isComponentConfigurationEncrypted)
468        {
469            this.isComponentConfigurationEncrypted = isComponentConfigurationEncrypted;
470        }
471    
472        /**
473         * @return Returns the isComponentRolesEncrypted.
474         */
475        private String isComponentRolesEncrypted()
476        {
477            return isComponentRolesEncrypted;
478        }
479        /**
480         * @param isComponentRolesEncrypted The isComponentRolesEncrypted to set.
481         */
482        public void setComponentRolesEncrypted(String isComponentRolesEncrypted)
483        {
484            this.isComponentRolesEncrypted = isComponentRolesEncrypted;
485        }
486    
487        /**
488         * @return Returns the isParametersEncrypted.
489         */
490        private String isParametersEncrypted()
491        {
492            return isParametersEncrypted;
493        }
494    
495        /**
496         * @param isParametersEncrypted The isParametersEncrypted to set.
497         */
498        public void setParametersEncrypted(String isParametersEncrypted)
499        {
500            Validate.notEmpty(isParametersEncrypted,"isParametersEncrypted");
501            this.isParametersEncrypted = isParametersEncrypted;
502        }
503    
504        /**
505         * @return Returns the logger.
506         */
507        public Logger getLogger()
508        {
509            return logger;
510        }
511    
512        /**
513         * @param logger The logger to set.
514         */
515        public void setLogger(Logger logger)
516        {
517            this.logger = logger;
518        }
519    
520        /**
521         * @return Returns the parametersLocation.
522         */
523        private String getParametersLocation()
524        {
525            return parametersLocation;
526        }
527    
528        /**
529         * @param parametersLocation The parametersLocation to set.
530         */
531        public void setParametersLocation(String parametersLocation)
532        {
533            this.parametersLocation = parametersLocation;
534        }
535    
536        /**
537         * @return Returns the applicationRootDir.
538         */
539        private File getApplicationRootDir()
540        {
541            return new File(applicationRootDir);
542        }
543    
544        /**
545         * @param applicationRootDir The applicationRootDir to set.
546         */
547        public void setApplicationRootDir(String applicationRootDir)
548        {
549            Validate.notNull(applicationRootDir, "applicationRootDir");
550    
551            if( applicationRootDir.equals(".") )
552            {
553                this.applicationRootDir = new File("").getAbsolutePath();
554            }
555            else
556            {
557                this.applicationRootDir = new File( applicationRootDir ).getAbsolutePath();
558            }
559        }
560    
561        /**
562         * @return Returns the tempRootDir.
563         */
564        private File getTempRootDir()
565        {
566            return makeAbsoluteFile(this.getApplicationRootDir(),this.tempRootDir);
567        }
568    
569        /**
570         * @param tempRootDir The tempRootDir to set.
571         */
572        public void setTempRootDir(String tempRootDir)
573        {
574            Validate.notNull(tempRootDir, "tempRootDir");
575            this.tempRootDir = tempRootDir;
576        }
577    
578        /**
579         * @return Returns the classLoader.
580         */
581        private ClassLoader getComponentClassLoader()
582        {
583            return componentClassLoader;
584        }
585    
586        /**
587         * @param componentClassLoader The classLoader to set.
588         */
589        public void setComponentClassLoader(ClassLoader componentClassLoader)
590        {
591            Validate.notNull(componentClassLoader, "componentClassLoader");
592            this.componentClassLoader = componentClassLoader;
593        }
594    
595        /**
596         * @return Returns the containerFlavour.
597         */
598        private String getContainerFlavour()
599        {
600            return containerFlavour;
601        }
602        /**
603         * @param containerFlavour The containerFlavour to set.
604         */
605        public void setContainerFlavour(String containerFlavour)
606        {
607            this.containerFlavour = containerFlavour;
608        }
609    
610        /**
611         * @return Returns the containerConfiguration.
612         */
613        private Configuration getContainerConfiguration()
614        {
615            return containerConfiguration;
616        }
617    
618        /**
619         * @param containerConfiguration The containerConfiguration to set.
620         */
621        public void setContainerConfiguration(Configuration containerConfiguration)
622        {
623            this.containerConfiguration = containerConfiguration;
624        }
625    
626        /**
627         * Get the parent service manager to find service managed by the
628         * parent container.
629         *
630         * @return the parent container
631         */
632    
633        public ServiceManager getParentServiceManager() {
634            return parentServiceManager;
635        }
636    
637        /**
638         * Set the parent service manager to find service managed by the
639         * parent container.
640         *
641         * @param parentServiceManager the parent container
642         */
643        public void setParentServiceManager(ServiceManager parentServiceManager) {
644            this.parentServiceManager = parentServiceManager;
645        }
646    
647        /**
648         * Get a list of service manager managing their own set of services.
649         *
650         * @return a list of service implementing the ServiceManager interface
651         */
652        public String[] getServiceManagerList() {
653            return serviceManagerList;
654        }
655    
656        /**
657         * Set a list of service manager managing their own set of services.
658         *
659         * @param serviceManagerList a list of service implementing the ServiceManager interface
660         */
661        public void setServiceManagerList(String[] serviceManagerList) {
662            this.serviceManagerList = serviceManagerList;
663        }
664    
665        /**
666         * @return is a list of service manager managing their own set of services defined
667         */
668        public boolean hasServiceManagerList()
669        {
670            return ((this.serviceManagerList != null) && (this.serviceManagerList.length > 0));
671        }
672    
673        /**
674         * Loads a containerConfiguration file and set is as the Avalon
675         * configuration to be used for Configurable.configure(). Take
676         * care that the implementation uses an InputStreamLocator to
677         * find the containerConfiguration which uses the previously
678         * set application root directory.
679         *
680         * @param location the location of the containerConfiguration
681         * @throws IOException loading the configuration failed
682         */
683        public void loadContainerConfiguration( String location )
684            throws IOException
685        {
686            this.loadContainerConfiguration( location, "false" );
687        }
688    
689        /**
690         * Loads a containerConfiguration file and set is as the Avalon
691         * configuration to be used for Configurable.configure(). Take
692         * care that the implementation uses an InputStreamLocator to
693         * find the containerConfiguration which uses the previously
694         * set application root directory.
695         *
696         * @param location the location of the containerConfiguration
697         * @param isEncrypted is the file encrypted
698         * @throws IOException loading the configuration failed
699         */
700        public void loadContainerConfiguration( String location, String isEncrypted )
701            throws IOException
702        {
703            Configuration result = null;
704    
705            InputStreamLocator locator = new InputStreamLocator(
706                this.getApplicationRootDir(),
707                this.getLogger()
708                );
709    
710            DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
711            InputStream is = locator.locate( location );
712    
713            if( is != null )
714            {
715                try
716                {
717                    is = CryptoStreamFactory.getDecryptingInputStream(is ,isEncrypted);
718                    result = builder.build( is );
719                    this.setContainerConfiguration( result );
720                }
721                catch ( Exception e )
722                {
723                    String msg = "Unable to parse the following file : " + location;
724                    this.getLogger().error( msg , e );
725                    throw new IOException(msg);
726                }
727            }
728            else
729            {
730                String msg = "Unable to locate the containerConfiguration file : " + location;
731                this.getLogger().error(msg);
732                throw new IOException(msg);
733            }
734        }
735    
736        /**
737         * Determines the absolute file.
738         * @param baseDir the base directory
739         * @param fileName the filename
740         * @return the absolute path
741         */
742        private static File makeAbsoluteFile( File baseDir, String fileName )
743        {
744            File result = new File(fileName);
745    
746            if(!result.isAbsolute())
747            {
748                result = new File( baseDir, fileName );
749            }
750    
751            return result;
752        }
753    }