001    /**
002     * <copyright> 
003     *
004     * Copyright (c) 2004-2006 IBM Corporation and others.
005     * All rights reserved.   This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors: 
011     *   IBM - Initial API and implementation
012     *
013     * </copyright>
014     *
015     * $Id$
016     */
017    package org.eclipse.emf.common.archive;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.net.URL;
022    import java.net.URLConnection;
023    import java.net.URLStreamHandler;
024    
025    /**
026     * A URL stream handler that can be {@link #register() registered} to support archive access protocol.
027     * It uses {@link ArchiveURLConnection} to implement the connection.
028     */
029    public class Handler extends URLStreamHandler
030    {
031      /**
032       * Registers this class.
033       * A handler for protocol "xyz" is registered 
034       * by providing a class named Handler implementing {@link URLStreamHandler}
035       * in a package called named xyz in a package of your choosing,
036       * and then registering that chosen prefix package name 
037       * in the system property for <code>"java.protocol.handler.pkgs"</code>,
038       * which is an "|" separated list of package prefixes to search for handlers.
039       */
040      public static void register()
041      {
042        String javaProtocolHandlerPkgs = System.getProperty("java.protocol.handler.pkgs");
043        if (javaProtocolHandlerPkgs == null || javaProtocolHandlerPkgs.length() == 0)
044        {
045          javaProtocolHandlerPkgs = "org.eclipse.emf.common";
046        }
047        else
048        {
049          javaProtocolHandlerPkgs += "|org.eclipse.emf.common";
050        }
051        System.setProperty("java.protocol.handler.pkgs", javaProtocolHandlerPkgs); 
052      }
053      
054      /**
055       * Registers this handler and interprets each argument as URL to be opened, read in, and written out to System.out.
056       * @param args URLs to open, read, and write to System.out
057       * @throws IOException if there are problems opening or reading from the URLs, or writing to System.out.
058       */
059      public static void main(String[] args) throws IOException
060      {
061        register();
062        
063        for (int i = 0; i < args.length; ++i)
064        {
065          InputStream inputStream = new URL(args[i]).openStream();
066          byte [] bytes = new byte [4048];
067          for (int size; (size = inputStream.read(bytes, 0, bytes.length)) > -1; )
068          {
069            System.out.write(bytes, 0, size);
070          }
071        }
072      }
073      
074      /**
075       *  Creates an instance.
076       */
077      public Handler()
078      {
079        super();
080      }
081      
082      /**
083       * Overrides parsing the URL to validate constraints on well formed archive syntax.
084       * @see URLStreamHandler#parseURL(java.net.URL, java.lang.String, int, int)
085       */
086      @Override
087      protected void parseURL(URL url, String specification, int start, int limit)
088      {
089        super.parseURL(url, specification, start, limit);
090          
091        // There needs to be another URL protocol right after the archive protocol, and not a "/".
092        //
093        if (start > limit || specification.charAt(start) == '/')
094        {
095          throw 
096            new IllegalArgumentException
097              ("archive protocol must be immediately followed by another URL protocol " + specification);
098        }
099        
100        // There must be at least one archive path.
101        //
102        int archiveSeparator = specification.indexOf("!/", start);
103        if (archiveSeparator < 0)
104        {
105          throw new IllegalArgumentException("missing archive separators " + specification.substring(start, limit));
106        }
107              
108        // Parse to count the archive paths that must will be delegated to the nested URL based on the number of schemes at the start.
109        //
110        for (int i = start, end = specification.indexOf('/', start) - 1; (i = specification.indexOf(':', i)) < end; ++i)
111        {
112          // There should be at least one archive separator per scheme.
113          //
114          archiveSeparator = specification.indexOf("!/", archiveSeparator + 2);
115          if (archiveSeparator < 0)
116          {
117            throw new IllegalArgumentException("too few archive separators " + specification);
118          }
119        }
120      }
121      
122      /**
123       *  Returns a new {@link ArchiveURLConnection}.
124       */
125      @Override
126      protected URLConnection openConnection(URL url) throws IOException
127      {
128        return new ArchiveURLConnection(url);
129      }
130    }