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.resources;
019:
020: import java.io.InputStream;
021: import java.io.IOException;
022: import java.io.OutputStream;
023:
024: import org.apache.tools.ant.BuildException;
025: import org.apache.tools.ant.types.Resource;
026: import org.apache.tools.ant.types.Reference;
027: import org.apache.tools.ant.types.ResourceCollection;
028: import org.apache.tools.ant.util.FileUtils;
029:
030: /**
031: * A compressed resource.
032: *
033: * <p>Wraps around another resource, delegates all queries (except
034: * getSize) to that other resource but uncompresses/compresses streams
035: * on the fly.</p>
036: *
037: * @since Ant 1.7
038: */
039: public abstract class CompressedResource extends Resource {
040:
041: private Resource resource;
042:
043: /** no arg constructor */
044: public CompressedResource() {
045: }
046:
047: /**
048: * Constructor with another resource to wrap.
049: * @param other the resource to wrap.
050: */
051: public CompressedResource(ResourceCollection other) {
052: addConfigured(other);
053: }
054:
055: /**
056: * Sets the resource to wrap using a single-element collection.
057: * @param a the resource to wrap as a single element Resource collection.
058: */
059: public void addConfigured(ResourceCollection a) {
060: checkChildrenAllowed();
061: if (resource != null) {
062: throw new BuildException(
063: "you must not specify more than one" + " resource");
064: }
065: if (a.size() != 1) {
066: throw new BuildException(
067: "only single argument resource collections"
068: + " are supported");
069: }
070: resource = (Resource) a.iterator().next();
071: }
072:
073: /**
074: * Get the name of the resource.
075: * @return the name of the wrapped resource.
076: */
077: public String getName() {
078: return getResource().getName();
079: }
080:
081: /**
082: * Overridden, not allowed to set the name of the resource.
083: * @param name not used.
084: * @throws BuildException always.
085: */
086: public void setName(String name) throws BuildException {
087: throw new BuildException(
088: "you can't change the name of a compressed"
089: + " resource");
090: }
091:
092: /**
093: * The exists attribute tells whether a file exists.
094: * @return true if this resource exists.
095: */
096: public boolean isExists() {
097: return getResource().isExists();
098: }
099:
100: /**
101: * Set the exists attribute.
102: * @param exists if true, this resource exists.
103: */
104: public void setExists(boolean exists) {
105: throw new BuildException(
106: "you can't change the exists state of a "
107: + " compressed resource");
108: }
109:
110: /**
111: * Tells the modification time in milliseconds since 01.01.1970 .
112: *
113: * @return 0 if the resource does not exist to mirror the behavior
114: * of {@link java.io.File File}.
115: */
116: public long getLastModified() {
117: return getResource().getLastModified();
118: }
119:
120: /**
121: * Override setLastModified.
122: * @param lastmodified not used.
123: * @throws BuildException always.
124: */
125: public void setLastModified(long lastmodified)
126: throws BuildException {
127: throw new BuildException("you can't change the timestamp of a "
128: + " compressed resource");
129: }
130:
131: /**
132: * Tells if the resource is a directory.
133: * @return boolean flag indicating if the resource is a directory.
134: */
135: public boolean isDirectory() {
136: return getResource().isDirectory();
137: }
138:
139: /**
140: * Override setDirectory.
141: * @param directory not used.
142: * @throws BuildException always.
143: */
144: public void setDirectory(boolean directory) throws BuildException {
145: throw new BuildException(
146: "you can't change the directory state of a "
147: + " compressed resource");
148: }
149:
150: /**
151: * Get the size of this Resource.
152: * @return the size, as a long, 0 if the Resource does not exist (for
153: * compatibility with java.io.File), or UNKNOWN_SIZE if not known.
154: */
155: public long getSize() {
156: if (isExists()) {
157: InputStream in = null;
158: try {
159: in = getInputStream();
160: byte[] buf = new byte[8192];
161: int size = 0;
162: int readNow;
163: while ((readNow = in.read(buf, 0, buf.length)) > 0) {
164: size += readNow;
165: }
166: return size;
167: } catch (IOException ex) {
168: throw new BuildException(
169: "caught exception while reading " + getName(),
170: ex);
171: } finally {
172: FileUtils.close(in);
173: }
174: } else {
175: return 0;
176: }
177: }
178:
179: /**
180: * Override setSize.
181: * @param size not used.
182: * @throws BuildException always.
183: */
184: public void setSize(long size) throws BuildException {
185: throw new BuildException("you can't change the size of a "
186: + " compressed resource");
187: }
188:
189: /**
190: * Delegates to a comparison of names.
191: * @param other the object to compare to.
192: * @return a negative integer, zero, or a positive integer as this Resource
193: * is less than, equal to, or greater than the specified Resource.
194: */
195: public int compareTo(Object other) {
196: if (other == this ) {
197: return 0;
198: }
199: if (other instanceof CompressedResource) {
200: return getResource().compareTo(
201: ((CompressedResource) other).getResource());
202: }
203: return getResource().compareTo(other);
204: }
205:
206: /**
207: * Get the hash code for this Resource.
208: * @return hash code as int.
209: */
210: public int hashCode() {
211: return getResource().hashCode();
212: }
213:
214: /**
215: * Get an InputStream for the Resource.
216: * @return an InputStream containing this Resource's content.
217: * @throws IOException if unable to provide the content of this
218: * Resource as a stream.
219: * @throws UnsupportedOperationException if InputStreams are not
220: * supported for this Resource type.
221: */
222: public InputStream getInputStream() throws IOException {
223: InputStream in = getResource().getInputStream();
224: if (in != null) {
225: in = wrapStream(in);
226: }
227: return in;
228: }
229:
230: /**
231: * Get an OutputStream for the Resource.
232: * @return an OutputStream to which content can be written.
233: * @throws IOException if unable to provide the content of this
234: * Resource as a stream.
235: * @throws UnsupportedOperationException if OutputStreams are not
236: * supported for this Resource type.
237: */
238: public OutputStream getOutputStream() throws IOException {
239: OutputStream out = getResource().getOutputStream();
240: if (out != null) {
241: out = wrapStream(out);
242: }
243: return out;
244: }
245:
246: /**
247: * Fulfill the ResourceCollection contract.
248: * @return whether this Resource is a FileResource.
249: */
250: public boolean isFilesystemOnly() {
251: return false;
252: }
253:
254: /**
255: * Get the string representation of this Resource.
256: * @return this Resource formatted as a String.
257: * @since Ant 1.7
258: */
259: public String toString() {
260: return getCompressionName() + " compressed "
261: + getResource().toString();
262: }
263:
264: /**
265: * Overrides the base version.
266: * @param r the Reference to set.
267: */
268: public void setRefid(Reference r) {
269: if (resource != null) {
270: throw noChildrenAllowed();
271: }
272: super .setRefid(r);
273: }
274:
275: /**
276: * Is supposed to wrap the stream to allow decompression on the fly.
277: *
278: * @param in InputStream to wrap, will never be null.
279: * @return a compressed inputstream.
280: * @throws IOException if there is a problem.
281: */
282: protected abstract InputStream wrapStream(InputStream in)
283: throws IOException;
284:
285: /**
286: * Is supposed to wrap the stream to allow compression on the fly.
287: *
288: * @param out OutputStream to wrap, will never be null.
289: * @return a compressed outputstream.
290: * @throws IOException if there is a problem.
291: */
292: protected abstract OutputStream wrapStream(OutputStream out)
293: throws IOException;
294:
295: /**
296: * @return the name of the compression method.
297: */
298: protected abstract String getCompressionName();
299:
300: private Resource getResource() {
301: if (isReference()) {
302: return (Resource) getCheckedRef();
303: } else if (resource == null) {
304: throw new BuildException("no resource specified");
305: }
306: return resource;
307: }
308:
309: }
|