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.0.3 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 }