001    package org.apache.fulcrum.jetty.impl;
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 org.apache.avalon.framework.activity.Startable;
023    import org.apache.avalon.framework.activity.Initializable;
024    import org.apache.avalon.framework.logger.AbstractLogEnabled;
025    import org.apache.avalon.framework.logger.LogEnabled;
026    import org.apache.avalon.framework.configuration.ConfigurationException;
027    import org.apache.avalon.framework.configuration.Configuration;
028    import org.apache.avalon.framework.configuration.Reconfigurable;
029    import org.apache.avalon.framework.context.Contextualizable;
030    import org.apache.avalon.framework.context.Context;
031    import org.apache.avalon.framework.context.ContextException;
032    import org.apache.fulcrum.jetty.JettyService;
033    
034    import org.mortbay.jetty.Server;
035    import org.mortbay.xml.XmlConfiguration;
036    
037    import java.io.File;
038    import java.io.InputStream;
039    import java.io.IOException;
040    import java.io.FileInputStream;
041    
042    /**
043     * Starts an instance of the Spring Service Framework as Avalon service.
044     *
045     * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
046     */
047    
048    public class JettyServiceImpl
049        extends AbstractLogEnabled
050        implements LogEnabled, Startable, Contextualizable, Initializable, Reconfigurable, JettyService
051    {
052        /** the Jetty server instance */
053        private Server server;
054    
055        /** the location of the Jetty XML configuration files */
056        private String[] configurationLocations;
057    
058        /** the working directory of the service */
059        private File serviceApplicationDir;
060    
061        /////////////////////////////////////////////////////////////////////////
062        // Avalon Lifecycle Implementation
063        /////////////////////////////////////////////////////////////////////////
064    
065        /**
066         * Constructor
067         */
068        public JettyServiceImpl()
069        {
070            // nothing to do
071        }
072    
073        public void contextualize(Context context) throws ContextException
074        {
075            this.serviceApplicationDir = (File) context.get("context-root");
076        }
077    
078        /**
079         * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
080         */
081        public void configure(Configuration configuration) throws ConfigurationException
082        {
083            // parse the 'configurations'
084    
085            Configuration[] configurationsList = configuration.getChild("configurations").getChildren("configuration");
086            this.configurationLocations = new String[configurationsList.length];
087    
088            for(int i=0; i<this.configurationLocations.length; i++)
089            {
090                this.configurationLocations[i] = configurationsList[i].getValue();
091            }
092    
093            if(this.configurationLocations.length == 0)
094            {
095                String msg = "No configuration files for the Jetty are defined";
096                throw new ConfigurationException(msg);
097            }
098    
099            // parse the 'properties'
100    
101            Configuration[] propertiesConfiguration = configuration.getChild("properties", true).getChildren("property");
102    
103            for( int i=0; i<propertiesConfiguration.length; i++ )
104            {
105                String key = propertiesConfiguration[i].getAttribute("name");
106                String value = propertiesConfiguration[i].getValue();
107                this.getLogger().info("Setting the system property '" + key + "'==>'" + value + "'");            
108                System.setProperty( key, value );
109            }
110        }
111    
112        /**
113         * @see org.apache.avalon.framework.activity.Initializable#initialize()
114         */
115        public void initialize() throws Exception
116        {
117            // locate the serviceConfiguration file and initialize Jetty server
118    
119            Server currServer = new Server();
120    
121            for(int i=0; i<this.configurationLocations.length; i++)
122            {
123                String currConfigurationLocation = this.configurationLocations[i]; 
124                this.getLogger().info("Loading the Jetty serviceConfiguration file : " + currConfigurationLocation);
125                InputStream is = this.locate(this.serviceApplicationDir, currConfigurationLocation);
126                XmlConfiguration configuration = new XmlConfiguration(is);
127                configuration.configure(currServer);
128                is.close();
129            }
130    
131            this.server = currServer;
132        }
133    
134        /**
135         * @see org.apache.avalon.framework.activity.Startable#start()
136         */
137        public void start() throws Exception
138        {
139            this.getServer().start();
140        }
141    
142        /**
143         * @see org.apache.avalon.framework.activity.Startable#stop()
144         */
145        public void stop() throws Exception
146        {
147            this.getServer().stop();
148        }
149    
150        /**
151         * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
152         */
153        public void reconfigure(Configuration configuration) throws ConfigurationException
154        {
155            if(configuration != null)
156            {
157                this.configure(configuration);
158            }
159    
160            try
161            {
162                this.initialize();
163            }
164            catch(Exception e)
165            {
166                String msg = "Initializing the new server failed";
167                throw new ConfigurationException(msg, e);
168            }
169        }
170    
171        /////////////////////////////////////////////////////////////////////////
172        // Service Interface Implementation
173        /////////////////////////////////////////////////////////////////////////
174    
175        public Server getServer()
176        {
177            return this.server;
178        }
179    
180        /////////////////////////////////////////////////////////////////////////
181        // Service Implementation
182        /////////////////////////////////////////////////////////////////////////
183    
184        /**
185         * Locate the configuration file using the file system or a classpath.
186         *
187         * @param applicationDir the directory where to start the search
188         * @param location the location of the source to be loaded
189         * @return the input stream of the resource
190         * @exception IOException the operation failed
191         */
192        private InputStream locate( File applicationDir, String location ) throws IOException
193        {
194            if( ( location == null ) || ( location.length() == 0 ) )
195            {
196                throw new IllegalArgumentException("location is null or empty");
197            }
198    
199            File file = null;
200            InputStream is = null;
201    
202            // try to load a relative location with the given root dir
203            // e.g. "jetty.xml" located in the current working directory
204    
205            if( !location.startsWith("/") )
206            {
207                file = new File( applicationDir, location );
208    
209                this.getLogger().debug("Looking for " + location + " in the application directory");
210    
211                if( file.exists() )
212                {
213                    is = new FileInputStream( file );
214                    this.getLogger().debug("Found " + location + " as " + file.getAbsolutePath() );
215                }
216            }
217    
218            // try to load an absolute location as file
219            // e.g. "/foo/jetty.xml" from the root of the file system
220    
221            if( ( is == null ) && (location.startsWith("/")) )
222            {
223                file = new File( location );
224    
225                this.getLogger().debug("Looking for " + location + " as absolute file location");
226    
227                if( file.isAbsolute() && file.exists() )
228                {
229                    is = new FileInputStream( file );
230                    this.getLogger().debug("Found " + location + " as " + file.getAbsolutePath() );
231                }
232            }
233    
234            // try to load an absolute location through the classpath
235            // e.g. "/jetty.xml" located in the classpath
236    
237            if( ( is == null ) && (location.startsWith("/")) )
238            {
239                this.getLogger().debug("Looking for " + location + " using the class loader");
240                is =  getClass().getResourceAsStream( location );
241    
242                if( is != null )
243                {
244                    this.getLogger().debug("Successfully located " + location);
245                }
246            }
247    
248            if( is == null )
249            {
250                this.getLogger().warn("Unable to find any resource with the name '" + location + "'");
251            }
252    
253            return is;
254        }
255    }