001    /*
002     * Copyright 2006 Stephen McConnell.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package net.dpml.http;
017    
018    import java.net.URI;
019    import java.net.URL;
020    import java.util.ArrayList;
021    
022    import net.dpml.logging.Logger;
023    
024    import net.dpml.metro.PartsManager;
025    import net.dpml.metro.ComponentHandler;
026    import net.dpml.component.Provider;
027    
028    import org.mortbay.thread.ThreadPool;
029    import org.mortbay.jetty.Connector;
030    import org.mortbay.jetty.security.UserRealm;
031    import org.mortbay.xml.XmlConfiguration;
032    
033    /**
034     * HTTP server implementation.
035     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
036     * @version 0.0.4
037     */
038    public class Server extends org.mortbay.jetty.Server
039    {
040       /**
041        * Component context through which the server configuration uri may be declared.
042        */
043        public interface Context
044        {
045           /**
046            * Get the Jetty XML configuration uri.  The configuration uri is 
047            * used to establish the default server configuration prior to 
048            * customization via the server context. If not supplied the server
049            * will be deployed relative to the supplied context.
050            *
051            * @param uri the default uri
052            * @return a uri referencing a Jetty configuration profile
053            */
054            URI getConfiguration( URI uri );
055            
056           /**
057            * Get the assigned thread pool. If no thread pool is 
058            * assigned by the deployment scenario a default pool
059            * will be established using the thread pool assigned in the
060            * component internal parts.
061            *
062            * @param pool the default value
063            * @return the resolved thread pool
064            */
065            ThreadPool getThreadPool( ThreadPool pool );
066        }
067        
068       /**
069        * Internal parts managemwent interface.
070        */
071        public interface Parts extends PartsManager
072        {
073           /**
074            * Return the default thread pool.
075            * @return the default thread pool.
076            */
077            ThreadPool getThreadPool();
078            
079           /**
080            * Return the collection of handlers.  For any given request all handlers
081            * in the collection will be supplied with a request irrespective of response 
082            * status.
083            *
084            * @return the configured handler collection.
085            */
086            HandlerCollection getHandlers();
087        }
088        
089        private final Logger m_logger;
090        private final Context m_context;
091        private final ArrayList m_connections = new ArrayList();
092    
093       /**
094        * Creation of a new HTTP server implementation.
095        * @param logger the assigned logging channel
096        * @param context the assigned deployment context
097        * @param parts the parts manager
098        * @exception Exception if an instantiation error occurs
099        */
100        public Server( Logger logger, Context context, Parts parts ) throws Exception
101        {
102            super();
103            
104            m_logger = logger;
105            m_context = context;
106            
107            getLogger().debug( "commencing http server deployment" );
108            Logger internal = logger.getChildLogger( "jetty" );
109            internal.debug( "assigning internal jetty logger" );
110            LoggerAdapter.setRootLogger( internal );
111            
112            Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
113            URI uri = context.getConfiguration( null );
114            if( null != uri )
115            {
116                getLogger().debug( "applying server configuration: " + uri );
117                URL url = uri.toURL();
118                XmlConfiguration config = new XmlConfiguration( url );
119                config.configure( this );
120            }
121            
122            //
123            // setup the thread pool
124            //
125            
126            ThreadPool pool = context.getThreadPool( null );
127            if( null != pool )
128            {
129                super.setThreadPool( pool );
130            }
131            else
132            {
133                super.setThreadPool( parts.getThreadPool() );
134            }
135            
136            //
137            // add connectors, realms and handlers
138            //
139            
140            addConnectors( parts );
141            addUserRealms( parts );
142            HandlerCollection collection = parts.getHandlers();
143            setHandler( collection );
144            
145            // notify completion of server establishment
146            
147            getLogger().debug( "server established" );
148        }
149        
150        private void addConnectors( PartsManager parts ) throws Exception
151        {
152            getLogger().debug( "commencing connector addition" );
153            ComponentHandler[] handlers = parts.getComponentHandlers( Connector.class );
154            getLogger().debug( "connector count: " + handlers.length );
155            for( int i=0; i<handlers.length; i++ )
156            {
157                ComponentHandler handler = handlers[i];
158                getLogger().debug( "adding connector: " + handler );
159                try
160                {
161                    Provider provider = handler.getProvider();
162                    Connector ch = (Connector) provider.getValue( false );
163                    m_connections.add( ch );
164                }
165                catch( Throwable e )
166                {
167                    final String error = 
168                      "Failed to deploy content handler: " + handler;
169                    throw new Exception( error, e );
170                }
171            }
172            Connector[] connectors = (Connector[]) m_connections.toArray( new Connector[0] );
173            setConnectors( connectors );
174        }
175        
176        private void addUserRealms( PartsManager parts )  throws Exception
177        {
178            getLogger().debug( "commencing realm addition" );
179            ArrayList list = new ArrayList();
180            ComponentHandler[] handlers = parts.getComponentHandlers( UserRealm.class );
181            for( int i=0; i<handlers.length; i++ )
182            {
183                ComponentHandler handler = handlers[i];
184                getLogger().debug( "adding realm: " + handler );
185                try
186                {
187                    Provider provider = handler.getProvider();
188                    org.mortbay.jetty.security.UserRealm ch = 
189                      (org.mortbay.jetty.security.UserRealm) provider.getValue( false );
190                      list.add( ch );
191                }
192                catch( Throwable e )
193                {
194                    final String error = 
195                      "Failed to deploy user realm: " + handler;
196                    throw new Exception( error, e );
197                }
198            }
199            UserRealm[] realms = (UserRealm[]) list.toArray( new UserRealm[0] );
200            setUserRealms( realms );
201        }
202        
203        private Logger getLogger()
204        {
205            return m_logger;
206        }
207    }