001    /*
002     * Copyright 2006 Stephen J. 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
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.lang;
020    
021    import dpml.lang.Part;
022    
023    import java.io.IOException;
024    import java.io.OutputStream;
025    import java.io.OutputStreamWriter;
026    import java.io.Writer;
027    import java.net.URI;
028    import java.net.URL;
029    import java.net.URLConnection;
030    import java.util.ServiceLoader;
031    
032    import javax.xml.XMLConstants;
033    
034    import net.dpml.transit.Artifact;
035    import net.dpml.transit.Transit;
036    
037    import net.dpml.runtime.ComponentStrategyHandler;
038    import net.dpml.util.Logger;
039    
040    import dpml.util.DefaultLogger;
041    import dpml.util.ElementHelper;
042    
043    import org.w3c.dom.Element;
044    import org.w3c.dom.TypeInfo;
045    
046    /**
047     * Abstract component deployment strategy.
048     *
049     * @author <a href="http://www.dpml.net">Digital Product Management Laboratory</a>
050     * @version 2.0.1
051     */
052    public abstract class Strategy implements Comparable<Strategy>
053    {
054        private static final Logger LOGGER = new DefaultLogger( "dpml.lang" );
055        
056       /**
057        * Creation of a new management strategy.
058        *
059        * @param subject the implementation class to be managed
060        * @param registry the service registry
061        * @param name the path under which the strategy will be established
062        * @return the management strategy
063        * @exception Exception if a general loading error occurs
064        */
065        public static Strategy load( Class<?> subject, ServiceRegistry registry, String name ) throws Exception
066        {
067            if( null == subject )
068            {
069                throw new NullPointerException( "subject" );
070            }
071            StrategyHandler handler = PartContentHandler.getStrategyHandler( subject );
072            Strategy strategy = handler.newStrategy( subject, name );
073            if( null == registry )
074            {
075                StandardServiceRegistry standard = new StandardServiceRegistry();
076                strategy.initialize( standard );
077            }
078            else
079            {
080                strategy.initialize( registry );
081            }
082            return strategy;
083        }
084        
085       /**
086        * Load a strategy defined by the supplied uri.
087        *
088        * @param uri the source uri to a part definition
089        * @return the strategy
090        * @exception Exception if a general loading error occurs
091        * @exception NullPointerException if the uri argument is null
092        */
093        public static Strategy load( URI uri ) throws Exception, NullPointerException
094        {
095            return load( null, null, uri, null );
096        }
097        
098       /**
099        * Load a strategy defined by the supplied uri, name, classloader and service 
100        * registry, and return a value assignable to the supplied type.
101        *
102        * @param classloader the anchor classloader
103        * @param registry the service registry
104        * @param uri the source uri to a part definition
105        * @param name the path under which the strategy will be established
106        * @return an instance of the supplied type
107        * @exception Exception if a general loading error occurs
108        * @exception NullPointerException if the uri argument is null
109        */
110        public static Strategy load( 
111          ClassLoader classloader, ServiceRegistry registry, URI uri, String name ) throws Exception, NullPointerException
112        {
113            if( null == uri )
114            {
115                throw new NullPointerException( "uri" );
116            }
117            Transit transit = Transit.getInstance();
118            URL url = Artifact.toURL( uri );
119            URLConnection connection = url.openConnection();
120            Part part = PartContentHandler.getPartContent( classloader, connection, name, true );
121            Strategy strategy = part.getStrategy();
122            if( null == registry )
123            {
124                StandardServiceRegistry standard = new StandardServiceRegistry();
125                strategy.initialize( standard );
126            }
127            else
128            {
129                strategy.initialize( registry );
130            }
131            return strategy;
132        }
133        
134        //--------------------------------------------------------------------
135        // state
136        //--------------------------------------------------------------------
137    
138        private ClassLoader m_classloader;
139        
140        //--------------------------------------------------------------------
141        // constructor
142        //--------------------------------------------------------------------
143        
144       /**
145        * Creation of a new deployment strategy.
146        * @param classloader the classloader
147        */
148        protected Strategy( ClassLoader classloader )
149        {
150            m_classloader = classloader;
151        }
152        
153        //--------------------------------------------------------------------
154        // public operations
155        //--------------------------------------------------------------------
156    
157       /**
158        * Return the classloader establised by the strategy implementation.
159        * @return the classloader
160        */
161        public ClassLoader getClassLoader()
162        {
163            return m_classloader;
164        }
165        
166       /**
167        * Return the priority assigned to this strategy.
168        * @return the priority value
169        */
170        public abstract int getPriority();
171        
172       /**
173        * Return true if this strategy is a candidate with result to the 
174        * supply of an instance assignable to the supplied type.
175        * 
176        * @param type the requested type
177        * @return type if this strategy is a condidate
178        */
179        public abstract boolean isaCandidate( Class<?> type );
180        
181       /**
182        * Instantiate a service returning an instance assigned to the supplied type.
183        *
184        * @param type the return type
185        * @return an instance of the type
186        */
187        public abstract <T>T getInstance( Class<T> type );
188        
189       /**
190        * Write the strategy to the supplied buffer in XML format.
191        * @param buffer the output buffer
192        * @param key the optional identifying key
193        * @exception IOException if an IO error occurs
194        */
195        public abstract void encode( Buffer buffer, String key ) throws IOException;
196    
197       /**
198        * Composite strategies are strategy implementations that contain subidary
199        * strategies.  During lookup operations, a subsidiary strategy may request 
200        * a service from the enclosing strategy.  To enable traversal from a subsidary
201        * to enclosing context a service registry shall be provided to all subsidiary
202        * strategies.
203        * 
204        * @param registry the service registry
205        */
206        public abstract void initialize( ServiceRegistry registry );
207        
208       /**
209        * Return the short name of this strategy.
210        * @return the name
211        */
212        public abstract String getName();
213    
214       /**
215        * Compares a supplied strategy with this strategy.  If the supplied
216        * strategy has a priority greater than this strategy the returned value
217        * is 1, otherwise if the supplied strategy has a priority lower than this
218        * strategy then the return value is -1,otherwise the returned value is 0.
219        *
220        * @param strategy the strategy to evaluate relative to this strategy
221        * @return the priority comparative index
222        */
223        public int compareTo( Strategy strategy )
224        {
225            int n = getPriority();
226            int m = strategy.getPriority();
227            if( n > m )
228            {
229                return -1;
230            }
231            else if( n == m )
232            {
233                return 0;
234            }
235            else
236            {
237                return 1;
238            }
239        }
240    
241        //--------------------------------------------------------------------
242        // protected operations
243        //--------------------------------------------------------------------
244        
245       /**
246        * Return a value assignable to the supplied type or null if the type
247        * cannot be resolved from this strategy.
248        * @param c the target class
249        * @return an instance of the class or null
250        * @exception IOException if an IO error occurs
251        */
252        public abstract <T>T getContentForClass( Class<T> c ) throws IOException;
253        
254        //--------------------------------------------------------------------
255        // private implementation
256        //--------------------------------------------------------------------
257        
258    }