001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. 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 implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.types;
019:
020: import java.io.InputStream;
021: import java.io.IOException;
022: import java.io.OutputStream;
023: import java.math.BigInteger;
024: import java.util.Iterator;
025: import java.util.NoSuchElementException;
026:
027: /**
028: * Describes a "File-like" resource (File, ZipEntry, etc.).
029: *
030: * This class is meant to be used by classes needing to record path
031: * and date/time information about a file, a zip entry or some similar
032: * resource (URL, archive in a version control repository, ...).
033: *
034: * @since Ant 1.5.2
035: * @see org.apache.tools.ant.types.resources.Touchable
036: */
037: public class Resource extends DataType implements Cloneable,
038: Comparable, ResourceCollection {
039:
040: /** Constant unknown size */
041: public static final long UNKNOWN_SIZE = -1;
042:
043: /** Constant unknown datetime for getLastModified */
044: public static final long UNKNOWN_DATETIME = 0L;
045:
046: /** Magic number */
047: protected static final int MAGIC = getMagicNumber("Resource"
048: .getBytes());
049:
050: private static final int NULL_NAME = getMagicNumber("null name"
051: .getBytes());
052:
053: /**
054: * Create a "magic number" for use in hashCode calculations.
055: * @param seed byte[] to seed with.
056: * @return a magic number as int.
057: */
058: protected static int getMagicNumber(byte[] seed) {
059: return new BigInteger(seed).intValue();
060: }
061:
062: private String name = null;
063: private Boolean exists = null;
064: private Long lastmodified = null;
065: private Boolean directory = null;
066: private Long size = null;
067:
068: /**
069: * Default constructor.
070: */
071: public Resource() {
072: }
073:
074: /**
075: * Only sets the name.
076: *
077: * <p>This is a dummy, used for not existing resources.</p>
078: *
079: * @param name relative path of the resource. Expects
080: * "/" to be used as the directory separator.
081: */
082: public Resource(String name) {
083: this (name, false, 0, false);
084: }
085:
086: /**
087: * Sets the name, lastmodified flag, and exists flag.
088: *
089: * @param name relative path of the resource. Expects
090: * "/" to be used as the directory separator.
091: * @param exists if true, this resource exists.
092: * @param lastmodified the last modification time of this resource.
093: */
094: public Resource(String name, boolean exists, long lastmodified) {
095: this (name, exists, lastmodified, false);
096: }
097:
098: /**
099: * Sets the name, lastmodified flag, exists flag, and directory flag.
100: *
101: * @param name relative path of the resource. Expects
102: * "/" to be used as the directory separator.
103: * @param exists if true the resource exists
104: * @param lastmodified the last modification time of the resource
105: * @param directory if true, this resource is a directory
106: */
107: public Resource(String name, boolean exists, long lastmodified,
108: boolean directory) {
109: this (name, exists, lastmodified, directory, UNKNOWN_SIZE);
110: }
111:
112: /**
113: * Sets the name, lastmodified flag, exists flag, directory flag, and size.
114: *
115: * @param name relative path of the resource. Expects
116: * "/" to be used as the directory separator.
117: * @param exists if true the resource exists
118: * @param lastmodified the last modification time of the resource
119: * @param directory if true, this resource is a directory
120: * @param size the size of this resource.
121: */
122: public Resource(String name, boolean exists, long lastmodified,
123: boolean directory, long size) {
124: this .name = name;
125: setName(name);
126: setExists(exists);
127: setLastModified(lastmodified);
128: setDirectory(directory);
129: setSize(size);
130: }
131:
132: /**
133: * Name attribute will contain the path of a file relative to the
134: * root directory of its fileset or the recorded path of a zip
135: * entry.
136: *
137: * <p>example for a file with fullpath /var/opt/adm/resource.txt
138: * in a file set with root dir /var/opt it will be
139: * adm/resource.txt.</p>
140: *
141: * <p>"/" will be used as the directory separator.</p>
142: * @return the name of this resource.
143: */
144: public String getName() {
145: return isReference() ? ((Resource) getCheckedRef()).getName()
146: : name;
147: }
148:
149: /**
150: * Set the name of this Resource.
151: * @param name relative path of the resource. Expects
152: * "/" to be used as the directory separator.
153: */
154: public void setName(String name) {
155: checkAttributesAllowed();
156: this .name = name;
157: }
158:
159: /**
160: * The exists attribute tells whether a file exists.
161: * @return true if this resource exists.
162: */
163: public boolean isExists() {
164: if (isReference()) {
165: return ((Resource) getCheckedRef()).isExists();
166: }
167: //default true:
168: return exists == null || exists.booleanValue();
169: }
170:
171: /**
172: * Set the exists attribute.
173: * @param exists if true, this resource exists.
174: */
175: public void setExists(boolean exists) {
176: checkAttributesAllowed();
177: this .exists = exists ? Boolean.TRUE : Boolean.FALSE;
178: }
179:
180: /**
181: * Tells the modification time in milliseconds since 01.01.1970 .
182: *
183: * @return 0 if the resource does not exist to mirror the behavior
184: * of {@link java.io.File File}.
185: */
186: public long getLastModified() {
187: if (isReference()) {
188: return ((Resource) getCheckedRef()).getLastModified();
189: }
190: if (!isExists() || lastmodified == null) {
191: return UNKNOWN_DATETIME;
192: }
193: long result = lastmodified.longValue();
194: return result < UNKNOWN_DATETIME ? UNKNOWN_DATETIME : result;
195: }
196:
197: /**
198: * Set the last modification attribute.
199: * @param lastmodified the modification time in milliseconds since 01.01.1970.
200: */
201: public void setLastModified(long lastmodified) {
202: checkAttributesAllowed();
203: this .lastmodified = new Long(lastmodified);
204: }
205:
206: /**
207: * Tells if the resource is a directory.
208: * @return boolean flag indicating if the resource is a directory.
209: */
210: public boolean isDirectory() {
211: if (isReference()) {
212: return ((Resource) getCheckedRef()).isDirectory();
213: }
214: //default false:
215: return directory != null && directory.booleanValue();
216: }
217:
218: /**
219: * Set the directory attribute.
220: * @param directory if true, this resource is a directory.
221: */
222: public void setDirectory(boolean directory) {
223: checkAttributesAllowed();
224: this .directory = directory ? Boolean.TRUE : Boolean.FALSE;
225: }
226:
227: /**
228: * Set the size of this Resource.
229: * @param size the size, as a long.
230: * @since Ant 1.6.3
231: */
232: public void setSize(long size) {
233: checkAttributesAllowed();
234: this .size = new Long(size > UNKNOWN_SIZE ? size : UNKNOWN_SIZE);
235: }
236:
237: /**
238: * Get the size of this Resource.
239: * @return the size, as a long, 0 if the Resource does not exist (for
240: * compatibility with java.io.File), or UNKNOWN_SIZE if not known.
241: * @since Ant 1.6.3
242: */
243: public long getSize() {
244: if (isReference()) {
245: return ((Resource) getCheckedRef()).getSize();
246: }
247: return isExists() ? (size != null ? size.longValue()
248: : UNKNOWN_SIZE) : 0L;
249: }
250:
251: /**
252: * Clone this Resource.
253: * @return copy of this.
254: */
255: public Object clone() {
256: try {
257: return super .clone();
258: } catch (CloneNotSupportedException e) {
259: throw new UnsupportedOperationException(
260: "CloneNotSupportedException for a Resource caught. "
261: + "Derived classes must support cloning.");
262: }
263: }
264:
265: /**
266: * Delegates to a comparison of names.
267: * @param other the object to compare to.
268: * @return a negative integer, zero, or a positive integer as this Resource
269: * is less than, equal to, or greater than the specified Resource.
270: * @since Ant 1.6
271: */
272: public int compareTo(Object other) {
273: if (isReference()) {
274: return ((Comparable) getCheckedRef()).compareTo(other);
275: }
276: if (!(other instanceof Resource)) {
277: throw new IllegalArgumentException(
278: "Can only be compared with Resources");
279: }
280: return toString().compareTo(other.toString());
281: }
282:
283: /**
284: * Implement basic Resource equality.
285: * @param other the object to check against.
286: * @return true if the specified Object is equal to this Resource.
287: * @since Ant 1.7
288: */
289: public boolean equals(Object other) {
290: if (isReference()) {
291: return getCheckedRef().equals(other);
292: }
293: return other.getClass().equals(getClass())
294: && compareTo(other) == 0;
295: }
296:
297: /**
298: * Get the hash code for this Resource.
299: * @return hash code as int.
300: * @since Ant 1.7
301: */
302: public int hashCode() {
303: if (isReference()) {
304: return getCheckedRef().hashCode();
305: }
306: String name = getName();
307: return MAGIC * (name == null ? NULL_NAME : name.hashCode());
308: }
309:
310: /**
311: * Get an InputStream for the Resource.
312: * @return an InputStream containing this Resource's content.
313: * @throws IOException if unable to provide the content of this
314: * Resource as a stream.
315: * @throws UnsupportedOperationException if InputStreams are not
316: * supported for this Resource type.
317: * @since Ant 1.7
318: */
319: public InputStream getInputStream() throws IOException {
320: if (isReference()) {
321: return ((Resource) getCheckedRef()).getInputStream();
322: }
323: throw new UnsupportedOperationException();
324: }
325:
326: /**
327: * Get an OutputStream for the Resource.
328: * @return an OutputStream to which content can be written.
329: * @throws IOException if unable to provide the content of this
330: * Resource as a stream.
331: * @throws UnsupportedOperationException if OutputStreams are not
332: * supported for this Resource type.
333: * @since Ant 1.7
334: */
335: public OutputStream getOutputStream() throws IOException {
336: if (isReference()) {
337: return ((Resource) getCheckedRef()).getOutputStream();
338: }
339: throw new UnsupportedOperationException();
340: }
341:
342: /**
343: * Fulfill the ResourceCollection contract.
344: * @return an Iterator of Resources.
345: * @since Ant 1.7
346: */
347: public Iterator iterator() {
348: return isReference() ? ((Resource) getCheckedRef()).iterator()
349: : new Iterator() {
350: private boolean done = false;
351:
352: public boolean hasNext() {
353: return !done;
354: }
355:
356: public Object next() {
357: if (done) {
358: throw new NoSuchElementException();
359: }
360: done = true;
361: return Resource.this ;
362: }
363:
364: public void remove() {
365: throw new UnsupportedOperationException();
366: }
367: };
368: }
369:
370: /**
371: * Fulfill the ResourceCollection contract.
372: * @return the size of this ResourceCollection.
373: * @since Ant 1.7
374: */
375: public int size() {
376: return isReference() ? ((Resource) getCheckedRef()).size() : 1;
377: }
378:
379: /**
380: * Fulfill the ResourceCollection contract.
381: * @return whether this Resource is a FileResource.
382: * @since Ant 1.7
383: */
384: public boolean isFilesystemOnly() {
385: //default false:
386: return isReference()
387: && ((Resource) getCheckedRef()).isFilesystemOnly();
388: }
389:
390: /**
391: * Get the string representation of this Resource.
392: * @return this Resource formatted as a String.
393: * @since Ant 1.7
394: */
395: public String toString() {
396: if (isReference()) {
397: return getCheckedRef().toString();
398: }
399: String n = getName();
400: return n == null ? "(anonymous)" : n;
401: }
402:
403: /**
404: * Get a long String representation of this Resource.
405: * This typically should be the value of <code>toString()</code>
406: * prefixed by a type description.
407: * @return this Resource formatted as a long String.
408: * @since Ant 1.7
409: */
410: public final String toLongString() {
411: return isReference() ? ((Resource) getCheckedRef())
412: .toLongString() : getDataTypeName() + " \""
413: + toString() + '"';
414: }
415:
416: /**
417: * Overrides the base version.
418: * @param r the Reference to set.
419: */
420: public void setRefid(Reference r) {
421: if (name != null || exists != null || lastmodified != null
422: || directory != null || size != null) {
423: throw tooManyAttributes();
424: }
425: super.setRefid(r);
426: }
427:
428: }
|