001    /*
002     * Copyright 2004 Niclas Hedhman
003     * Copyright 2004-2006 Stephen J. McConnell
004     *
005     * Licensed  under the  Apache License,  Version 2.0  (the "License");
006     * you may not use  this file  except in  compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *   http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed  under the  License is distributed on an "AS IS" BASIS,
013     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
014     * implied.
015     *
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    package net.dpml.transit.artifact;
021    
022    import java.io.InputStream;
023    import java.io.IOException;
024    import java.io.OutputStream;
025    import java.io.File;
026    import java.net.UnknownServiceException;
027    import java.net.URI;
028    import java.net.URL;
029    import java.net.URLConnection;
030    import java.net.URISyntaxException;
031    
032    import net.dpml.transit.Artifact;
033    import net.dpml.transit.Transit;
034    import net.dpml.transit.SecuredTransitContext;
035    import net.dpml.transit.CacheHandler;
036    
037    import net.dpml.lang.Part;
038    
039    import net.dpml.util.MimeTypeHandler;
040    
041    /**
042     * The connection handler for URLs based on the "artifact" protocol family.
043     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
044     * @version 1.1.0
045     */
046    public class ArtifactURLConnection extends URLConnection
047    {
048        // ------------------------------------------------------------------------
049        // state
050        // ------------------------------------------------------------------------
051    
052       /**
053        * Transit context.
054        */
055        private final SecuredTransitContext m_context;
056    
057       /**
058        * Artifact.
059        */
060        private final Artifact m_artifact;
061    
062       /**
063        * Reference fragment.
064        */
065        private final String m_reference;
066    
067       /**
068        * The connected state.
069        */
070        private boolean m_connected;
071    
072        // ------------------------------------------------------------------------
073        // constructor
074        // ------------------------------------------------------------------------
075    
076        /**
077         * Creation of a new handler.
078         * @param url the url to establish a connection with
079         * @param context the transit context
080         * @exception NullPointerException if the url argument is null
081         * @exception IOException if the url argument is invalid
082          */
083        ArtifactURLConnection( URL url, SecuredTransitContext context )
084            throws NullPointerException, IOException
085        {
086            super( url );
087    
088            Transit.getInstance(); // make sure Transit is initialized
089    
090            m_context = context;
091            m_reference = getReference( url );
092    
093            String spec = getRealSpec( url, m_reference );
094            try
095            {
096                m_artifact = Artifact.createArtifact( spec );
097            }
098            catch( URISyntaxException e )
099            {
100                throw new IOException( e.toString() );
101            }
102        }
103    
104        // ------------------------------------------------------------------------
105        // URLConnection
106        // ------------------------------------------------------------------------
107    
108       /**
109        * Establish a connection.  The implementation will attempt to
110        * resolve the resource relative to the cache and associated hosts.
111        *
112        * @exception IOException is an error occurs while attempting to establish
113        *  the connection.
114        */
115        public void connect()
116            throws IOException
117        {
118            if( m_connected )
119            {
120                return;
121            }
122            else
123            {
124                m_connected = true;
125                InputStream stream = null;
126                try
127                {
128                    stream = getInputStream();
129                }
130                finally
131                {
132                    if( null != stream )
133                    {
134                        try
135                        {
136                            stream.close();
137                        }
138                        finally
139                        {
140                            stream = null;
141                        }
142                    }
143                }
144            }
145        }
146    
147       /**
148        * Return an input stream to the resource.
149        * @return the input stream
150        * @exception IOException is an error occurs
151        */
152        public InputStream getInputStream()
153            throws IOException
154        {
155            connect();
156            CacheHandler cache = m_context.getCacheHandler();
157            if( null != m_reference )
158            {
159                return cache.getResource( m_artifact, m_reference );
160            }
161            else
162            {
163                return cache.getResource( m_artifact );
164            }
165        }
166    
167       /**
168        * Return an output stream to the resource.
169        * @return the output stream
170        * @exception IOException if any I/O problems occur.
171        */
172        public OutputStream getOutputStream()
173            throws IOException
174        {
175            CacheHandler cache = m_context.getCacheHandler();
176            return cache.createOutputStream( m_artifact );
177        }
178    
179       /**
180        * Reutrn the mimetype of the content.
181        * @return the content mimetype
182        */
183        public String getContentType()
184        {
185            String type = m_artifact.getType();
186            return MimeTypeHandler.getMimeType( type );
187        }
188    
189       /**
190        * Return the content for this artifact.
191        * @return the content object (possibly null)
192        * @exception IOException is an error occurs
193        */
194        public Object getContent()
195            throws IOException
196        {
197            Object content = getContent( new Class[0] );
198            if( content != null )
199            {
200                return content;
201            }
202            else
203            {
204                return super.getContent();
205            }
206        }
207    
208       /**
209        * Return the content for this artifact.
210        * @param classes a sequence of classes against which the
211        *   implementation will attempt to establish a known match
212        * @return the content object (possibly null)
213        * @exception IOException is an error occurs
214        */
215        public Object getContent( Class[] classes )
216            throws IOException
217        {
218            //
219            // attempt to resolve this locally as we may be dealing
220            // with Depot references to the artifact File
221            //
222    
223            for( int i=0; i < classes.length; i++ )
224            {
225                Class c = classes[i];
226                if( c.equals( File.class ) )
227                {
228                    return m_context.getCacheHandler().getLocalFile( m_artifact );
229                }
230            }
231            
232            String type = m_artifact.getType();
233    
234            // 
235            // if the type is a plugin then handle this directly
236            //
237    
238            if( "part".equals( type ) )
239            { 
240                URI uri = m_artifact.toURI();
241                Part part = Part.load( uri );
242                return part.getContent( classes );
243            }
244            
245            //
246            // otherwise fallback on the default jvm content handling
247            //
248    
249            try
250            {
251                Object content = super.getContent( classes );
252                if( content != null )
253                {
254                    return content;
255                }
256            }
257            catch( UnknownServiceException use )
258            {
259                boolean ignoreThis = true;
260            }
261    
262            return null;
263        }
264        
265        // ------------------------------------------------------------------------
266        // implementation
267        // ------------------------------------------------------------------------
268    
269       /**
270        * Return a fragment referencing content within the resource referenced by
271        * the artifact.
272        * @param url the url
273        * @return the fragment or null if this is not a referential url
274        */
275        private String getReference( URL url )
276        {
277            String path = url.getPath();
278            int i = path.indexOf( '!' );
279            if( i < 0 )
280            {
281                return null;
282            }
283            else
284            {
285                return path.substring( i );
286            }
287        }
288    
289       /**
290        * Return the real specification of the supplied url.
291        * @param url the url to evaluate
292        * @param ref a reference fragment
293        * @return the artifact url spec withough the ref fragment
294        */
295        private String getRealSpec( URL url, String ref )
296        {
297            if( null != ref )
298            {
299                String spec = url.toString();
300                int j = spec.indexOf( ref );
301                if( j > 0 )
302                {
303                    String s = spec.substring( 0, j );
304                    String query = url.getQuery();
305                    if( null != query )
306                    {
307                        s = s + "?" + query;
308                    }
309                    String version = url.getUserInfo();
310                    if( null != version )
311                    {
312                        s = s + "#" + version;
313                    }
314                    return s;
315                }
316            }
317            return url.toString();
318        }
319    }