Java Source Code: org.apache.tools.ant.types.resources.URLResource


   1: /*
   2:  *  Licensed to the Apache Software Foundation (ASF) under one or more
   3:  *  contributor license agreements.  See the NOTICE file distributed with
   4:  *  this work for additional information regarding copyright ownership.
   5:  *  The ASF licenses this file to You under the Apache License, Version 2.0
   6:  *  (the "License"); you may not use this file except in compliance with
   7:  *  the License.  You may obtain a copy of the License at
   8:  *
   9:  *      http://www.apache.org/licenses/LICENSE-2.0
  10:  *
  11:  *  Unless required by applicable law or agreed to in writing, software
  12:  *  distributed under the License is distributed on an "AS IS" BASIS,
  13:  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14:  *  See the License for the specific language governing permissions and
  15:  *  limitations under the License.
  16:  *
  17:  */
  18: 
  19: package org.apache.tools.ant.types.resources;
  20: 
  21: import java.io.File;
  22: import java.io.IOException;
  23: import java.io.InputStream;
  24: import java.io.OutputStream;
  25: import java.net.HttpURLConnection;
  26: import java.net.URL;
  27: import java.net.URLConnection;
  28: import java.net.MalformedURLException;
  29: import java.net.JarURLConnection;
  30: import java.util.jar.JarFile;
  31: 
  32: import org.apache.tools.ant.Project;
  33: import org.apache.tools.ant.BuildException;
  34: import org.apache.tools.ant.types.Resource;
  35: import org.apache.tools.ant.types.Reference;
  36: import org.apache.tools.ant.util.FileUtils;
  37: 
  38: /**
  39:  * Exposes a URL as a Resource.
  40:  * @since Ant 1.7
  41:  */
  42:	  public class URLResource extends Resource {
  43:    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  44:    private static final int NULL_URL
  45:        = Resource.getMagicNumber("null URL".getBytes());
  46:
  47:    private URL url;
  48:    private URLConnection conn;
  49:
  50:    /**
  51:     * Default constructor.
  52:     */
  53:	      public URLResource() {
  54:    }
  55:
  56:    /**
  57:     * Convenience constructor.
  58:     * @param u the URL to expose.
  59:     */
  60:	      public URLResource(URL u) {
  61:        setURL(u);
  62:    }
  63:
  64:    /**
  65:     * Convenience constructor.
  66:     * @param f the File to set as a URL.
  67:     */
  68:	      public URLResource(File f) {
  69:        setFile(f);
  70:    }
  71:
  72:    /**
  73:     * String constructor for Ant attribute introspection.
  74:     * @param u String representation of this URL.
  75:     * @see org.apache.tools.ant.IntrospectionHelper
  76:     */
  77:	      public URLResource(String u) {
  78:        this(newURL(u));
  79:    }
  80:
  81:    /**
  82:     * Set the URL for this URLResource.
  83:     * @param u the URL to expose.
  84:     */
  85:	      public synchronized void setURL(URL u) {
  86:        checkAttributesAllowed();
  87:        url = u;
  88:    }
  89:
  90:    /**
  91:     * Set the URL from a File.
  92:     * @param f the File to set as a URL.
  93:     */
  94:	      public synchronized void setFile(File f) {
  95:	          try {
  96:            setURL(FILE_UTILS.getFileURL(f));
  97:        } catch (MalformedURLException e) {
  98:            throw new BuildException(e);
  99:        }
 100:    }
 101:
 102:    /**
 103:     * Get the URL used by this URLResource.
 104:     * @return a URL object.
 105:     */
 106:	      public synchronized URL getURL() {
 107:	          if (isReference()) {
 108:            return ((URLResource) getCheckedRef()).getURL();
 109:        }
 110:        return url;
 111:     }
 112:
 113:    /**
 114:     * Overrides the super version.
 115:     * @param r the Reference to set.
 116:     */
 117:	      public synchronized void setRefid(Reference r) {
 118:        //not using the accessor in this case to avoid side effects
 119:	          if (url != null) {
 120:            throw tooManyAttributes();
 121:        }
 122:        super.setRefid(r);
 123:    }
 124:
 125:    /**
 126:     * Get the name of this URLResource
 127:     * (its file component minus the leading separator).
 128:     * @return the name of this resource.
 129:     */
 130:	      public synchronized String getName() {
 131:        return isReference() ? ((Resource) getCheckedRef()).getName()
 132:            : getURL().getFile().substring(1);
 133:    }
 134:
 135:    /**
 136:     * Return this URLResource formatted as a String.
 137:     * @return a String representation of this URLResource.
 138:     */
 139:	      public synchronized String toString() {
 140:        return isReference()
 141:            ? getCheckedRef().toString() : String.valueOf(getURL());
 142:    }
 143:
 144:    /**
 145:     * Find out whether the URL exists .
 146:     * @return true if this resource exists.
 147:     */
 148:	      public synchronized boolean isExists() {
 149:	          if (isReference()) {
 150:            return ((Resource) getCheckedRef()).isExists();
 151:        }
 152:        return isExists(false);
 153:    }
 154:
 155:    /**
 156:     * Find out whether the URL exists, and close the connection
 157:     * opened to the URL if closeConnection is true.
 158:     *
 159:     * Note that this method does ensure that if:
 160:     * - the resource exists (if it returns true)
 161:     * - and if the current object is not a reference
 162:     * (isReference() returns false)
 163:     * - and if it was called with closeConnection to false,
 164:     *
 165:     * then the connection to the URL (stored in the conn
 166:     * private field) will be opened, and require to be closed
 167:     * by the caller.
 168:     *
 169:     * @param closeConnection true if the connection should be closed
 170:     * after the call, false if it should stay open.
 171:     * @return true if this resource exists.
 172:     */
 173:	      private synchronized boolean isExists(boolean closeConnection) {
 174:	          if (getURL() == null) {
 175:            return false;
 176:        }
 177:	          try {
 178:            connect();
 179:            return true;
 180:        } catch (IOException e) {
 181:            return false;
 182:        } finally {
 183:	              if (closeConnection) {
 184:                close();
 185:            }
 186:        }
 187:    }
 188:
 189:
 190:    /**
 191:     * Tells the modification time in milliseconds since 01.01.1970 .
 192:     *
 193:     * @return 0 if the resource does not exist to mirror the behavior
 194:     * of {@link java.io.File File}.
 195:     */
 196:	      public synchronized long getLastModified() {
 197:	          if (isReference()) {
 198:            return ((Resource) getCheckedRef()).getLastModified();
 199:        }
 200:	          if (!isExists(false)) {
 201:            return 0L;
 202:        }
 203:        return conn.getLastModified();
 204:    }
 205:
 206:    /**
 207:     * Tells if the resource is a directory.
 208:     * @return boolean whether the resource is a directory.
 209:     */
 210:	      public synchronized boolean isDirectory() {
 211:        return isReference()
 212:            ? ((Resource) getCheckedRef()).isDirectory()
 213:            : getName().endsWith("/");
 214:    }
 215:
 216:    /**
 217:     * Get the size of this Resource.
 218:     * @return the size, as a long, 0 if the Resource does not exist (for
 219:     *         compatibility with java.io.File), or UNKNOWN_SIZE if not known.
 220:     */
 221:	      public synchronized long getSize() {
 222:	          if (isReference()) {
 223:            return ((Resource) getCheckedRef()).getSize();
 224:        }
 225:	          if (!isExists(false)) {
 226:            return 0L;
 227:        }
 228:	          try {
 229:            connect();
 230:            long contentlength = conn.getContentLength();
 231:            close();
 232:            return contentlength;
 233:        } catch (IOException e) {
 234:            return UNKNOWN_SIZE;
 235:        }
 236:    }
 237:
 238:    /**
 239:     * Test whether an Object equals this URLResource.
 240:     * @param another the other Object to compare.
 241:     * @return true if the specified Object is equal to this Resource.
 242:     */
 243:	      public synchronized boolean equals(Object another) {
 244:	          if (this == another) {
 245:            return true;
 246:        }
 247:	          if (isReference()) {
 248:            return getCheckedRef().equals(another);
 249:        }
 250:	          if (!(another.getClass().equals(getClass()))) {
 251:            return false;
 252:        }
 253:        URLResource otheru = (URLResource) another;
 254:        return getURL() == null
 255:            ? otheru.getURL() == null
 256:            : getURL().equals(otheru.getURL());
 257:    }
 258:
 259:    /**
 260:     * Get the hash code for this Resource.
 261:     * @return hash code as int.
 262:     */
 263:	      public synchronized int hashCode() {
 264:	          if (isReference()) {
 265:            return getCheckedRef().hashCode();
 266:        }
 267:        return MAGIC * ((getURL() == null) ? NULL_URL : getURL().hashCode());
 268:    }
 269:
 270:    /**
 271:     * Get an InputStream for the Resource.
 272:     * @return an InputStream containing this Resource's content.
 273:     * @throws IOException if unable to provide the content of this
 274:     *         Resource as a stream.
 275:     * @throws UnsupportedOperationException if InputStreams are not
 276:     *         supported for this Resource type.
 277:     */
 278:	      public synchronized InputStream getInputStream() throws IOException {
 279:	          if (isReference()) {
 280:            return ((Resource) getCheckedRef()).getInputStream();
 281:        }
 282:        connect();
 283:	          try {
 284:            return conn.getInputStream();
 285:        } finally {
 286:            conn = null;
 287:        }
 288:    }
 289:
 290:    /**
 291:     * Get an OutputStream for the Resource.
 292:     * @return an OutputStream to which content can be written.
 293:     * @throws IOException if unable to provide the content of this
 294:     *         Resource as a stream.
 295:     * @throws UnsupportedOperationException if OutputStreams are not
 296:     *         supported for this Resource type.
 297:     * @throws IOException if the URL cannot be opened.
 298:     */
 299:	      public synchronized OutputStream getOutputStream() throws IOException {
 300:	          if (isReference()) {
 301:            return ((Resource) getCheckedRef()).getOutputStream();
 302:        }
 303:        connect();
 304:	          try {
 305:            return conn.getOutputStream();
 306:        } finally {
 307:            conn = null;
 308:        }
 309:    }
 310:
 311:    /**
 312:     * Ensure that we have a connection.
 313:     * @throws IOException if the connection cannot be established.
 314:     */
 315:	      protected synchronized void connect() throws IOException {
 316:        URL u = getURL();
 317:	          if (u == null) {
 318:            throw new BuildException("URL not set");
 319:        }
 320:	          if (conn == null) {
 321:	              try {
 322:                conn = u.openConnection();
 323:                conn.connect();
 324:            } catch (IOException e) {
 325:                log(e.toString(), Project.MSG_ERR);
 326:                conn = null;
 327:                throw e;
 328:            }
 329:        }
 330:    }
 331:
 332:    /**
 333:     * Closes the URL connection if:
 334:     * - it is opened (i.e. the field conn is not null)
 335:     * - this type of URLConnection supports some sort of close mechanism
 336:     *
 337:     * This method ensures the field conn will be null after the call.
 338:     *
 339:     */
 340:	      private synchronized void close() {
 341:	          if (conn != null) {
 342:	              try {
 343:	                  if (conn instanceof JarURLConnection) {
 344:                    JarURLConnection juc = (JarURLConnection) conn;
 345:                    JarFile jf = juc.getJarFile();
 346:                    jf.close();
 347:                    jf = null;
 348:                } else if (conn instanceof HttpURLConnection) {
 349:                    ((HttpURLConnection) conn).disconnect();
 350:                }
 351:            } catch (IOException exc) {
 352:                //ignore
 353:            } finally {
 354:                conn = null;
 355:            }
 356:        }
 357:    }
 358:
 359:	      private static URL newURL(String u) {
 360:	          try {
 361:            return new URL(u);
 362:        } catch (MalformedURLException e) {
 363:            throw new BuildException(e);
 364:        }
 365:    }
 366:
 367:}