diff --git a/.classpath b/.classpath index 81bbbfc6da7..7b5916556a0 100644 --- a/.classpath +++ b/.classpath @@ -7,30 +7,9 @@ - - - - - - - - - - - - - - - - - - - - - - + diff --git a/.project b/.project index 572b2b3c1e7..f8629a548c9 100644 --- a/.project +++ b/.project @@ -43,5 +43,6 @@ org.sonar.ide.eclipse.core.sonarNature sf.eclipse.javacc.javaccnature net.sf.eclipsecs.core.CheckstyleNature + org.apache.ivyde.eclipse.ivynature diff --git a/.travis.yml b/.travis.yml index f6911d20991..88a2b6c5984 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,10 @@ before_install: - > case "${TRAVIS_OS_NAME:-linux}" in linux) + ant resolve ;; osx) + ant resolve brew update brew install ant ;; diff --git a/build.xml b/build.xml index 1d20d1b0a54..e0471bc0e89 100644 --- a/build.xml +++ b/build.xml @@ -8,8 +8,8 @@ ** https://josm.openstreetmap.de/wiki/DevelopersGuide/CreateBuild ** --> - - + + - + @@ -116,7 +109,7 @@ - + @@ -136,7 +129,7 @@ - + @@ -172,6 +165,14 @@ Build-Date: ${build.tstamp} + + + + + + + + @@ -189,13 +190,61 @@ Build-Date: ${build.tstamp} - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - + + @@ -254,9 +304,10 @@ Build-Date: ${build.tstamp} + - + @@ -267,92 +318,26 @@ Build-Date: ${build.tstamp} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + @@ -392,12 +377,13 @@ Build-Date: ${build.tstamp} JOSM - Javadoc]]> @@ -412,7 +398,7 @@ Build-Date: ${build.tstamp} - + @@ -422,6 +408,9 @@ Build-Date: ${build.tstamp} + @@ -431,7 +420,7 @@ Build-Date: ${build.tstamp} - + @@ -440,7 +429,8 @@ Build-Date: ${build.tstamp} - + + @@ -467,7 +457,7 @@ Build-Date: ${build.tstamp} - + @@ -578,11 +568,14 @@ Build-Date: ${build.tstamp} - + + + -injars ${dist.jar} -outjars ${dist-optimized.jar} + -libraryjars ${library.jars} -libraryjars ${java.home}/lib -dontoptimize @@ -647,8 +640,9 @@ Build-Date: ${build.tstamp} + - + @@ -718,7 +712,7 @@ Build-Date: ${build.tstamp} - + @@ -786,7 +780,12 @@ Build-Date: ${build.tstamp} - + + + + + + @@ -800,7 +799,7 @@ Build-Date: ${build.tstamp} - + <_taginfo type="mappaint" output="taginfo_style.json"/> @@ -808,10 +807,14 @@ Build-Date: ${build.tstamp} <_taginfo type="external_presets" output="taginfo_external_presets.json"/> - - + + - + + + + + @@ -841,28 +844,37 @@ Build-Date: ${build.tstamp} + + + + + + + + + - + + encoding="UTF-8" classpathref="checkstyle.path"> + - + - + - - + + @@ -873,28 +885,27 @@ Build-Date: ${build.tstamp} - - - - - - - + + + + + + - - + + + ${pmd.dir}/josm-ruleset.xml @@ -920,7 +931,7 @@ Build-Date: ${build.tstamp} - + + + + + + + + + + + + + + + + + + + diff --git a/ivy.xml b/ivy.xml new file mode 100644 index 00000000000..19d9dbb531d --- /dev/null +++ b/ivy.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ivysettings.xml b/ivysettings.xml new file mode 100644 index 00000000000..7f0c3c9bbdf --- /dev/null +++ b/ivysettings.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/org/apache/commons/compress/MemoryLimitException.java b/src/org/apache/commons/compress/MemoryLimitException.java deleted file mode 100644 index d251fb3f7e9..00000000000 --- a/src/org/apache/commons/compress/MemoryLimitException.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress; - -import java.io.IOException; - -/** - * If a stream checks for estimated memory allocation, and the estimate - * goes above the memory limit, this is thrown. This can also be thrown - * if a stream tries to allocate a byte array that is larger than - * the allowable limit. - * - * @since 1.14 - */ -public class MemoryLimitException extends IOException { - - private static final long serialVersionUID = 1L; - - //long instead of int to account for overflow for corrupt files - private final long memoryNeededInKb; - private final int memoryLimitInKb; - - public MemoryLimitException(long memoryNeededInKb, int memoryLimitInKb) { - super(buildMessage(memoryNeededInKb, memoryLimitInKb)); - this.memoryNeededInKb = memoryNeededInKb; - this.memoryLimitInKb = memoryLimitInKb; - } - - public MemoryLimitException(long memoryNeededInKb, int memoryLimitInKb, Exception e) { - super(buildMessage(memoryNeededInKb, memoryLimitInKb), e); - this.memoryNeededInKb = memoryNeededInKb; - this.memoryLimitInKb = memoryLimitInKb; - } - - public long getMemoryNeededInKb() { - return memoryNeededInKb; - } - - public int getMemoryLimitInKb() { - return memoryLimitInKb; - } - - private static String buildMessage(long memoryNeededInKb, int memoryLimitInKb) { - return memoryNeededInKb + " kb of memory would be needed; limit was " - + memoryLimitInKb + " kb. " + - "If the file is not corrupt, consider increasing the memory limit."; - } -} diff --git a/src/org/apache/commons/compress/PasswordRequiredException.java b/src/org/apache/commons/compress/PasswordRequiredException.java deleted file mode 100644 index d876b96b0e1..00000000000 --- a/src/org/apache/commons/compress/PasswordRequiredException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress; - -import java.io.IOException; - -/** - * Exception thrown when trying to read an encrypted entry or file without - * configuring a password. - * @since 1.10 - */ -public class PasswordRequiredException extends IOException { - - private static final long serialVersionUID = 1391070005491684483L; - - /** - * Create a new exception. - * - * @param name name of the archive containing encrypted streams or - * the encrypted file. - */ - public PasswordRequiredException(final String name) { - super("Cannot read encrypted content from " + name + " without a password."); - } -} diff --git a/src/org/apache/commons/compress/archivers/ArchiveEntry.java b/src/org/apache/commons/compress/archivers/ArchiveEntry.java deleted file mode 100644 index d5fa746a65a..00000000000 --- a/src/org/apache/commons/compress/archivers/ArchiveEntry.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -import java.util.Date; - -/** - * Represents an entry of an archive. - */ -public interface ArchiveEntry { - - /** - * Gets the name of the entry in this archive. May refer to a file or directory or other item. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return The name of this entry in the archive. - */ - String getName(); - - /** - * Gets the uncompressed size of this entry. May be -1 (SIZE_UNKNOWN) if the size is unknown - * - * @return the uncompressed size of this entry. - */ - long getSize(); - - /** Special value indicating that the size is unknown */ - long SIZE_UNKNOWN = -1; - - /** - * Returns true if this entry refers to a directory. - * - * @return true if this entry refers to a directory. - */ - boolean isDirectory(); - - /** - * Gets the last modified date of this entry. - * - * @return the last modified date of this entry. - * @since 1.1 - */ - Date getLastModifiedDate(); -} diff --git a/src/org/apache/commons/compress/archivers/ArchiveException.java b/src/org/apache/commons/compress/archivers/ArchiveException.java deleted file mode 100644 index bb577850c06..00000000000 --- a/src/org/apache/commons/compress/archivers/ArchiveException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -/** - * Archiver related Exception - */ -public class ArchiveException extends Exception { - - /** Serial */ - private static final long serialVersionUID = 2772690708123267100L; - - /** - * Constructs a new exception with the specified detail message. The cause - * is not initialized. - * - * @param message - * the detail message - */ - public ArchiveException(final String message) { - super(message); - } - - /** - * Constructs a new exception with the specified detail message and cause. - * - * @param message - * the detail message - * @param cause - * the cause - */ - public ArchiveException(final String message, final Exception cause) { - super(message); - this.initCause(cause); - } -} diff --git a/src/org/apache/commons/compress/archivers/ArchiveInputStream.java b/src/org/apache/commons/compress/archivers/ArchiveInputStream.java deleted file mode 100644 index 9c4e9782113..00000000000 --- a/src/org/apache/commons/compress/archivers/ArchiveInputStream.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Archive input streams MUST override the - * {@link #read(byte[], int, int)} - or {@link #read()} - - * method so that reading from the stream generates EOF for the end of - * data in each entry as well as at the end of the file proper. - *

- * The {@link #getNextEntry()} method is used to reset the input stream - * ready for reading the data from the next entry. - *

- * The input stream classes must also implement a method with the signature: - *

- * public static boolean matches(byte[] signature, int length)
- * 
- * which is used by the {@link ArchiveStreamFactory} to autodetect - * the archive type from the first few bytes of a stream. - */ -public abstract class ArchiveInputStream extends InputStream { - - private final byte[] single = new byte[1]; - private static final int BYTE_MASK = 0xFF; - - /** holds the number of bytes read in this stream */ - private long bytesRead = 0; - - /** - * Returns the next Archive Entry in this Stream. - * - * @return the next entry, - * or {@code null} if there are no more entries - * @throws IOException if the next entry could not be read - */ - public abstract ArchiveEntry getNextEntry() throws IOException; - - /* - * Note that subclasses also implement specific get() methods which - * return the appropriate class without need for a cast. - * See SVN revision r743259 - * @return - * @throws IOException - */ - // public abstract XXXArchiveEntry getNextXXXEntry() throws IOException; - - /** - * Reads a byte of data. This method will block until enough input is - * available. - * - * Simply calls the {@link #read(byte[], int, int)} method. - * - * MUST be overridden if the {@link #read(byte[], int, int)} method - * is not overridden; may be overridden otherwise. - * - * @return the byte read, or -1 if end of input is reached - * @throws IOException - * if an I/O error has occurred - */ - @Override - public int read() throws IOException { - final int num = read(single, 0, 1); - return num == -1 ? -1 : single[0] & BYTE_MASK; - } - - /** - * Increments the counter of already read bytes. - * Doesn't increment if the EOF has been hit (read == -1) - * - * @param read the number of bytes read - */ - protected void count(final int read) { - count((long) read); - } - - /** - * Increments the counter of already read bytes. - * Doesn't increment if the EOF has been hit (read == -1) - * - * @param read the number of bytes read - * @since 1.1 - */ - protected void count(final long read) { - if (read != -1) { - bytesRead = bytesRead + read; - } - } - - /** - * Decrements the counter of already read bytes. - * - * @param pushedBack the number of bytes pushed back. - * @since 1.1 - */ - protected void pushedBackBytes(final long pushedBack) { - bytesRead -= pushedBack; - } - - /** - * Returns the current number of bytes read from this stream. - * @return the number of read bytes - * @deprecated this method may yield wrong results for large - * archives, use #getBytesRead instead - */ - @Deprecated - public int getCount() { - return (int) bytesRead; - } - - /** - * Returns the current number of bytes read from this stream. - * @return the number of read bytes - * @since 1.1 - */ - public long getBytesRead() { - return bytesRead; - } - - /** - * Whether this stream is able to read the given entry. - * - *

- * Some archive formats support variants or details that are not supported (yet). - *

- * - * @param archiveEntry - * the entry to test - * @return This implementation always returns true. - * - * @since 1.1 - */ - public boolean canReadEntryData(final ArchiveEntry archiveEntry) { - return true; - } - -} diff --git a/src/org/apache/commons/compress/archivers/ArchiveOutputStream.java b/src/org/apache/commons/compress/archivers/ArchiveOutputStream.java deleted file mode 100644 index 4377b6dc449..00000000000 --- a/src/org/apache/commons/compress/archivers/ArchiveOutputStream.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Archive output stream implementations are expected to override the - * {@link #write(byte[], int, int)} method to improve performance. - * They should also override {@link #close()} to ensure that any necessary - * trailers are added. - * - *

The normal sequence of calls when working with ArchiveOutputStreams is:

- *
    - *
  • Create ArchiveOutputStream object,
  • - *
  • optionally write SFX header (Zip only),
  • - *
  • repeat as needed: - *
      - *
    • {@link #putArchiveEntry(ArchiveEntry)} (writes entry header), - *
    • {@link #write(byte[])} (writes entry data, as often as needed), - *
    • {@link #closeArchiveEntry()} (closes entry), - *
    - *
  • - *
  • {@link #finish()} (ends the addition of entries),
  • - *
  • optionally write additional data, provided format supports it,
  • - *
  • {@link #close()}.
  • - *
- */ -public abstract class ArchiveOutputStream extends OutputStream { - - /** Temporary buffer used for the {@link #write(int)} method */ - private final byte[] oneByte = new byte[1]; - static final int BYTE_MASK = 0xFF; - - /** holds the number of bytes written to this stream */ - private long bytesWritten = 0; - // Methods specific to ArchiveOutputStream - - /** - * Writes the headers for an archive entry to the output stream. - * The caller must then write the content to the stream and call - * {@link #closeArchiveEntry()} to complete the process. - * - * @param entry describes the entry - * @throws IOException if an I/O error occurs - */ - public abstract void putArchiveEntry(ArchiveEntry entry) throws IOException; - - /** - * Closes the archive entry, writing any trailer information that may - * be required. - * @throws IOException if an I/O error occurs - */ - public abstract void closeArchiveEntry() throws IOException; - - /** - * Finishes the addition of entries to this stream, without closing it. - * Additional data can be written, if the format supports it. - * - * @throws IOException if the user forgets to close the entry. - */ - public abstract void finish() throws IOException; - - /** - * Create an archive entry using the inputFile and entryName provided. - * - * @param inputFile the file to create the entry from - * @param entryName name to use for the entry - * @return the ArchiveEntry set up with details from the file - * - * @throws IOException if an I/O error occurs - */ - public abstract ArchiveEntry createArchiveEntry(File inputFile, String entryName) throws IOException; - - // Generic implementations of OutputStream methods that may be useful to sub-classes - - /** - * Writes a byte to the current archive entry. - * - *

This method simply calls {@code write( byte[], 0, 1 )}. - * - *

MUST be overridden if the {@link #write(byte[], int, int)} method - * is not overridden; may be overridden otherwise. - * - * @param b The byte to be written. - * @throws IOException on error - */ - @Override - public void write(final int b) throws IOException { - oneByte[0] = (byte) (b & BYTE_MASK); - write(oneByte, 0, 1); - } - - /** - * Increments the counter of already written bytes. - * Doesn't increment if EOF has been hit ({@code written == -1}). - * - * @param written the number of bytes written - */ - protected void count(final int written) { - count((long) written); - } - - /** - * Increments the counter of already written bytes. - * Doesn't increment if EOF has been hit ({@code written == -1}). - * - * @param written the number of bytes written - * @since 1.1 - */ - protected void count(final long written) { - if (written != -1) { - bytesWritten = bytesWritten + written; - } - } - - /** - * Returns the current number of bytes written to this stream. - * @return the number of written bytes - * @deprecated this method may yield wrong results for large - * archives, use #getBytesWritten instead - */ - @Deprecated - public int getCount() { - return (int) bytesWritten; - } - - /** - * Returns the current number of bytes written to this stream. - * @return the number of written bytes - * @since 1.1 - */ - public long getBytesWritten() { - return bytesWritten; - } - - /** - * Whether this stream is able to write the given entry. - * - *

Some archive formats support variants or details that are - * not supported (yet).

- * - * @param archiveEntry - * the entry to test - * @return This implementation always returns true. - * @since 1.1 - */ - public boolean canWriteEntryData(final ArchiveEntry archiveEntry) { - return true; - } -} diff --git a/src/org/apache/commons/compress/archivers/ArchiveStreamFactory.java b/src/org/apache/commons/compress/archivers/ArchiveStreamFactory.java deleted file mode 100644 index 3cd8ba76355..00000000000 --- a/src/org/apache/commons/compress/archivers/ArchiveStreamFactory.java +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.Locale; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; - -import org.apache.commons.compress.archivers.ar.ArArchiveInputStream; -import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream; -import org.apache.commons.compress.archivers.arj.ArjArchiveInputStream; -import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream; -import org.apache.commons.compress.archivers.cpio.CpioArchiveOutputStream; -import org.apache.commons.compress.archivers.dump.DumpArchiveInputStream; -import org.apache.commons.compress.archivers.jar.JarArchiveInputStream; -import org.apache.commons.compress.archivers.jar.JarArchiveOutputStream; -import org.apache.commons.compress.archivers.sevenz.SevenZFile; -import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; -import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; -import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; -import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.compress.utils.ServiceLoaderIterator; -import org.apache.commons.compress.utils.Sets; - -/** - * Factory to create Archive[In|Out]putStreams from names or the first bytes of - * the InputStream. In order to add other implementations, you should extend - * ArchiveStreamFactory and override the appropriate methods (and call their - * implementation from super of course). - * - * Compressing a ZIP-File: - * - *
- * final OutputStream out = Files.newOutputStream(output.toPath());
- * ArchiveOutputStream os = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP, out);
- *
- * os.putArchiveEntry(new ZipArchiveEntry("testdata/test1.xml"));
- * IOUtils.copy(Files.newInputStream(file1.toPath()), os);
- * os.closeArchiveEntry();
- *
- * os.putArchiveEntry(new ZipArchiveEntry("testdata/test2.xml"));
- * IOUtils.copy(Files.newInputStream(file2.toPath()), os);
- * os.closeArchiveEntry();
- * os.close();
- * 
- * - * Decompressing a ZIP-File: - * - *
- * final InputStream is = Files.newInputStream(input.toPath());
- * ArchiveInputStream in = new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP, is);
- * ZipArchiveEntry entry = (ZipArchiveEntry)in.getNextEntry();
- * OutputStream out = Files.newOutputStream(dir.toPath().resolve(entry.getName()));
- * IOUtils.copy(in, out);
- * out.close();
- * in.close();
- * 
- * @Immutable provided that the deprecated method setEntryEncoding is not used. - * @ThreadSafe even if the deprecated method setEntryEncoding is used - */ -public class ArchiveStreamFactory implements ArchiveStreamProvider { - - private static final int TAR_HEADER_SIZE = 512; - - private static final int DUMP_SIGNATURE_SIZE = 32; - - private static final int SIGNATURE_SIZE = 12; - - private static final ArchiveStreamFactory SINGLETON = new ArchiveStreamFactory(); - - /** - * Constant (value {@value}) used to identify the AR archive format. - * @since 1.1 - */ - public static final String AR = "ar"; - - /** - * Constant (value {@value}) used to identify the ARJ archive format. - * Not supported as an output stream type. - * @since 1.6 - */ - public static final String ARJ = "arj"; - - /** - * Constant (value {@value}) used to identify the CPIO archive format. - * @since 1.1 - */ - public static final String CPIO = "cpio"; - - /** - * Constant (value {@value}) used to identify the Unix DUMP archive format. - * Not supported as an output stream type. - * @since 1.3 - */ - public static final String DUMP = "dump"; - - /** - * Constant (value {@value}) used to identify the JAR archive format. - * @since 1.1 - */ - public static final String JAR = "jar"; - - /** - * Constant used to identify the TAR archive format. - * @since 1.1 - */ - public static final String TAR = "tar"; - - /** - * Constant (value {@value}) used to identify the ZIP archive format. - * @since 1.1 - */ - public static final String ZIP = "zip"; - - /** - * Constant (value {@value}) used to identify the 7z archive format. - * @since 1.8 - */ - public static final String SEVEN_Z = "7z"; - - /** - * Entry encoding, null for the platform default. - */ - private final String encoding; - - /** - * Entry encoding, null for the default. - */ - private volatile String entryEncoding; - - private SortedMap archiveInputStreamProviders; - - private SortedMap archiveOutputStreamProviders; - - private static ArrayList findArchiveStreamProviders() { - return Lists.newArrayList(serviceLoaderIterator()); - } - - static void putAll(Set names, ArchiveStreamProvider provider, - TreeMap map) { - for (String name : names) { - map.put(toKey(name), provider); - } - } - - private static Iterator serviceLoaderIterator() { - return new ServiceLoaderIterator<>(ArchiveStreamProvider.class); - } - - private static String toKey(final String name) { - return name.toUpperCase(Locale.ROOT); - } - - /** - * Constructs a new sorted map from input stream provider names to provider - * objects. - * - *

- * The map returned by this method will have one entry for each provider for - * which support is available in the current Java virtual machine. If two or - * more supported provider have the same name then the resulting map will - * contain just one of them; which one it will contain is not specified. - *

- * - *

- * The invocation of this method, and the subsequent use of the resulting - * map, may cause time-consuming disk or network I/O operations to occur. - * This method is provided for applications that need to enumerate all of - * the available providers, for example to allow user provider selection. - *

- * - *

- * This method may return different results at different times if new - * providers are dynamically made available to the current Java virtual - * machine. - *

- * - * @return An immutable, map from names to provider objects - * @since 1.13 - */ - public static SortedMap findAvailableArchiveInputStreamProviders() { - return AccessController.doPrivileged(new PrivilegedAction>() { - @Override - public SortedMap run() { - TreeMap map = new TreeMap<>(); - putAll(SINGLETON.getInputStreamArchiveNames(), SINGLETON, map); - for (ArchiveStreamProvider provider : findArchiveStreamProviders()) { - putAll(provider.getInputStreamArchiveNames(), provider, map); - } - return map; - } - }); - } - - /** - * Constructs a new sorted map from output stream provider names to provider - * objects. - * - *

- * The map returned by this method will have one entry for each provider for - * which support is available in the current Java virtual machine. If two or - * more supported provider have the same name then the resulting map will - * contain just one of them; which one it will contain is not specified. - *

- * - *

- * The invocation of this method, and the subsequent use of the resulting - * map, may cause time-consuming disk or network I/O operations to occur. - * This method is provided for applications that need to enumerate all of - * the available providers, for example to allow user provider selection. - *

- * - *

- * This method may return different results at different times if new - * providers are dynamically made available to the current Java virtual - * machine. - *

- * - * @return An immutable, map from names to provider objects - * @since 1.13 - */ - public static SortedMap findAvailableArchiveOutputStreamProviders() { - return AccessController.doPrivileged(new PrivilegedAction>() { - @Override - public SortedMap run() { - TreeMap map = new TreeMap<>(); - putAll(SINGLETON.getOutputStreamArchiveNames(), SINGLETON, map); - for (ArchiveStreamProvider provider : findArchiveStreamProviders()) { - putAll(provider.getOutputStreamArchiveNames(), provider, map); - } - return map; - } - }); - } - - /** - * Create an instance using the platform default encoding. - */ - public ArchiveStreamFactory() { - this(null); - } - - /** - * Create an instance using the specified encoding. - * - * @param encoding the encoding to be used. - * - * @since 1.10 - */ - public ArchiveStreamFactory(final String encoding) { - super(); - this.encoding = encoding; - // Also set the original field so can continue to use it. - this.entryEncoding = encoding; - } - - /** - * Returns the encoding to use for arj, jar, zip, dump, cpio and tar - * files, or null for the archiver default. - * - * @return entry encoding, or null for the archiver default - * @since 1.5 - */ - public String getEntryEncoding() { - return entryEncoding; - } - - /** - * Sets the encoding to use for arj, jar, zip, dump, cpio and tar files. Use null for the archiver default. - * - * @param entryEncoding the entry encoding, null uses the archiver default. - * @since 1.5 - * @deprecated 1.10 use {@link #ArchiveStreamFactory(String)} to specify the encoding - * @throws IllegalStateException if the constructor {@link #ArchiveStreamFactory(String)} - * was used to specify the factory encoding. - */ - @Deprecated - public void setEntryEncoding(final String entryEncoding) { - // Note: this does not detect new ArchiveStreamFactory(null) but that does not set the encoding anyway - if (encoding != null) { - throw new IllegalStateException("Cannot overide encoding set by the constructor"); - } - this.entryEncoding = entryEncoding; - } - - /** - * Creates an archive input stream from an archiver name and an input stream. - * - * @param archiverName the archive name, - * i.e. {@value #AR}, {@value #ARJ}, {@value #ZIP}, {@value #TAR}, {@value #JAR}, {@value #CPIO}, {@value #DUMP} or {@value #SEVEN_Z} - * @param in the input stream - * @return the archive input stream - * @throws ArchiveException if the archiver name is not known - * @throws StreamingNotSupportedException if the format cannot be - * read from a stream - * @throws IllegalArgumentException if the archiver name or stream is null - */ - public ArchiveInputStream createArchiveInputStream(final String archiverName, final InputStream in) - throws ArchiveException { - return createArchiveInputStream(archiverName, in, entryEncoding); - } - - @Override - public ArchiveInputStream createArchiveInputStream(final String archiverName, final InputStream in, - final String actualEncoding) throws ArchiveException { - - if (archiverName == null) { - throw new IllegalArgumentException("Archivername must not be null."); - } - - if (in == null) { - throw new IllegalArgumentException("InputStream must not be null."); - } - - if (AR.equalsIgnoreCase(archiverName)) { - return new ArArchiveInputStream(in); - } - if (ARJ.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new ArjArchiveInputStream(in, actualEncoding); - } - return new ArjArchiveInputStream(in); - } - if (ZIP.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new ZipArchiveInputStream(in, actualEncoding); - } - return new ZipArchiveInputStream(in); - } - if (TAR.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new TarArchiveInputStream(in, actualEncoding); - } - return new TarArchiveInputStream(in); - } - if (JAR.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new JarArchiveInputStream(in, actualEncoding); - } - return new JarArchiveInputStream(in); - } - if (CPIO.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new CpioArchiveInputStream(in, actualEncoding); - } - return new CpioArchiveInputStream(in); - } - if (DUMP.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new DumpArchiveInputStream(in, actualEncoding); - } - return new DumpArchiveInputStream(in); - } - if (SEVEN_Z.equalsIgnoreCase(archiverName)) { - throw new StreamingNotSupportedException(SEVEN_Z); - } - - final ArchiveStreamProvider archiveStreamProvider = getArchiveInputStreamProviders().get(toKey(archiverName)); - if (archiveStreamProvider != null) { - return archiveStreamProvider.createArchiveInputStream(archiverName, in, actualEncoding); - } - - throw new ArchiveException("Archiver: " + archiverName + " not found."); - } - - /** - * Creates an archive output stream from an archiver name and an output stream. - * - * @param archiverName the archive name, - * i.e. {@value #AR}, {@value #ZIP}, {@value #TAR}, {@value #JAR} or {@value #CPIO} - * @param out the output stream - * @return the archive output stream - * @throws ArchiveException if the archiver name is not known - * @throws StreamingNotSupportedException if the format cannot be - * written to a stream - * @throws IllegalArgumentException if the archiver name or stream is null - */ - public ArchiveOutputStream createArchiveOutputStream(final String archiverName, final OutputStream out) - throws ArchiveException { - return createArchiveOutputStream(archiverName, out, entryEncoding); - } - - @Override - public ArchiveOutputStream createArchiveOutputStream( - final String archiverName, final OutputStream out, final String actualEncoding) - throws ArchiveException { - if (archiverName == null) { - throw new IllegalArgumentException("Archivername must not be null."); - } - if (out == null) { - throw new IllegalArgumentException("OutputStream must not be null."); - } - - if (AR.equalsIgnoreCase(archiverName)) { - return new ArArchiveOutputStream(out); - } - if (ZIP.equalsIgnoreCase(archiverName)) { - final ZipArchiveOutputStream zip = new ZipArchiveOutputStream(out); - if (actualEncoding != null) { - zip.setEncoding(actualEncoding); - } - return zip; - } - if (TAR.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new TarArchiveOutputStream(out, actualEncoding); - } - return new TarArchiveOutputStream(out); - } - if (JAR.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new JarArchiveOutputStream(out, actualEncoding); - } - return new JarArchiveOutputStream(out); - } - if (CPIO.equalsIgnoreCase(archiverName)) { - if (actualEncoding != null) { - return new CpioArchiveOutputStream(out, actualEncoding); - } - return new CpioArchiveOutputStream(out); - } - if (SEVEN_Z.equalsIgnoreCase(archiverName)) { - throw new StreamingNotSupportedException(SEVEN_Z); - } - - final ArchiveStreamProvider archiveStreamProvider = getArchiveOutputStreamProviders().get(toKey(archiverName)); - if (archiveStreamProvider != null) { - return archiveStreamProvider.createArchiveOutputStream(archiverName, out, actualEncoding); - } - - throw new ArchiveException("Archiver: " + archiverName + " not found."); - } - - /** - * Create an archive input stream from an input stream, autodetecting - * the archive type from the first few bytes of the stream. The InputStream - * must support marks, like BufferedInputStream. - * - * @param in the input stream - * @return the archive input stream - * @throws ArchiveException if the archiver name is not known - * @throws StreamingNotSupportedException if the format cannot be - * read from a stream - * @throws IllegalArgumentException if the stream is null or does not support mark - */ - public ArchiveInputStream createArchiveInputStream(final InputStream in) - throws ArchiveException { - return createArchiveInputStream(detect(in), in); - } - - /** - * Try to determine the type of Archiver - * @param in input stream - * @return type of archiver if found - * @throws ArchiveException if an archiver cannot be detected in the stream - * @since 1.14 - */ - public static String detect(InputStream in) throws ArchiveException { - if (in == null) { - throw new IllegalArgumentException("Stream must not be null."); - } - - if (!in.markSupported()) { - throw new IllegalArgumentException("Mark is not supported."); - } - - final byte[] signature = new byte[SIGNATURE_SIZE]; - in.mark(signature.length); - int signatureLength = -1; - try { - signatureLength = IOUtils.readFully(in, signature); - in.reset(); - } catch (IOException e) { - throw new ArchiveException("IOException while reading signature.", e); - } - - if (ZipArchiveInputStream.matches(signature, signatureLength)) { - return ZIP; - } else if (JarArchiveInputStream.matches(signature, signatureLength)) { - return JAR; - } else if (ArArchiveInputStream.matches(signature, signatureLength)) { - return AR; - } else if (CpioArchiveInputStream.matches(signature, signatureLength)) { - return CPIO; - } else if (ArjArchiveInputStream.matches(signature, signatureLength)) { - return ARJ; - } else if (SevenZFile.matches(signature, signatureLength)) { - return SEVEN_Z; - } - - // Dump needs a bigger buffer to check the signature; - final byte[] dumpsig = new byte[DUMP_SIGNATURE_SIZE]; - in.mark(dumpsig.length); - try { - signatureLength = IOUtils.readFully(in, dumpsig); - in.reset(); - } catch (IOException e) { - throw new ArchiveException("IOException while reading dump signature", e); - } - if (DumpArchiveInputStream.matches(dumpsig, signatureLength)) { - return DUMP; - } - - // Tar needs an even bigger buffer to check the signature; read the first block - final byte[] tarHeader = new byte[TAR_HEADER_SIZE]; - in.mark(tarHeader.length); - try { - signatureLength = IOUtils.readFully(in, tarHeader); - in.reset(); - } catch (IOException e) { - throw new ArchiveException("IOException while reading tar signature", e); - } - if (TarArchiveInputStream.matches(tarHeader, signatureLength)) { - return TAR; - } - - // COMPRESS-117 - improve auto-recognition - if (signatureLength >= TAR_HEADER_SIZE) { - TarArchiveInputStream tais = null; - try { - tais = new TarArchiveInputStream(new ByteArrayInputStream(tarHeader)); - // COMPRESS-191 - verify the header checksum - if (tais.getNextTarEntry().isCheckSumOK()) { - return TAR; - } - } catch (final Exception e) { // NOPMD // NOSONAR - // can generate IllegalArgumentException as well - // as IOException - // autodetection, simply not a TAR - // ignored - } finally { - IOUtils.closeQuietly(tais); - } - } - throw new ArchiveException("No Archiver found for the stream signature"); - } - - public SortedMap getArchiveInputStreamProviders() { - if (archiveInputStreamProviders == null) { - archiveInputStreamProviders = Collections - .unmodifiableSortedMap(findAvailableArchiveInputStreamProviders()); - } - return archiveInputStreamProviders; - } - - public SortedMap getArchiveOutputStreamProviders() { - if (archiveOutputStreamProviders == null) { - archiveOutputStreamProviders = Collections - .unmodifiableSortedMap(findAvailableArchiveOutputStreamProviders()); - } - return archiveOutputStreamProviders; - } - - @Override - public Set getInputStreamArchiveNames() { - return Sets.newHashSet(AR, ARJ, ZIP, TAR, JAR, CPIO, DUMP, SEVEN_Z); - } - - @Override - public Set getOutputStreamArchiveNames() { - return Sets.newHashSet(AR, ZIP, TAR, JAR, CPIO, SEVEN_Z); - } - -} diff --git a/src/org/apache/commons/compress/archivers/ArchiveStreamProvider.java b/src/org/apache/commons/compress/archivers/ArchiveStreamProvider.java deleted file mode 100644 index eb1862c9dea..00000000000 --- a/src/org/apache/commons/compress/archivers/ArchiveStreamProvider.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Set; - -/** - * Creates Archive {@link ArchiveInputStream}s and {@link ArchiveOutputStream}s. - * - * @since 1.13 - */ -public interface ArchiveStreamProvider { - - /** - * Creates an archive input stream from an archiver name and an input - * stream. - * - * @param name - * the archive name, i.e. - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#AR}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#ARJ}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#ZIP}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#TAR}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#JAR}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#CPIO}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#DUMP} - * or - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#SEVEN_Z} - * @param in - * the input stream - * @param encoding - * encoding name or null for the default - * @return the archive input stream - * @throws ArchiveException - * if the archiver name is not known - * @throws StreamingNotSupportedException - * if the format cannot be read from a stream - * @throws IllegalArgumentException - * if the archiver name or stream is null - */ - ArchiveInputStream createArchiveInputStream(final String name, final InputStream in, final String encoding) - throws ArchiveException; - - /** - * Creates an archive output stream from an archiver name and an output - * stream. - * - * @param name - * the archive name, i.e. - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#AR}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#ZIP}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#TAR}, - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#JAR} - * or - * {@value org.apache.commons.compress.archivers.ArchiveStreamFactory#CPIO} - * @param out - * the output stream - * @param encoding - * encoding name or null for the default - * @return the archive output stream - * @throws ArchiveException - * if the archiver name is not known - * @throws StreamingNotSupportedException - * if the format cannot be written to a stream - * @throws IllegalArgumentException - * if the archiver name or stream is null - */ - ArchiveOutputStream createArchiveOutputStream(final String name, final OutputStream out, final String encoding) - throws ArchiveException; - - /** - * Gets all the input stream archive names for this provider - * - * @return all the input archive names for this provider - */ - Set getInputStreamArchiveNames(); - - /** - * Gets all the output stream archive names for this provider - * - * @return all the output archive names for this provider - */ - Set getOutputStreamArchiveNames(); - -} diff --git a/src/org/apache/commons/compress/archivers/Archiver.java b/src/org/apache/commons/compress/archivers/Archiver.java deleted file mode 100644 index 4e82640a84a..00000000000 --- a/src/org/apache/commons/compress/archivers/Archiver.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.StandardOpenOption; - -import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile; -import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Provides a high level API for creating archives. - * @since 1.17 - */ -public class Archiver { - - private static final FileFilter ACCEPT_ALL = new FileFilter() { - @Override - public boolean accept(File f) { - return true; - } - }; - - private interface ArchiveEntryCreator { - ArchiveEntry create(File f, String entryName) throws IOException; - } - - private interface ArchiveEntryConsumer { - void accept(File source, ArchiveEntry entry) throws IOException; - } - - private interface Finisher { - void finish() throws IOException; - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the file to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, File target, File directory) throws IOException, ArchiveException { - create(format, target, directory, ACCEPT_ALL); - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory} that are accepted by {@code filter}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the file to write the new archive to. - * @param directory the directory that contains the files to archive. - * @param filter selects the files and directories to include inside the archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, File target, File directory, FileFilter filter) - throws IOException, ArchiveException { - if (prefersSeekableByteChannel(format)) { - try (SeekableByteChannel c = FileChannel.open(target.toPath(), StandardOpenOption.WRITE, - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - create(format, c, directory, filter); - } - return; - } - try (OutputStream o = new FileOutputStream(target)) { - create(format, o, directory, filter); - } - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the stream to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, OutputStream target, File directory) throws IOException, ArchiveException { - create(format, target, directory, ACCEPT_ALL); - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory} that are accepted by {@code filter}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the stream to write the new archive to. - * @param directory the directory that contains the files to archive. - * @param filter selects the files and directories to include inside the archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, OutputStream target, File directory, FileFilter filter) - throws IOException, ArchiveException { - create(new ArchiveStreamFactory().createArchiveOutputStream(format, target), directory, filter); - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the channel to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, SeekableByteChannel target, File directory) - throws IOException, ArchiveException { - create(format, target, directory, ACCEPT_ALL); - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory} that are accepted by {@code filter}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the channel to write the new archive to. - * @param directory the directory that contains the files to archive. - * @param filter selects the files and directories to include inside the archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, SeekableByteChannel target, File directory, FileFilter filter) - throws IOException, ArchiveException { - if (!prefersSeekableByteChannel(format)) { - create(format, Channels.newOutputStream(target), directory, filter); - } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) { - create(new ZipArchiveOutputStream(target), directory, filter); - } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) { - create(new SevenZOutputFile(target), directory, filter); - } else { - throw new ArchiveException("don't know how to handle format " + format); - } - } - - /** - * Creates an archive {@code target} by recursively including all - * files and directories in {@code directory}. - * - * @param target the stream to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(ArchiveOutputStream target, File directory) throws IOException, ArchiveException { - create(target, directory, ACCEPT_ALL); - } - - /** - * Creates an archive {@code target} by recursively including all - * files and directories in {@code directory} that are accepted by - * {@code filter}. - * - * @param target the stream to write the new archive to. - * @param directory the directory that contains the files to archive. - * @param filter selects the files and directories to include inside the archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(final ArchiveOutputStream target, File directory, FileFilter filter) - throws IOException, ArchiveException { - create(directory, filter, new ArchiveEntryCreator() { - public ArchiveEntry create(File f, String entryName) throws IOException { - return target.createArchiveEntry(f, entryName); - } - }, new ArchiveEntryConsumer() { - public void accept(File source, ArchiveEntry e) throws IOException { - target.putArchiveEntry(e); - if (!e.isDirectory()) { - try (InputStream in = new BufferedInputStream(new FileInputStream(source))) { - IOUtils.copy(in, target); - } - } - target.closeArchiveEntry(); - } - }, new Finisher() { - public void finish() throws IOException { - target.finish(); - } - }); - } - - /** - * Creates an archive {@code target} by recursively including all - * files and directories in {@code directory}. - * - * @param target the file to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - */ - public void create(final SevenZOutputFile target, File directory) throws IOException { - create(target, directory, ACCEPT_ALL); - } - - /** - * Creates an archive {@code target} by recursively including all - * files and directories in {@code directory} that are accepted by - * {@code filter}. - * - * @param target the file to write the new archive to. - * @param directory the directory that contains the files to archive. - * @param filter selects the files and directories to include inside the archive. - * @throws IOException if an I/O error occurs - */ - public void create(final SevenZOutputFile target, File directory, FileFilter filter) throws IOException { - create(directory, filter, new ArchiveEntryCreator() { - public ArchiveEntry create(File f, String entryName) throws IOException { - return target.createArchiveEntry(f, entryName); - } - }, new ArchiveEntryConsumer() { - public void accept(File source, ArchiveEntry e) throws IOException { - target.putArchiveEntry(e); - if (!e.isDirectory()) { - final byte[] buffer = new byte[8024]; - int n = 0; - long count = 0; - try (InputStream in = new BufferedInputStream(new FileInputStream(source))) { - while (-1 != (n = in.read(buffer))) { - target.write(buffer, 0, n); - count += n; - } - } - } - target.closeArchiveEntry(); - } - }, new Finisher() { - public void finish() throws IOException { - target.finish(); - } - }); - } - - private boolean prefersSeekableByteChannel(String format) { - return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format); - } - - private void create(File directory, FileFilter filter, ArchiveEntryCreator creator, ArchiveEntryConsumer consumer, - Finisher finisher) throws IOException { - create("", directory, filter, creator, consumer); - finisher.finish(); - } - - private void create(String prefix, File directory, FileFilter filter, ArchiveEntryCreator creator, ArchiveEntryConsumer consumer) - throws IOException { - File[] children = directory.listFiles(filter); - if (children == null) { - return; - } - for (File f : children) { - String entryName = prefix + f.getName() + (f.isDirectory() ? "/" : ""); - consumer.accept(f, creator.create(f, entryName)); - if (f.isDirectory()) { - create(entryName, f, filter, creator, consumer); - } - } - } -} diff --git a/src/org/apache/commons/compress/archivers/EntryStreamOffsets.java b/src/org/apache/commons/compress/archivers/EntryStreamOffsets.java deleted file mode 100644 index a73d079e293..00000000000 --- a/src/org/apache/commons/compress/archivers/EntryStreamOffsets.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - - -/** - * Provides information about ArchiveEntry stream offsets. - */ -public interface EntryStreamOffsets { - - /** Special value indicating that the offset is unknown. */ - long OFFSET_UNKNOWN = -1; - - /** - * Gets the offset of data stream within the archive file, - * - * @return - * the offset of entry data stream, {@code OFFSET_UNKNOWN} if not known. - */ - long getDataOffset(); - - /** - * Indicates whether the stream is contiguous, i.e. not split among - * several archive parts, interspersed with control blocks, etc. - * - * @return - * true if stream is contiguous, false otherwise. - */ - boolean isStreamContiguous(); -} diff --git a/src/org/apache/commons/compress/archivers/Expander.java b/src/org/apache/commons/compress/archivers/Expander.java deleted file mode 100644 index 82b958ebac0..00000000000 --- a/src/org/apache/commons/compress/archivers/Expander.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.StandardOpenOption; -import java.util.Enumeration; - -import org.apache.commons.compress.archivers.sevenz.SevenZFile; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipFile; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Provides a high level API for expanding archives. - * @since 1.17 - */ -public class Expander { - /** - * Used to filter the entries to be extracted. - */ - public interface ArchiveEntryFilter { - /** - * @return true if the entry shall be expanded - * @param entry the entry to test - */ - boolean accept(ArchiveEntry entry); - } - - private static final ArchiveEntryFilter ACCEPT_ALL = new ArchiveEntryFilter() { - @Override - public boolean accept(ArchiveEntry e) { - return true; - } - }; - - private interface ArchiveEntrySupplier { - ArchiveEntry getNextReadableEntry() throws IOException; - } - - private interface EntryWriter { - void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException; - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - *

Tries to auto-detect the archive's format.

- * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(File archive, File targetDirectory) throws IOException, ArchiveException { - expand(archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, File archive, File targetDirectory) throws IOException, ArchiveException { - expand(format, archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - *

Tries to auto-detect the archive's format.

- * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(File archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - String format = null; - try (InputStream i = new BufferedInputStream(new FileInputStream(archive))) { - format = new ArchiveStreamFactory().detect(i); - } - expand(format, archive, targetDirectory, filter); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, File archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - if (prefersSeekableByteChannel(format)) { - try (SeekableByteChannel c = FileChannel.open(archive.toPath(), StandardOpenOption.READ)) { - expand(format, c, targetDirectory, filter); - } - return; - } - try (InputStream i = new BufferedInputStream(new FileInputStream(archive))) { - expand(format, i, targetDirectory, filter); - } - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - *

Tries to auto-detect the archive's format.

- * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(InputStream archive, File targetDirectory) throws IOException, ArchiveException { - expand(archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, InputStream archive, File targetDirectory) - throws IOException, ArchiveException { - expand(format, archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - *

Tries to auto-detect the archive's format.

- * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(InputStream archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - expand(new ArchiveStreamFactory().createArchiveInputStream(archive), targetDirectory, filter); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, InputStream archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - expand(new ArchiveStreamFactory().createArchiveInputStream(format, archive), targetDirectory, filter); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, SeekableByteChannel archive, File targetDirectory) - throws IOException, ArchiveException { - expand(format, archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, SeekableByteChannel archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - if (!prefersSeekableByteChannel(format)) { - expand(format, Channels.newInputStream(archive), targetDirectory, filter); - } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) { - expand(new ZipFile(archive), targetDirectory, filter); - } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) { - expand(new SevenZFile(archive), targetDirectory, filter); - } else { - throw new ArchiveException("don't know how to handle format " + format); - } - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(ArchiveInputStream archive, File targetDirectory) - throws IOException, ArchiveException { - expand(archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(final ArchiveInputStream archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - expand(new ArchiveEntrySupplier() { - @Override - public ArchiveEntry getNextReadableEntry() throws IOException { - ArchiveEntry next = archive.getNextEntry(); - while (next != null && !archive.canReadEntryData(next)) { - next = archive.getNextEntry(); - } - return next; - } - }, new EntryWriter() { - @Override - public void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException { - IOUtils.copy(archive, out); - } - }, targetDirectory, filter); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(ZipFile archive, File targetDirectory) - throws IOException, ArchiveException { - expand(archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(final ZipFile archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - final Enumeration entries = archive.getEntries(); - expand(new ArchiveEntrySupplier() { - @Override - public ArchiveEntry getNextReadableEntry() throws IOException { - ZipArchiveEntry next = entries.hasMoreElements() ? entries.nextElement() : null; - while (next != null && !archive.canReadEntryData(next)) { - next = entries.hasMoreElements() ? entries.nextElement() : null; - } - return next; - } - }, new EntryWriter() { - @Override - public void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException { - try (InputStream in = archive.getInputStream((ZipArchiveEntry) entry)) { - IOUtils.copy(in, out); - } - } - }, targetDirectory, filter); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(SevenZFile archive, File targetDirectory) - throws IOException, ArchiveException { - expand(archive, targetDirectory, ACCEPT_ALL); - } - - /** - * Expands {@code archive} into {@code targetDirectory}, using - * only the entries accepted by the {@code filter}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param filter selects the entries to expand - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(final SevenZFile archive, File targetDirectory, ArchiveEntryFilter filter) - throws IOException, ArchiveException { - expand(new ArchiveEntrySupplier() { - @Override - public ArchiveEntry getNextReadableEntry() throws IOException { - return archive.getNextEntry(); - } - }, new EntryWriter() { - @Override - public void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException { - final byte[] buffer = new byte[8024]; - int n = 0; - long count = 0; - while (-1 != (n = archive.read(buffer))) { - out.write(buffer, 0, n); - count += n; - } - } - }, targetDirectory, filter); - } - - private boolean prefersSeekableByteChannel(String format) { - return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format); - } - - private void expand(ArchiveEntrySupplier supplier, EntryWriter writer, File targetDirectory, ArchiveEntryFilter filter) - throws IOException { - String targetDirPath = targetDirectory.getCanonicalPath(); - ArchiveEntry nextEntry = supplier.getNextReadableEntry(); - while (nextEntry != null) { - if (!filter.accept(nextEntry)) { - continue; - } - File f = new File(targetDirectory, nextEntry.getName()); - if (!f.getCanonicalPath().startsWith(targetDirPath)) { - throw new IOException("expanding " + nextEntry.getName() - + " would craete file outside of " + targetDirectory); - } - if (nextEntry.isDirectory()) { - f.mkdirs(); - } else { - f.getParentFile().mkdirs(); - try (OutputStream o = new FileOutputStream(f)) { - writer.writeEntryDataTo(nextEntry, o); - } - } - nextEntry = supplier.getNextReadableEntry(); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/Lister.java b/src/org/apache/commons/compress/archivers/Lister.java deleted file mode 100644 index 07a8e9c0756..00000000000 --- a/src/org/apache/commons/compress/archivers/Lister.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import org.apache.commons.compress.archivers.sevenz.SevenZFile; - -/** - * Simple command line application that lists the contents of an archive. - * - *

The name of the archive must be given as a command line argument.

- *

The optional second argument defines the archive type, in case the format is not recognized.

- * - * @since 1.1 - */ -public final class Lister { - private static final ArchiveStreamFactory factory = new ArchiveStreamFactory(); - - public static void main(final String[] args) throws Exception { - if (args.length == 0) { - usage(); - return; - } - System.out.println("Analysing " + args[0]); - final File f = new File(args[0]); - if (!f.isFile()) { - System.err.println(f + " doesn't exist or is a directory"); - } - String format = args.length > 1 ? args[1] : detectFormat(f); - if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) { - list7z(f); - } else { - listStream(f, args); - } - } - - private static void listStream(File f, String[] args) throws ArchiveException, IOException { - try (final InputStream fis = new BufferedInputStream(Files.newInputStream(f.toPath())); - final ArchiveInputStream ais = createArchiveInputStream(args, fis)) { - System.out.println("Created " + ais.toString()); - ArchiveEntry ae; - while ((ae = ais.getNextEntry()) != null) { - System.out.println(ae.getName()); - } - } - } - - private static ArchiveInputStream createArchiveInputStream(final String[] args, final InputStream fis) - throws ArchiveException { - if (args.length > 1) { - return factory.createArchiveInputStream(args[1], fis); - } - return factory.createArchiveInputStream(fis); - } - - private static String detectFormat(File f) throws ArchiveException, IOException { - try (final InputStream fis = new BufferedInputStream(Files.newInputStream(f.toPath()))) { - return factory.detect(fis); - } - } - - private static void list7z(File f) throws ArchiveException, IOException { - try (SevenZFile z = new SevenZFile(f)) { - System.out.println("Created " + z.toString()); - ArchiveEntry ae; - while ((ae = z.getNextEntry()) != null) { - System.out.println(ae.getName()); - } - } - } - - private static void usage() { - System.out.println("Parameters: archive-name [archive-type]"); - } - -} diff --git a/src/org/apache/commons/compress/archivers/StreamingNotSupportedException.java b/src/org/apache/commons/compress/archivers/StreamingNotSupportedException.java deleted file mode 100644 index 9f12a7aff9c..00000000000 --- a/src/org/apache/commons/compress/archivers/StreamingNotSupportedException.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers; - -/** - * Exception thrown by ArchiveStreamFactory if a format is requested/detected that doesn't support streaming. - * - * @since 1.8 - */ -public class StreamingNotSupportedException extends ArchiveException { - - private static final long serialVersionUID = 1L; - - private final String format; - - /** - * Creates a new StreamingNotSupportedException. - * - * @param format the format that has been requested/detected. - */ - public StreamingNotSupportedException(final String format) { - super("The " + format + " doesn't support streaming."); - this.format = format; - } - - /** - * Returns the format that has been requested/detected. - * - * @return the format that has been requested/detected. - */ - public String getFormat() { - return format; - } - -} diff --git a/src/org/apache/commons/compress/archivers/ar/ArArchiveEntry.java b/src/org/apache/commons/compress/archivers/ar/ArArchiveEntry.java deleted file mode 100644 index df9595ad249..00000000000 --- a/src/org/apache/commons/compress/archivers/ar/ArArchiveEntry.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.ar; - -import java.io.File; -import java.util.Date; - -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * Represents an archive entry in the "ar" format. - * - * Each AR archive starts with "!<arch>" followed by a LF. After these 8 bytes - * the archive entries are listed. The format of an entry header is as it follows: - * - *
- * START BYTE   END BYTE    NAME                    FORMAT      LENGTH
- * 0            15          File name               ASCII       16
- * 16           27          Modification timestamp  Decimal     12
- * 28           33          Owner ID                Decimal     6
- * 34           39          Group ID                Decimal     6
- * 40           47          File mode               Octal       8
- * 48           57          File size (bytes)       Decimal     10
- * 58           59          File magic              \140\012    2
- * 
- * - * This specifies that an ar archive entry header contains 60 bytes. - * - * Due to the limitation of the file name length to 16 bytes GNU and - * BSD has their own variants of this format. Currently Commons - * Compress can read but not write the GNU variant. It fully supports - * the BSD variant. - * - * @see ar man page - * - * @Immutable - */ -public class ArArchiveEntry implements ArchiveEntry { - - /** The header for each entry */ - public static final String HEADER = "!\n"; - - /** The trailer for each entry */ - public static final String TRAILER = "`\012"; - - /** - * SVR4/GNU adds a trailing / to names; BSD does not. - * They also vary in how names longer than 16 characters are represented. - * (Not yet fully supported by this implementation) - */ - private final String name; - private final int userId; - private final int groupId; - private final int mode; - private static final int DEFAULT_MODE = 33188; // = (octal) 0100644 - private final long lastModified; - private final long length; - - /** - * Create a new instance using a couple of default values. - * - *

Sets userId and groupId to 0, the octal file mode to 644 and - * the last modified time to the current time.

- * - * @param name name of the entry - * @param length length of the entry in bytes - */ - public ArArchiveEntry(final String name, final long length) { - this(name, length, 0, 0, DEFAULT_MODE, - System.currentTimeMillis() / 1000); - } - - /** - * Create a new instance. - * - * @param name name of the entry - * @param length length of the entry in bytes - * @param userId numeric user id - * @param groupId numeric group id - * @param mode file mode - * @param lastModified last modified time in seconds since the epoch - */ - public ArArchiveEntry(final String name, final long length, final int userId, final int groupId, - final int mode, final long lastModified) { - this.name = name; - this.length = length; - this.userId = userId; - this.groupId = groupId; - this.mode = mode; - this.lastModified = lastModified; - } - - /** - * Create a new instance using the attributes of the given file - * @param inputFile the file to create an entry from - * @param entryName the name of the entry - */ - public ArArchiveEntry(final File inputFile, final String entryName) { - // TODO sort out mode - this(entryName, inputFile.isFile() ? inputFile.length() : 0, - 0, 0, DEFAULT_MODE, inputFile.lastModified() / 1000); - } - - @Override - public long getSize() { - return this.getLength(); - } - - @Override - public String getName() { - return name; - } - - public int getUserId() { - return userId; - } - - public int getGroupId() { - return groupId; - } - - public int getMode() { - return mode; - } - - /** - * Last modified time in seconds since the epoch. - * @return the last modified date - */ - public long getLastModified() { - return lastModified; - } - - @Override - public Date getLastModifiedDate() { - return new Date(1000 * getLastModified()); - } - - public long getLength() { - return length; - } - - @Override - public boolean isDirectory() { - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (name == null ? 0 : name.hashCode()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final ArArchiveEntry other = (ArArchiveEntry) obj; - if (name == null) { - return other.name == null; - } else { - return name.equals(other.name); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java b/src/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java deleted file mode 100644 index ddd122ede19..00000000000 --- a/src/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.ar; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.utils.ArchiveUtils; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Implements the "ar" archive format as an input stream. - * - * @NotThreadSafe - * - */ -public class ArArchiveInputStream extends ArchiveInputStream { - - private final InputStream input; - private long offset = 0; - private boolean closed; - - /* - * If getNextEnxtry has been called, the entry metadata is stored in - * currentEntry. - */ - private ArArchiveEntry currentEntry = null; - - // Storage area for extra long names (GNU ar) - private byte[] namebuffer = null; - - /* - * The offset where the current entry started. -1 if no entry has been - * called - */ - private long entryOffset = -1; - - // cached buffers - must only be used locally in the class (COMPRESS-172 - reduce garbage collection) - private final byte[] nameBuf = new byte[16]; - private final byte[] lastModifiedBuf = new byte[12]; - private final byte[] idBuf = new byte[6]; - private final byte[] fileModeBuf = new byte[8]; - private final byte[] lengthBuf = new byte[10]; - - /** - * Constructs an Ar input stream with the referenced stream - * - * @param pInput - * the ar input stream - */ - public ArArchiveInputStream(final InputStream pInput) { - input = pInput; - closed = false; - } - - /** - * Returns the next AR entry in this stream. - * - * @return the next AR entry. - * @throws IOException - * if the entry could not be read - */ - public ArArchiveEntry getNextArEntry() throws IOException { - if (currentEntry != null) { - final long entryEnd = entryOffset + currentEntry.getLength(); - IOUtils.skip(this, entryEnd - offset); - currentEntry = null; - } - - if (offset == 0) { - final byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.HEADER); - final byte[] realized = new byte[expected.length]; - final int read = IOUtils.readFully(this, realized); - if (read != expected.length) { - throw new IOException("failed to read header. Occured at byte: " + getBytesRead()); - } - for (int i = 0; i < expected.length; i++) { - if (expected[i] != realized[i]) { - throw new IOException("invalid header " + ArchiveUtils.toAsciiString(realized)); - } - } - } - - if (offset % 2 != 0 && read() < 0) { - // hit eof - return null; - } - - if (input.available() == 0) { - return null; - } - - IOUtils.readFully(this, nameBuf); - IOUtils.readFully(this, lastModifiedBuf); - IOUtils.readFully(this, idBuf); - final int userId = asInt(idBuf, true); - IOUtils.readFully(this, idBuf); - IOUtils.readFully(this, fileModeBuf); - IOUtils.readFully(this, lengthBuf); - - { - final byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.TRAILER); - final byte[] realized = new byte[expected.length]; - final int read = IOUtils.readFully(this, realized); - if (read != expected.length) { - throw new IOException("failed to read entry trailer. Occured at byte: " + getBytesRead()); - } - for (int i = 0; i < expected.length; i++) { - if (expected[i] != realized[i]) { - throw new IOException("invalid entry trailer. not read the content? Occured at byte: " + getBytesRead()); - } - } - } - - entryOffset = offset; - -// GNU ar uses a '/' to mark the end of the filename; this allows for the use of spaces without the use of an extended filename. - - // entry name is stored as ASCII string - String temp = ArchiveUtils.toAsciiString(nameBuf).trim(); - if (isGNUStringTable(temp)) { // GNU extended filenames entry - currentEntry = readGNUStringTable(lengthBuf); - return getNextArEntry(); - } - - long len = asLong(lengthBuf); - if (temp.endsWith("/")) { // GNU terminator - temp = temp.substring(0, temp.length() - 1); - } else if (isGNULongName(temp)) { - final int off = Integer.parseInt(temp.substring(1));// get the offset - temp = getExtendedName(off); // convert to the long name - } else if (isBSDLongName(temp)) { - temp = getBSDLongName(temp); - // entry length contained the length of the file name in - // addition to the real length of the entry. - // assume file name was ASCII, there is no "standard" otherwise - final int nameLen = temp.length(); - len -= nameLen; - entryOffset += nameLen; - } - - currentEntry = new ArArchiveEntry(temp, len, userId, - asInt(idBuf, true), - asInt(fileModeBuf, 8), - asLong(lastModifiedBuf)); - return currentEntry; - } - - /** - * Get an extended name from the GNU extended name buffer. - * - * @param offset pointer to entry within the buffer - * @return the extended file name; without trailing "/" if present. - * @throws IOException if name not found or buffer not set up - */ - private String getExtendedName(final int offset) throws IOException { - if (namebuffer == null) { - throw new IOException("Cannot process GNU long filename as no // record was found"); - } - for (int i = offset; i < namebuffer.length; i++) { - if (namebuffer[i] == '\012' || namebuffer[i] == 0) { - if (namebuffer[i - 1] == '/') { - i--; // drop trailing / - } - return ArchiveUtils.toAsciiString(namebuffer, offset, i - offset); - } - } - throw new IOException("Failed to read entry: " + offset); - } - - private long asLong(final byte[] byteArray) { - return Long.parseLong(ArchiveUtils.toAsciiString(byteArray).trim()); - } - - private int asInt(final byte[] byteArray) { - return asInt(byteArray, 10, false); - } - - private int asInt(final byte[] byteArray, final boolean treatBlankAsZero) { - return asInt(byteArray, 10, treatBlankAsZero); - } - - private int asInt(final byte[] byteArray, final int base) { - return asInt(byteArray, base, false); - } - - private int asInt(final byte[] byteArray, final int base, final boolean treatBlankAsZero) { - final String string = ArchiveUtils.toAsciiString(byteArray).trim(); - if (string.length() == 0 && treatBlankAsZero) { - return 0; - } - return Integer.parseInt(string, base); - } - - /* - * (non-Javadoc) - * - * @see - * org.apache.commons.compress.archivers.ArchiveInputStream#getNextEntry() - */ - @Override - public ArchiveEntry getNextEntry() throws IOException { - return getNextArEntry(); - } - - /* - * (non-Javadoc) - * - * @see java.io.InputStream#close() - */ - @Override - public void close() throws IOException { - if (!closed) { - closed = true; - input.close(); - } - currentEntry = null; - } - - /* - * (non-Javadoc) - * - * @see java.io.InputStream#read(byte[], int, int) - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - int toRead = len; - if (currentEntry != null) { - final long entryEnd = entryOffset + currentEntry.getLength(); - if (len > 0 && entryEnd > offset) { - toRead = (int) Math.min(len, entryEnd - offset); - } else { - return -1; - } - } - final int ret = this.input.read(b, off, toRead); - count(ret); - offset += ret > 0 ? ret : 0; - return ret; - } - - /** - * Checks if the signature matches ASCII "!<arch>" followed by a single LF - * control character - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is an Ar archive stream, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - // 3c21 7261 6863 0a3e - - return length >= 8 && signature[0] == 0x21 && - signature[1] == 0x3c && signature[2] == 0x61 && - signature[3] == 0x72 && signature[4] == 0x63 && - signature[5] == 0x68 && signature[6] == 0x3e && - signature[7] == 0x0a; - } - - static final String BSD_LONGNAME_PREFIX = "#1/"; - private static final int BSD_LONGNAME_PREFIX_LEN = - BSD_LONGNAME_PREFIX.length(); - private static final String BSD_LONGNAME_PATTERN = - "^" + BSD_LONGNAME_PREFIX + "\\d+"; - - /** - * Does the name look like it is a long name (or a name containing - * spaces) as encoded by BSD ar? - * - *

From the FreeBSD ar(5) man page:

- *
-     * BSD   In the BSD variant, names that are shorter than 16
-     *       characters and without embedded spaces are stored
-     *       directly in this field.  If a name has an embedded
-     *       space, or if it is longer than 16 characters, then
-     *       the string "#1/" followed by the decimal represen-
-     *       tation of the length of the file name is placed in
-     *       this field. The actual file name is stored immedi-
-     *       ately after the archive header.  The content of the
-     *       archive member follows the file name.  The ar_size
-     *       field of the header (see below) will then hold the
-     *       sum of the size of the file name and the size of
-     *       the member.
-     * 
- * - * @since 1.3 - */ - private static boolean isBSDLongName(final String name) { - return name != null && name.matches(BSD_LONGNAME_PATTERN); - } - - /** - * Reads the real name from the current stream assuming the very - * first bytes to be read are the real file name. - * - * @see #isBSDLongName - * - * @since 1.3 - */ - private String getBSDLongName(final String bsdLongName) throws IOException { - final int nameLen = - Integer.parseInt(bsdLongName.substring(BSD_LONGNAME_PREFIX_LEN)); - final byte[] name = new byte[nameLen]; - final int read = IOUtils.readFully(this, name); - if (read != nameLen) { - throw new EOFException(); - } - return ArchiveUtils.toAsciiString(name); - } - - private static final String GNU_STRING_TABLE_NAME = "//"; - - /** - * Is this the name of the "Archive String Table" as used by - * SVR4/GNU to store long file names? - * - *

GNU ar stores multiple extended filenames in the data section - * of a file with the name "//", this record is referred to by - * future headers.

- * - *

A header references an extended filename by storing a "/" - * followed by a decimal offset to the start of the filename in - * the extended filename data section.

- * - *

The format of the "//" file itself is simply a list of the - * long filenames, each separated by one or more LF - * characters. Note that the decimal offsets are number of - * characters, not line or string number within the "//" file.

- */ - private static boolean isGNUStringTable(final String name) { - return GNU_STRING_TABLE_NAME.equals(name); - } - - /** - * Reads the GNU archive String Table. - * - * @see #isGNUStringTable - */ - private ArArchiveEntry readGNUStringTable(final byte[] length) throws IOException { - final int bufflen = asInt(length); // Assume length will fit in an int - namebuffer = new byte[bufflen]; - final int read = IOUtils.readFully(this, namebuffer, 0, bufflen); - if (read != bufflen){ - throw new IOException("Failed to read complete // record: expected=" - + bufflen + " read=" + read); - } - return new ArArchiveEntry(GNU_STRING_TABLE_NAME, bufflen); - } - - private static final String GNU_LONGNAME_PATTERN = "^/\\d+"; - - /** - * Does the name look like it is a long name (or a name containing - * spaces) as encoded by SVR4/GNU ar? - * - * @see #isGNUStringTable - */ - private boolean isGNULongName(final String name) { - return name != null && name.matches(GNU_LONGNAME_PATTERN); - } -} diff --git a/src/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java b/src/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java deleted file mode 100644 index ffca90b383a..00000000000 --- a/src/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.ar; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.utils.ArchiveUtils; - -/** - * Implements the "ar" archive format as an output stream. - * - * @NotThreadSafe - */ -public class ArArchiveOutputStream extends ArchiveOutputStream { - /** Fail if a long file name is required in the archive. */ - public static final int LONGFILE_ERROR = 0; - - /** BSD ar extensions are used to store long file names in the archive. */ - public static final int LONGFILE_BSD = 1; - - private final OutputStream out; - private long entryOffset = 0; - private ArArchiveEntry prevEntry; - private boolean haveUnclosedEntry = false; - private int longFileMode = LONGFILE_ERROR; - - /** indicates if this archive is finished */ - private boolean finished = false; - - public ArArchiveOutputStream( final OutputStream pOut ) { - this.out = pOut; - } - - /** - * Set the long file mode. - * This can be LONGFILE_ERROR(0) or LONGFILE_BSD(1). - * This specifies the treatment of long file names (names >= 16). - * Default is LONGFILE_ERROR. - * @param longFileMode the mode to use - * @since 1.3 - */ - public void setLongFileMode(final int longFileMode) { - this.longFileMode = longFileMode; - } - - private long writeArchiveHeader() throws IOException { - final byte [] header = ArchiveUtils.toAsciiBytes(ArArchiveEntry.HEADER); - out.write(header); - return header.length; - } - - @Override - public void closeArchiveEntry() throws IOException { - if(finished) { - throw new IOException("Stream has already been finished"); - } - if (prevEntry == null || !haveUnclosedEntry){ - throw new IOException("No current entry to close"); - } - if (entryOffset % 2 != 0) { - out.write('\n'); // Pad byte - } - haveUnclosedEntry = false; - } - - @Override - public void putArchiveEntry( final ArchiveEntry pEntry ) throws IOException { - if(finished) { - throw new IOException("Stream has already been finished"); - } - - final ArArchiveEntry pArEntry = (ArArchiveEntry)pEntry; - if (prevEntry == null) { - writeArchiveHeader(); - } else { - if (prevEntry.getLength() != entryOffset) { - throw new IOException("length does not match entry (" + prevEntry.getLength() + " != " + entryOffset); - } - - if (haveUnclosedEntry) { - closeArchiveEntry(); - } - } - - prevEntry = pArEntry; - - writeEntryHeader(pArEntry); - - entryOffset = 0; - haveUnclosedEntry = true; - } - - private long fill( final long pOffset, final long pNewOffset, final char pFill ) throws IOException { - final long diff = pNewOffset - pOffset; - - if (diff > 0) { - for (int i = 0; i < diff; i++) { - write(pFill); - } - } - - return pNewOffset; - } - - private long write( final String data ) throws IOException { - final byte[] bytes = data.getBytes("ascii"); - write(bytes); - return bytes.length; - } - - private long writeEntryHeader( final ArArchiveEntry pEntry ) throws IOException { - - long offset = 0; - boolean mustAppendName = false; - - final String n = pEntry.getName(); - if (LONGFILE_ERROR == longFileMode && n.length() > 16) { - throw new IOException("filename too long, > 16 chars: "+n); - } - if (LONGFILE_BSD == longFileMode && - (n.length() > 16 || n.contains(" "))) { - mustAppendName = true; - offset += write(ArArchiveInputStream.BSD_LONGNAME_PREFIX - + String.valueOf(n.length())); - } else { - offset += write(n); - } - - offset = fill(offset, 16, ' '); - final String m = "" + pEntry.getLastModified(); - if (m.length() > 12) { - throw new IOException("modified too long"); - } - offset += write(m); - - offset = fill(offset, 28, ' '); - final String u = "" + pEntry.getUserId(); - if (u.length() > 6) { - throw new IOException("userid too long"); - } - offset += write(u); - - offset = fill(offset, 34, ' '); - final String g = "" + pEntry.getGroupId(); - if (g.length() > 6) { - throw new IOException("groupid too long"); - } - offset += write(g); - - offset = fill(offset, 40, ' '); - final String fm = "" + Integer.toString(pEntry.getMode(), 8); - if (fm.length() > 8) { - throw new IOException("filemode too long"); - } - offset += write(fm); - - offset = fill(offset, 48, ' '); - final String s = - String.valueOf(pEntry.getLength() - + (mustAppendName ? n.length() : 0)); - if (s.length() > 10) { - throw new IOException("size too long"); - } - offset += write(s); - - offset = fill(offset, 58, ' '); - - offset += write(ArArchiveEntry.TRAILER); - - if (mustAppendName) { - offset += write(n); - } - - return offset; - } - - @Override - public void write(final byte[] b, final int off, final int len) throws IOException { - out.write(b, off, len); - count(len); - entryOffset += len; - } - - /** - * Calls finish if necessary, and then closes the OutputStream - */ - @Override - public void close() throws IOException { - if(!finished) { - finish(); - } - out.close(); - prevEntry = null; - } - - @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) - throws IOException { - if(finished) { - throw new IOException("Stream has already been finished"); - } - return new ArArchiveEntry(inputFile, entryName); - } - - @Override - public void finish() throws IOException { - if(haveUnclosedEntry) { - throw new IOException("This archive contains unclosed entries."); - } else if(finished) { - throw new IOException("This archive has already been finished"); - } - finished = true; - } -} diff --git a/src/org/apache/commons/compress/archivers/ar/package.html b/src/org/apache/commons/compress/archivers/ar/package.html deleted file mode 100644 index 9c80f96e144..00000000000 --- a/src/org/apache/commons/compress/archivers/ar/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides stream classes for reading and writing archives using - the AR format.

- - diff --git a/src/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java b/src/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java deleted file mode 100644 index ab847db856c..00000000000 --- a/src/org/apache/commons/compress/archivers/arj/ArjArchiveEntry.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.arj; - -import java.io.File; -import java.util.Date; -import java.util.regex.Matcher; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipUtil; - -/** - * An entry in an ARJ archive. - * - * @NotThreadSafe - * @since 1.6 - */ -public class ArjArchiveEntry implements ArchiveEntry { - private final LocalFileHeader localFileHeader; - - public ArjArchiveEntry() { - localFileHeader = new LocalFileHeader(); - } - - ArjArchiveEntry(final LocalFileHeader localFileHeader) { - this.localFileHeader = localFileHeader; - } - - /** - * Get this entry's name. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return This entry's name. - */ - @Override - public String getName() { - if ((localFileHeader.arjFlags & LocalFileHeader.Flags.PATHSYM) != 0) { - return localFileHeader.name.replaceAll("/", - Matcher.quoteReplacement(File.separator)); - } - return localFileHeader.name; - } - - /** - * Get this entry's file size. - * - * @return This entry's file size. - */ - @Override - public long getSize() { - return localFileHeader.originalSize; - } - - /** True if the entry refers to a directory. - * - * @return True if the entry refers to a directory - */ - @Override - public boolean isDirectory() { - return localFileHeader.fileType == LocalFileHeader.FileTypes.DIRECTORY; - } - - /** - * The last modified date of the entry. - * - *

Note the interpretation of time is different depending on - * the HostOS that has created the archive. While an OS that is - * {@link #isHostOsUnix considered to be Unix} stores time in a - * timezone independent manner, other platforms only use the local - * time. I.e. if an archive has been created at midnight UTC on a - * machine in timezone UTC this method will return midnight - * regardless of timezone if the archive has been created on a - * non-Unix system and a time taking the current timezone into - * account if the archive has beeen created on Unix.

- * - * @return the last modified date - */ - @Override - public Date getLastModifiedDate() { - final long ts = isHostOsUnix() ? localFileHeader.dateTimeModified * 1000L - : ZipUtil.dosToJavaTime(0xFFFFFFFFL & localFileHeader.dateTimeModified); - return new Date(ts); - } - - /** - * File mode of this entry. - * - *

The format depends on the host os that created the entry.

- * - * @return the file mode - */ - public int getMode() { - return localFileHeader.fileAccessMode; - } - - /** - * File mode of this entry as Unix stat value. - * - *

Will only be non-zero of the host os was UNIX. - * - * @return the Unix mode - */ - public int getUnixMode() { - return isHostOsUnix() ? getMode() : 0; - } - - /** - * The operating system the archive has been created on. - * @see HostOs - * @return the host OS code - */ - public int getHostOs() { - return localFileHeader.hostOS; - } - - /** - * Is the operating system the archive has been created on one - * that is considered a UNIX OS by arj? - * @return whether the operating system the archive has been - * created on is considered a UNIX OS by arj - */ - public boolean isHostOsUnix() { - return getHostOs() == HostOs.UNIX || getHostOs() == HostOs.NEXT; - } - - int getMethod() { - return localFileHeader.method; - } - - /** - * The known values for HostOs. - */ - public static class HostOs { - public static final int DOS = 0; - public static final int PRIMOS = 1; - public static final int UNIX = 2; - public static final int AMIGA = 3; - public static final int MAC_OS = 4; - public static final int OS_2 = 5; - public static final int APPLE_GS = 6; - public static final int ATARI_ST = 7; - public static final int NEXT = 8; - public static final int VAX_VMS = 9; - public static final int WIN95 = 10; - public static final int WIN32 = 11; - } - -} diff --git a/src/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java b/src/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java deleted file mode 100644 index c22d4c04785..00000000000 --- a/src/org/apache/commons/compress/archivers/arj/ArjArchiveInputStream.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.arj; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.zip.CRC32; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.utils.BoundedInputStream; -import org.apache.commons.compress.utils.CRC32VerifyingInputStream; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Implements the "arj" archive format as an InputStream. - *

- * Reference - * @NotThreadSafe - * @since 1.6 - */ -public class ArjArchiveInputStream extends ArchiveInputStream { - private static final int ARJ_MAGIC_1 = 0x60; - private static final int ARJ_MAGIC_2 = 0xEA; - private final DataInputStream in; - private final String charsetName; - private final MainHeader mainHeader; - private LocalFileHeader currentLocalFileHeader = null; - private InputStream currentInputStream = null; - - /** - * Constructs the ArjInputStream, taking ownership of the inputStream that is passed in. - * @param inputStream the underlying stream, whose ownership is taken - * @param charsetName the charset used for file names and comments - * in the archive. May be {@code null} to use the platform default. - * @throws ArchiveException if an exception occurs while reading - */ - public ArjArchiveInputStream(final InputStream inputStream, - final String charsetName) throws ArchiveException { - in = new DataInputStream(inputStream); - this.charsetName = charsetName; - try { - mainHeader = readMainHeader(); - if ((mainHeader.arjFlags & MainHeader.Flags.GARBLED) != 0) { - throw new ArchiveException("Encrypted ARJ files are unsupported"); - } - if ((mainHeader.arjFlags & MainHeader.Flags.VOLUME) != 0) { - throw new ArchiveException("Multi-volume ARJ files are unsupported"); - } - } catch (final IOException ioException) { - throw new ArchiveException(ioException.getMessage(), ioException); - } - } - - /** - * Constructs the ArjInputStream, taking ownership of the inputStream that is passed in, - * and using the CP437 character encoding. - * @param inputStream the underlying stream, whose ownership is taken - * @throws ArchiveException if an exception occurs while reading - */ - public ArjArchiveInputStream(final InputStream inputStream) - throws ArchiveException { - this(inputStream, "CP437"); - } - - @Override - public void close() throws IOException { - in.close(); - } - - private int read8(final DataInputStream dataIn) throws IOException { - final int value = dataIn.readUnsignedByte(); - count(1); - return value; - } - - private int read16(final DataInputStream dataIn) throws IOException { - final int value = dataIn.readUnsignedShort(); - count(2); - return Integer.reverseBytes(value) >>> 16; - } - - private int read32(final DataInputStream dataIn) throws IOException { - final int value = dataIn.readInt(); - count(4); - return Integer.reverseBytes(value); - } - - private String readString(final DataInputStream dataIn) throws IOException { - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int nextByte; - while ((nextByte = dataIn.readUnsignedByte()) != 0) { - buffer.write(nextByte); - } - if (charsetName != null) { - return new String(buffer.toByteArray(), charsetName); - } - // intentionally using the default encoding as that's the contract for a null charsetName - return new String(buffer.toByteArray()); - } - - private void readFully(final DataInputStream dataIn, final byte[] b) - throws IOException { - dataIn.readFully(b); - count(b.length); - } - - private byte[] readHeader() throws IOException { - boolean found = false; - byte[] basicHeaderBytes = null; - do { - int first = 0; - int second = read8(in); - do { - first = second; - second = read8(in); - } while (first != ARJ_MAGIC_1 && second != ARJ_MAGIC_2); - final int basicHeaderSize = read16(in); - if (basicHeaderSize == 0) { - // end of archive - return null; - } - if (basicHeaderSize <= 2600) { - basicHeaderBytes = new byte[basicHeaderSize]; - readFully(in, basicHeaderBytes); - final long basicHeaderCrc32 = read32(in) & 0xFFFFFFFFL; - final CRC32 crc32 = new CRC32(); - crc32.update(basicHeaderBytes); - if (basicHeaderCrc32 == crc32.getValue()) { - found = true; - } - } - } while (!found); - return basicHeaderBytes; - } - - private MainHeader readMainHeader() throws IOException { - final byte[] basicHeaderBytes = readHeader(); - if (basicHeaderBytes == null) { - throw new IOException("Archive ends without any headers"); - } - final DataInputStream basicHeader = new DataInputStream( - new ByteArrayInputStream(basicHeaderBytes)); - - final int firstHeaderSize = basicHeader.readUnsignedByte(); - final byte[] firstHeaderBytes = new byte[firstHeaderSize - 1]; - basicHeader.readFully(firstHeaderBytes); - final DataInputStream firstHeader = new DataInputStream( - new ByteArrayInputStream(firstHeaderBytes)); - - final MainHeader hdr = new MainHeader(); - hdr.archiverVersionNumber = firstHeader.readUnsignedByte(); - hdr.minVersionToExtract = firstHeader.readUnsignedByte(); - hdr.hostOS = firstHeader.readUnsignedByte(); - hdr.arjFlags = firstHeader.readUnsignedByte(); - hdr.securityVersion = firstHeader.readUnsignedByte(); - hdr.fileType = firstHeader.readUnsignedByte(); - hdr.reserved = firstHeader.readUnsignedByte(); - hdr.dateTimeCreated = read32(firstHeader); - hdr.dateTimeModified = read32(firstHeader); - hdr.archiveSize = 0xffffFFFFL & read32(firstHeader); - hdr.securityEnvelopeFilePosition = read32(firstHeader); - hdr.fileSpecPosition = read16(firstHeader); - hdr.securityEnvelopeLength = read16(firstHeader); - pushedBackBytes(20); // count has already counted them via readFully - hdr.encryptionVersion = firstHeader.readUnsignedByte(); - hdr.lastChapter = firstHeader.readUnsignedByte(); - - if (firstHeaderSize >= 33) { - hdr.arjProtectionFactor = firstHeader.readUnsignedByte(); - hdr.arjFlags2 = firstHeader.readUnsignedByte(); - firstHeader.readUnsignedByte(); - firstHeader.readUnsignedByte(); - } - - hdr.name = readString(basicHeader); - hdr.comment = readString(basicHeader); - - final int extendedHeaderSize = read16(in); - if (extendedHeaderSize > 0) { - hdr.extendedHeaderBytes = new byte[extendedHeaderSize]; - readFully(in, hdr.extendedHeaderBytes); - final long extendedHeaderCrc32 = 0xffffFFFFL & read32(in); - final CRC32 crc32 = new CRC32(); - crc32.update(hdr.extendedHeaderBytes); - if (extendedHeaderCrc32 != crc32.getValue()) { - throw new IOException("Extended header CRC32 verification failure"); - } - } - - return hdr; - } - - private LocalFileHeader readLocalFileHeader() throws IOException { - final byte[] basicHeaderBytes = readHeader(); - if (basicHeaderBytes == null) { - return null; - } - try (final DataInputStream basicHeader = new DataInputStream(new ByteArrayInputStream(basicHeaderBytes))) { - - final int firstHeaderSize = basicHeader.readUnsignedByte(); - final byte[] firstHeaderBytes = new byte[firstHeaderSize - 1]; - basicHeader.readFully(firstHeaderBytes); - try (final DataInputStream firstHeader = new DataInputStream(new ByteArrayInputStream(firstHeaderBytes))) { - - final LocalFileHeader localFileHeader = new LocalFileHeader(); - localFileHeader.archiverVersionNumber = firstHeader.readUnsignedByte(); - localFileHeader.minVersionToExtract = firstHeader.readUnsignedByte(); - localFileHeader.hostOS = firstHeader.readUnsignedByte(); - localFileHeader.arjFlags = firstHeader.readUnsignedByte(); - localFileHeader.method = firstHeader.readUnsignedByte(); - localFileHeader.fileType = firstHeader.readUnsignedByte(); - localFileHeader.reserved = firstHeader.readUnsignedByte(); - localFileHeader.dateTimeModified = read32(firstHeader); - localFileHeader.compressedSize = 0xffffFFFFL & read32(firstHeader); - localFileHeader.originalSize = 0xffffFFFFL & read32(firstHeader); - localFileHeader.originalCrc32 = 0xffffFFFFL & read32(firstHeader); - localFileHeader.fileSpecPosition = read16(firstHeader); - localFileHeader.fileAccessMode = read16(firstHeader); - pushedBackBytes(20); - localFileHeader.firstChapter = firstHeader.readUnsignedByte(); - localFileHeader.lastChapter = firstHeader.readUnsignedByte(); - - readExtraData(firstHeaderSize, firstHeader, localFileHeader); - - localFileHeader.name = readString(basicHeader); - localFileHeader.comment = readString(basicHeader); - - final ArrayList extendedHeaders = new ArrayList<>(); - int extendedHeaderSize; - while ((extendedHeaderSize = read16(in)) > 0) { - final byte[] extendedHeaderBytes = new byte[extendedHeaderSize]; - readFully(in, extendedHeaderBytes); - final long extendedHeaderCrc32 = 0xffffFFFFL & read32(in); - final CRC32 crc32 = new CRC32(); - crc32.update(extendedHeaderBytes); - if (extendedHeaderCrc32 != crc32.getValue()) { - throw new IOException("Extended header CRC32 verification failure"); - } - extendedHeaders.add(extendedHeaderBytes); - } - localFileHeader.extendedHeaders = extendedHeaders.toArray(new byte[extendedHeaders.size()][]); - - return localFileHeader; - } - } - } - - private void readExtraData(final int firstHeaderSize, final DataInputStream firstHeader, - final LocalFileHeader localFileHeader) throws IOException { - if (firstHeaderSize >= 33) { - localFileHeader.extendedFilePosition = read32(firstHeader); - if (firstHeaderSize >= 45) { - localFileHeader.dateTimeAccessed = read32(firstHeader); - localFileHeader.dateTimeCreated = read32(firstHeader); - localFileHeader.originalSizeEvenForVolumes = read32(firstHeader); - pushedBackBytes(12); - } - pushedBackBytes(4); - } - } - - /** - * Checks if the signature matches what is expected for an arj file. - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is an arj archive stream, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - return length >= 2 && - (0xff & signature[0]) == ARJ_MAGIC_1 && - (0xff & signature[1]) == ARJ_MAGIC_2; - } - - /** - * Gets the archive's recorded name. - * @return the archive's name - */ - public String getArchiveName() { - return mainHeader.name; - } - - /** - * Gets the archive's comment. - * @return the archive's comment - */ - public String getArchiveComment() { - return mainHeader.comment; - } - - @Override - public ArjArchiveEntry getNextEntry() throws IOException { - if (currentInputStream != null) { - // return value ignored as IOUtils.skip ensures the stream is drained completely - IOUtils.skip(currentInputStream, Long.MAX_VALUE); - currentInputStream.close(); - currentLocalFileHeader = null; - currentInputStream = null; - } - - currentLocalFileHeader = readLocalFileHeader(); - if (currentLocalFileHeader != null) { - currentInputStream = new BoundedInputStream(in, currentLocalFileHeader.compressedSize); - if (currentLocalFileHeader.method == LocalFileHeader.Methods.STORED) { - currentInputStream = new CRC32VerifyingInputStream(currentInputStream, - currentLocalFileHeader.originalSize, currentLocalFileHeader.originalCrc32); - } - return new ArjArchiveEntry(currentLocalFileHeader); - } - currentInputStream = null; - return null; - } - - @Override - public boolean canReadEntryData(final ArchiveEntry ae) { - return ae instanceof ArjArchiveEntry - && ((ArjArchiveEntry) ae).getMethod() == LocalFileHeader.Methods.STORED; - } - - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (currentLocalFileHeader == null) { - throw new IllegalStateException("No current arj entry"); - } - if (currentLocalFileHeader.method != LocalFileHeader.Methods.STORED) { - throw new IOException("Unsupported compression method " + currentLocalFileHeader.method); - } - return currentInputStream.read(b, off, len); - } -} diff --git a/src/org/apache/commons/compress/archivers/arj/LocalFileHeader.java b/src/org/apache/commons/compress/archivers/arj/LocalFileHeader.java deleted file mode 100644 index 6ecb297becd..00000000000 --- a/src/org/apache/commons/compress/archivers/arj/LocalFileHeader.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.arj; - -import java.util.Arrays; - -class LocalFileHeader { - int archiverVersionNumber; - int minVersionToExtract; - int hostOS; - int arjFlags; - int method; - int fileType; - int reserved; - int dateTimeModified; - long compressedSize; - long originalSize; - long originalCrc32; - int fileSpecPosition; - int fileAccessMode; - int firstChapter; - int lastChapter; - - int extendedFilePosition; - int dateTimeAccessed; - int dateTimeCreated; - int originalSizeEvenForVolumes; - - String name; - String comment; - - byte[][] extendedHeaders = null; - - static class Flags { - static final int GARBLED = 0x01; - static final int VOLUME = 0x04; - static final int EXTFILE = 0x08; - static final int PATHSYM = 0x10; - static final int BACKUP = 0x20; - } - - static class FileTypes { - static final int BINARY = 0; - static final int SEVEN_BIT_TEXT = 1; - static final int DIRECTORY = 3; - static final int VOLUME_LABEL = 4; - static final int CHAPTER_LABEL = 5; - } - - static class Methods { - static final int STORED = 0; - static final int COMPRESSED_MOST = 1; - static final int COMPRESSED_FASTEST = 4; - static final int NO_DATA_NO_CRC = 8; - static final int NO_DATA = 9; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("LocalFileHeader [archiverVersionNumber="); - builder.append(archiverVersionNumber); - builder.append(", minVersionToExtract="); - builder.append(minVersionToExtract); - builder.append(", hostOS="); - builder.append(hostOS); - builder.append(", arjFlags="); - builder.append(arjFlags); - builder.append(", method="); - builder.append(method); - builder.append(", fileType="); - builder.append(fileType); - builder.append(", reserved="); - builder.append(reserved); - builder.append(", dateTimeModified="); - builder.append(dateTimeModified); - builder.append(", compressedSize="); - builder.append(compressedSize); - builder.append(", originalSize="); - builder.append(originalSize); - builder.append(", originalCrc32="); - builder.append(originalCrc32); - builder.append(", fileSpecPosition="); - builder.append(fileSpecPosition); - builder.append(", fileAccessMode="); - builder.append(fileAccessMode); - builder.append(", firstChapter="); - builder.append(firstChapter); - builder.append(", lastChapter="); - builder.append(lastChapter); - builder.append(", extendedFilePosition="); - builder.append(extendedFilePosition); - builder.append(", dateTimeAccessed="); - builder.append(dateTimeAccessed); - builder.append(", dateTimeCreated="); - builder.append(dateTimeCreated); - builder.append(", originalSizeEvenForVolumes="); - builder.append(originalSizeEvenForVolumes); - builder.append(", name="); - builder.append(name); - builder.append(", comment="); - builder.append(comment); - builder.append(", extendedHeaders="); - builder.append(Arrays.toString(extendedHeaders)); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/org/apache/commons/compress/archivers/arj/MainHeader.java b/src/org/apache/commons/compress/archivers/arj/MainHeader.java deleted file mode 100644 index 7a9f212a28b..00000000000 --- a/src/org/apache/commons/compress/archivers/arj/MainHeader.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.arj; - -import java.util.Arrays; - -class MainHeader { - int archiverVersionNumber; - int minVersionToExtract; - int hostOS; - int arjFlags; - int securityVersion; - int fileType; - int reserved; - int dateTimeCreated; - int dateTimeModified; - long archiveSize; - int securityEnvelopeFilePosition; - int fileSpecPosition; - int securityEnvelopeLength; - int encryptionVersion; - int lastChapter; - int arjProtectionFactor; - int arjFlags2; - String name; - String comment; - byte[] extendedHeaderBytes = null; - - static class Flags { - static final int GARBLED = 0x01; - static final int OLD_SECURED_NEW_ANSI_PAGE = 0x02; - static final int VOLUME = 0x04; - static final int ARJPROT = 0x08; - static final int PATHSYM = 0x10; - static final int BACKUP = 0x20; - static final int SECURED = 0x40; - static final int ALTNAME = 0x80; - } - - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("MainHeader [archiverVersionNumber="); - builder.append(archiverVersionNumber); - builder.append(", minVersionToExtract="); - builder.append(minVersionToExtract); - builder.append(", hostOS="); - builder.append(hostOS); - builder.append(", arjFlags="); - builder.append(arjFlags); - builder.append(", securityVersion="); - builder.append(securityVersion); - builder.append(", fileType="); - builder.append(fileType); - builder.append(", reserved="); - builder.append(reserved); - builder.append(", dateTimeCreated="); - builder.append(dateTimeCreated); - builder.append(", dateTimeModified="); - builder.append(dateTimeModified); - builder.append(", archiveSize="); - builder.append(archiveSize); - builder.append(", securityEnvelopeFilePosition="); - builder.append(securityEnvelopeFilePosition); - builder.append(", fileSpecPosition="); - builder.append(fileSpecPosition); - builder.append(", securityEnvelopeLength="); - builder.append(securityEnvelopeLength); - builder.append(", encryptionVersion="); - builder.append(encryptionVersion); - builder.append(", lastChapter="); - builder.append(lastChapter); - builder.append(", arjProtectionFactor="); - builder.append(arjProtectionFactor); - builder.append(", arjFlags2="); - builder.append(arjFlags2); - builder.append(", name="); - builder.append(name); - builder.append(", comment="); - builder.append(comment); - builder.append(", extendedHeaderBytes="); - builder.append(Arrays.toString(extendedHeaderBytes)); - builder.append("]"); - return builder.toString(); - } -} diff --git a/src/org/apache/commons/compress/archivers/arj/package.html b/src/org/apache/commons/compress/archivers/arj/package.html deleted file mode 100644 index de18f61d884..00000000000 --- a/src/org/apache/commons/compress/archivers/arj/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides stream classes for reading archives using - the ARJ format.

- - diff --git a/src/org/apache/commons/compress/archivers/cpio/CpioArchiveEntry.java b/src/org/apache/commons/compress/archivers/cpio/CpioArchiveEntry.java deleted file mode 100644 index 28e58238cc4..00000000000 --- a/src/org/apache/commons/compress/archivers/cpio/CpioArchiveEntry.java +++ /dev/null @@ -1,896 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.cpio; - -import java.io.File; -import java.util.Date; - -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * A cpio archive consists of a sequence of files. There are several types of - * headers defided in two categories of new and old format. The headers are - * recognized by magic numbers: - * - *
    - *
  • "070701" ASCII for new portable format
  • - *
  • "070702" ASCII for new portable format with CRC
  • - *
  • "070707" ASCII for old ascii (also known as Portable ASCII, odc or old - * character format
  • - *
  • 070707 binary for old binary
  • - *
- * - *

The old binary format is limited to 16 bits for user id, group - * id, device, and inode numbers. It is limited to 4 gigabyte file - * sizes. - * - * The old ASCII format is limited to 18 bits for the user id, group - * id, device, and inode numbers. It is limited to 8 gigabyte file - * sizes. - * - * The new ASCII format is limited to 4 gigabyte file sizes. - * - * CPIO 2.5 knows also about tar, but it is not recognized here.

- * - * - *

OLD FORMAT

- * - *

Each file has a 76 (ascii) / 26 (binary) byte header, a variable - * length, NUL terminated filename, and variable length file data. A - * header for a filename "TRAILER!!!" indicates the end of the - * archive.

- * - *

All the fields in the header are ISO 646 (approximately ASCII) - * strings of octal numbers, left padded, not NUL terminated.

- * - *
- * FIELDNAME        NOTES
- * c_magic          The integer value octal 070707.  This value can be used to deter-
- *                  mine whether this archive is written with little-endian or big-
- *                  endian integers.
- * c_dev            Device that contains a directory entry for this file
- * c_ino            I-node number that identifies the input file to the file system
- * c_mode           The mode specifies both the regular permissions and the file type.
- * c_uid            Numeric User ID of the owner of the input file
- * c_gid            Numeric Group ID of the owner of the input file
- * c_nlink          Number of links that are connected to the input file
- * c_rdev           For block special and character special entries, this field
- *                  contains the associated device number.  For all other entry types,
- *                  it should be set to zero by writers and ignored by readers.
- * c_mtime[2]       Modification time of the file, indicated as the number of seconds
- *                  since the start of the epoch, 00:00:00 UTC January 1, 1970.  The
- *                  four-byte integer is stored with the most-significant 16 bits
- *                  first followed by the least-significant 16 bits.  Each of the two
- *                  16 bit values are stored in machine-native byte order.
- * c_namesize       Length of the path name, including the terminating null byte
- * c_filesize[2]    Length of the file in bytes. This is the length of the data
- *                  section that follows the header structure. Must be 0 for
- *                  FIFOs and directories
- *
- * All fields are unsigned short fields with 16-bit integer values
- * apart from c_mtime and c_filesize which are 32-bit integer values
- * 
- * - *

If necessary, the filename and file data are padded with a NUL byte to an even length

- * - *

Special files, directories, and the trailer are recorded with - * the h_filesize field equal to 0.

- * - *

In the ASCII version of this format, the 16-bit entries are represented as 6-byte octal numbers, - * and the 32-bit entries are represented as 11-byte octal numbers. No padding is added.

- * - *

NEW FORMAT

- * - *

Each file has a 110 byte header, a variable length, NUL - * terminated filename, and variable length file data. A header for a - * filename "TRAILER!!!" indicates the end of the archive. All the - * fields in the header are ISO 646 (approximately ASCII) strings of - * hexadecimal numbers, left padded, not NUL terminated.

- * - *
- * FIELDNAME        NOTES
- * c_magic[6]       The string 070701 for new ASCII, the string 070702 for new ASCII with CRC
- * c_ino[8]
- * c_mode[8]
- * c_uid[8]
- * c_gid[8]
- * c_nlink[8]
- * c_mtim[8]
- * c_filesize[8]    must be 0 for FIFOs and directories
- * c_maj[8]
- * c_min[8]
- * c_rmaj[8]        only valid for chr and blk special files
- * c_rmin[8]        only valid for chr and blk special files
- * c_namesize[8]    count includes terminating NUL in pathname
- * c_check[8]       0 for "new" portable format; for CRC format
- *                  the sum of all the bytes in the file
- * 
- * - *

New ASCII Format The "new" ASCII format uses 8-byte hexadecimal - * fields for all numbers and separates device numbers into separate - * fields for major and minor numbers.

- * - *

The pathname is followed by NUL bytes so that the total size of - * the fixed header plus pathname is a multiple of four. Likewise, the - * file data is padded to a multiple of four bytes.

- * - *

This class uses mutable fields and is not considered to be - * threadsafe.

- * - *

Based on code from the jRPM project (http://jrpm.sourceforge.net).

- * - *

The MAGIC numbers and other constants are defined in {@link CpioConstants}

- * - *

- * N.B. does not handle the cpio "tar" format - *

- * @NotThreadSafe - * @see https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt - */ -public class CpioArchiveEntry implements CpioConstants, ArchiveEntry { - - // Header description fields - should be same throughout an archive - - /** - * See constructor documenation for possible values. - */ - private final short fileFormat; - - /** The number of bytes in each header record; depends on the file format */ - private final int headerSize; - - /** The boundary to which the header and data elements are aligned: 0, 2 or 4 bytes */ - private final int alignmentBoundary; - - // Header fields - - private long chksum = 0; - - /** Number of bytes in the file */ - private long filesize = 0; - - private long gid = 0; - - private long inode = 0; - - private long maj = 0; - - private long min = 0; - - private long mode = 0; - - private long mtime = 0; - - private String name; - - private long nlink = 0; - - private long rmaj = 0; - - private long rmin = 0; - - private long uid = 0; - - /** - * Creates a CpioArchiveEntry with a specified format. - * - * @param format - * The cpio format for this entry. - *

- * Possible format values are: - *

-     * CpioConstants.FORMAT_NEW
-     * CpioConstants.FORMAT_NEW_CRC
-     * CpioConstants.FORMAT_OLD_BINARY
-     * CpioConstants.FORMAT_OLD_ASCII
-     * 
- */ - public CpioArchiveEntry(final short format) { - switch (format) { - case FORMAT_NEW: - this.headerSize = 110; - this.alignmentBoundary = 4; - break; - case FORMAT_NEW_CRC: - this.headerSize = 110; - this.alignmentBoundary = 4; - break; - case FORMAT_OLD_ASCII: - this.headerSize = 76; - this.alignmentBoundary = 0; - break; - case FORMAT_OLD_BINARY: - this.headerSize = 26; - this.alignmentBoundary = 2; - break; - default: - throw new IllegalArgumentException("Unknown header type"); - } - this.fileFormat = format; - } - - /** - * Creates a CpioArchiveEntry with a specified name. The format of - * this entry will be the new format. - * - * @param name - * The name of this entry. - */ - public CpioArchiveEntry(final String name) { - this(FORMAT_NEW, name); - } - - /** - * Creates a CpioArchiveEntry with a specified name. - * - * @param format - * The cpio format for this entry. - * @param name - * The name of this entry. - *

- * Possible format values are: - *

-     * CpioConstants.FORMAT_NEW
-     * CpioConstants.FORMAT_NEW_CRC
-     * CpioConstants.FORMAT_OLD_BINARY
-     * CpioConstants.FORMAT_OLD_ASCII
-     * 
- * - * @since 1.1 - */ - public CpioArchiveEntry(final short format, final String name) { - this(format); - this.name = name; - } - - /** - * Creates a CpioArchiveEntry with a specified name. The format of - * this entry will be the new format. - * - * @param name - * The name of this entry. - * @param size - * The size of this entry - */ - public CpioArchiveEntry(final String name, final long size) { - this(name); - this.setSize(size); - } - - /** - * Creates a CpioArchiveEntry with a specified name. - * - * @param format - * The cpio format for this entry. - * @param name - * The name of this entry. - * @param size - * The size of this entry - *

- * Possible format values are: - *

-     * CpioConstants.FORMAT_NEW
-     * CpioConstants.FORMAT_NEW_CRC
-     * CpioConstants.FORMAT_OLD_BINARY
-     * CpioConstants.FORMAT_OLD_ASCII
-     * 
- * - * @since 1.1 - */ - public CpioArchiveEntry(final short format, final String name, - final long size) { - this(format, name); - this.setSize(size); - } - - /** - * Creates a CpioArchiveEntry with a specified name for a - * specified file. The format of this entry will be the new - * format. - * - * @param inputFile - * The file to gather information from. - * @param entryName - * The name of this entry. - */ - public CpioArchiveEntry(final File inputFile, final String entryName) { - this(FORMAT_NEW, inputFile, entryName); - } - - /** - * Creates a CpioArchiveEntry with a specified name for a - * specified file. - * - * @param format - * The cpio format for this entry. - * @param inputFile - * The file to gather information from. - * @param entryName - * The name of this entry. - *

- * Possible format values are: - *

-     * CpioConstants.FORMAT_NEW
-     * CpioConstants.FORMAT_NEW_CRC
-     * CpioConstants.FORMAT_OLD_BINARY
-     * CpioConstants.FORMAT_OLD_ASCII
-     * 
- * - * @since 1.1 - */ - public CpioArchiveEntry(final short format, final File inputFile, - final String entryName) { - this(format, entryName, inputFile.isFile() ? inputFile.length() : 0); - if (inputFile.isDirectory()){ - setMode(C_ISDIR); - } else if (inputFile.isFile()){ - setMode(C_ISREG); - } else { - throw new IllegalArgumentException("Cannot determine type of file " - + inputFile.getName()); - } - // TODO set other fields as needed - setTime(inputFile.lastModified() / 1000); - } - - /** - * Check if the method is allowed for the defined format. - */ - private void checkNewFormat() { - if ((this.fileFormat & FORMAT_NEW_MASK) == 0) { - throw new UnsupportedOperationException(); - } - } - - /** - * Check if the method is allowed for the defined format. - */ - private void checkOldFormat() { - if ((this.fileFormat & FORMAT_OLD_MASK) == 0) { - throw new UnsupportedOperationException(); - } - } - - /** - * Get the checksum. - * Only supported for the new formats. - * - * @return Returns the checksum. - * @throws UnsupportedOperationException if the format is not a new format - */ - public long getChksum() { - checkNewFormat(); - return this.chksum & 0xFFFFFFFFL; - } - - /** - * Get the device id. - * - * @return Returns the device id. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with a new - * format. - */ - public long getDevice() { - checkOldFormat(); - return this.min; - } - - /** - * Get the major device id. - * - * @return Returns the major device id. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with an old - * format. - */ - public long getDeviceMaj() { - checkNewFormat(); - return this.maj; - } - - /** - * Get the minor device id - * - * @return Returns the minor device id. - * @throws UnsupportedOperationException if format is not a new format - */ - public long getDeviceMin() { - checkNewFormat(); - return this.min; - } - - /** - * Get the filesize. - * - * @return Returns the filesize. - * @see org.apache.commons.compress.archivers.ArchiveEntry#getSize() - */ - @Override - public long getSize() { - return this.filesize; - } - - /** - * Get the format for this entry. - * - * @return Returns the format. - */ - public short getFormat() { - return this.fileFormat; - } - - /** - * Get the group id. - * - * @return Returns the group id. - */ - public long getGID() { - return this.gid; - } - - /** - * Get the header size for this CPIO format - * - * @return Returns the header size in bytes. - */ - public int getHeaderSize() { - return this.headerSize; - } - - /** - * Get the alignment boundary for this CPIO format - * - * @return Returns the aligment boundary (0, 2, 4) in bytes - */ - public int getAlignmentBoundary() { - return this.alignmentBoundary; - } - - /** - * Get the number of bytes needed to pad the header to the alignment boundary. - * - * @return the number of bytes needed to pad the header (0,1,2,3) - */ - public int getHeaderPadCount(){ - if (this.alignmentBoundary == 0) { return 0; } - int size = this.headerSize + 1; // Name has terminating null - if (name != null) { - size += name.length(); - } - final int remain = size % this.alignmentBoundary; - if (remain > 0){ - return this.alignmentBoundary - remain; - } - return 0; - } - - /** - * Get the number of bytes needed to pad the data to the alignment boundary. - * - * @return the number of bytes needed to pad the data (0,1,2,3) - */ - public int getDataPadCount(){ - if (this.alignmentBoundary == 0) { return 0; } - final long size = this.filesize; - final int remain = (int) (size % this.alignmentBoundary); - if (remain > 0){ - return this.alignmentBoundary - remain; - } - return 0; - } - - /** - * Set the inode. - * - * @return Returns the inode. - */ - public long getInode() { - return this.inode; - } - - /** - * Get the mode of this entry (e.g. directory, regular file). - * - * @return Returns the mode. - */ - public long getMode() { - return mode == 0 && !CPIO_TRAILER.equals(name) ? C_ISREG : mode; - } - - /** - * Get the name. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return Returns the name. - */ - @Override - public String getName() { - return this.name; - } - - /** - * Get the number of links. - * - * @return Returns the number of links. - */ - public long getNumberOfLinks() { - return nlink == 0 ? - isDirectory() ? 2 : 1 - : nlink; - } - - /** - * Get the remote device id. - * - * @return Returns the remote device id. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with a new - * format. - */ - public long getRemoteDevice() { - checkOldFormat(); - return this.rmin; - } - - /** - * Get the remote major device id. - * - * @return Returns the remote major device id. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with an old - * format. - */ - public long getRemoteDeviceMaj() { - checkNewFormat(); - return this.rmaj; - } - - /** - * Get the remote minor device id. - * - * @return Returns the remote minor device id. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with an old - * format. - */ - public long getRemoteDeviceMin() { - checkNewFormat(); - return this.rmin; - } - - /** - * Get the time in seconds. - * - * @return Returns the time. - */ - public long getTime() { - return this.mtime; - } - - @Override - public Date getLastModifiedDate() { - return new Date(1000 * getTime()); - } - - /** - * Get the user id. - * - * @return Returns the user id. - */ - public long getUID() { - return this.uid; - } - - /** - * Check if this entry represents a block device. - * - * @return TRUE if this entry is a block device. - */ - public boolean isBlockDevice() { - return CpioUtil.fileType(mode) == C_ISBLK; - } - - /** - * Check if this entry represents a character device. - * - * @return TRUE if this entry is a character device. - */ - public boolean isCharacterDevice() { - return CpioUtil.fileType(mode) == C_ISCHR; - } - - /** - * Check if this entry represents a directory. - * - * @return TRUE if this entry is a directory. - */ - @Override - public boolean isDirectory() { - return CpioUtil.fileType(mode) == C_ISDIR; - } - - /** - * Check if this entry represents a network device. - * - * @return TRUE if this entry is a network device. - */ - public boolean isNetwork() { - return CpioUtil.fileType(mode) == C_ISNWK; - } - - /** - * Check if this entry represents a pipe. - * - * @return TRUE if this entry is a pipe. - */ - public boolean isPipe() { - return CpioUtil.fileType(mode) == C_ISFIFO; - } - - /** - * Check if this entry represents a regular file. - * - * @return TRUE if this entry is a regular file. - */ - public boolean isRegularFile() { - return CpioUtil.fileType(mode) == C_ISREG; - } - - /** - * Check if this entry represents a socket. - * - * @return TRUE if this entry is a socket. - */ - public boolean isSocket() { - return CpioUtil.fileType(mode) == C_ISSOCK; - } - - /** - * Check if this entry represents a symbolic link. - * - * @return TRUE if this entry is a symbolic link. - */ - public boolean isSymbolicLink() { - return CpioUtil.fileType(mode) == C_ISLNK; - } - - /** - * Set the checksum. The checksum is calculated by adding all bytes of a - * file to transfer (crc += buf[pos] & 0xFF). - * - * @param chksum - * The checksum to set. - */ - public void setChksum(final long chksum) { - checkNewFormat(); - this.chksum = chksum & 0xFFFFFFFFL; - } - - /** - * Set the device id. - * - * @param device - * The device id to set. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with a new - * format. - */ - public void setDevice(final long device) { - checkOldFormat(); - this.min = device; - } - - /** - * Set major device id. - * - * @param maj - * The major device id to set. - */ - public void setDeviceMaj(final long maj) { - checkNewFormat(); - this.maj = maj; - } - - /** - * Set the minor device id - * - * @param min - * The minor device id to set. - */ - public void setDeviceMin(final long min) { - checkNewFormat(); - this.min = min; - } - - /** - * Set the filesize. - * - * @param size - * The filesize to set. - */ - public void setSize(final long size) { - if (size < 0 || size > 0xFFFFFFFFL) { - throw new IllegalArgumentException("invalid entry size <" + size - + ">"); - } - this.filesize = size; - } - - /** - * Set the group id. - * - * @param gid - * The group id to set. - */ - public void setGID(final long gid) { - this.gid = gid; - } - - /** - * Set the inode. - * - * @param inode - * The inode to set. - */ - public void setInode(final long inode) { - this.inode = inode; - } - - /** - * Set the mode of this entry (e.g. directory, regular file). - * - * @param mode - * The mode to set. - */ - public void setMode(final long mode) { - final long maskedMode = mode & S_IFMT; - switch ((int) maskedMode) { - case C_ISDIR: - case C_ISLNK: - case C_ISREG: - case C_ISFIFO: - case C_ISCHR: - case C_ISBLK: - case C_ISSOCK: - case C_ISNWK: - break; - default: - throw new IllegalArgumentException( - "Unknown mode. " - + "Full: " + Long.toHexString(mode) - + " Masked: " + Long.toHexString(maskedMode)); - } - - this.mode = mode; - } - - /** - * Set the name. - * - * @param name - * The name to set. - */ - public void setName(final String name) { - this.name = name; - } - - /** - * Set the number of links. - * - * @param nlink - * The number of links to set. - */ - public void setNumberOfLinks(final long nlink) { - this.nlink = nlink; - } - - /** - * Set the remote device id. - * - * @param device - * The remote device id to set. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with a new - * format. - */ - public void setRemoteDevice(final long device) { - checkOldFormat(); - this.rmin = device; - } - - /** - * Set the remote major device id. - * - * @param rmaj - * The remote major device id to set. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with an old - * format. - */ - public void setRemoteDeviceMaj(final long rmaj) { - checkNewFormat(); - this.rmaj = rmaj; - } - - /** - * Set the remote minor device id. - * - * @param rmin - * The remote minor device id to set. - * @throws UnsupportedOperationException - * if this method is called for a CpioArchiveEntry with an old - * format. - */ - public void setRemoteDeviceMin(final long rmin) { - checkNewFormat(); - this.rmin = rmin; - } - - /** - * Set the time in seconds. - * - * @param time - * The time to set. - */ - public void setTime(final long time) { - this.mtime = time; - } - - /** - * Set the user id. - * - * @param uid - * The user id to set. - */ - public void setUID(final long uid) { - this.uid = uid; - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (name == null ? 0 : name.hashCode()); - return result; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final CpioArchiveEntry other = (CpioArchiveEntry) obj; - if (name == null) { - return other.name == null; - } else { - return name.equals(other.name); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java b/src/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java deleted file mode 100644 index ad8e125a9b2..00000000000 --- a/src/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.cpio; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; -import org.apache.commons.compress.utils.ArchiveUtils; -import org.apache.commons.compress.utils.CharsetNames; -import org.apache.commons.compress.utils.IOUtils; - -/** - * CpioArchiveInputStream is a stream for reading cpio streams. All formats of - * cpio are supported (old ascii, old binary, new portable format and the new - * portable format with crc). - * - *

- * The stream can be read by extracting a cpio entry (containing all - * informations about a entry) and afterwards reading from the stream the file - * specified by the entry. - *

- *
- * CpioArchiveInputStream cpioIn = new CpioArchiveInputStream(
- *         Files.newInputStream(Paths.get("test.cpio")));
- * CpioArchiveEntry cpioEntry;
- *
- * while ((cpioEntry = cpioIn.getNextEntry()) != null) {
- *     System.out.println(cpioEntry.getName());
- *     int tmp;
- *     StringBuilder buf = new StringBuilder();
- *     while ((tmp = cpIn.read()) != -1) {
- *         buf.append((char) tmp);
- *     }
- *     System.out.println(buf.toString());
- * }
- * cpioIn.close();
- * 
- *

- * Note: This implementation should be compatible to cpio 2.5 - * - *

This class uses mutable fields and is not considered to be threadsafe. - * - *

Based on code from the jRPM project (jrpm.sourceforge.net) - */ - -public class CpioArchiveInputStream extends ArchiveInputStream implements - CpioConstants { - - private boolean closed = false; - - private CpioArchiveEntry entry; - - private long entryBytesRead = 0; - - private boolean entryEOF = false; - - private final byte tmpbuf[] = new byte[4096]; - - private long crc = 0; - - private final InputStream in; - - // cached buffers - must only be used locally in the class (COMPRESS-172 - reduce garbage collection) - private final byte[] twoBytesBuf = new byte[2]; - private final byte[] fourBytesBuf = new byte[4]; - private final byte[] sixBytesBuf = new byte[6]; - - private final int blockSize; - - /** - * The encoding to use for filenames and labels. - */ - private final ZipEncoding zipEncoding; - - // the provided encoding (for unit tests) - final String encoding; - - /** - * Construct the cpio input stream with a blocksize of {@link - * CpioConstants#BLOCK_SIZE BLOCK_SIZE} and expecting ASCII file - * names. - * - * @param in - * The cpio stream - */ - public CpioArchiveInputStream(final InputStream in) { - this(in, BLOCK_SIZE, CharsetNames.US_ASCII); - } - - /** - * Construct the cpio input stream with a blocksize of {@link - * CpioConstants#BLOCK_SIZE BLOCK_SIZE}. - * - * @param in - * The cpio stream - * @param encoding - * The encoding of file names to expect - use null for - * the platform's default. - * @since 1.6 - */ - public CpioArchiveInputStream(final InputStream in, final String encoding) { - this(in, BLOCK_SIZE, encoding); - } - - /** - * Construct the cpio input stream with a blocksize of {@link - * CpioConstants#BLOCK_SIZE BLOCK_SIZE} expecting ASCII file - * names. - * - * @param in - * The cpio stream - * @param blockSize - * The block size of the archive. - * @since 1.5 - */ - public CpioArchiveInputStream(final InputStream in, final int blockSize) { - this(in, blockSize, CharsetNames.US_ASCII); - } - - /** - * Construct the cpio input stream with a blocksize of {@link CpioConstants#BLOCK_SIZE BLOCK_SIZE}. - * - * @param in - * The cpio stream - * @param blockSize - * The block size of the archive. - * @param encoding - * The encoding of file names to expect - use null for - * the platform's default. - * @since 1.6 - */ - public CpioArchiveInputStream(final InputStream in, final int blockSize, final String encoding) { - this.in = in; - this.blockSize = blockSize; - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - } - - /** - * Returns 0 after EOF has reached for the current entry data, otherwise - * always return 1. - *

- * Programs should not count on this method to return the actual number of - * bytes that could be read without blocking. - * - * @return 1 before EOF and 0 after EOF has reached for current entry. - * @throws IOException - * if an I/O error has occurred or if a CPIO file error has - * occurred - */ - @Override - public int available() throws IOException { - ensureOpen(); - if (this.entryEOF) { - return 0; - } - return 1; - } - - /** - * Closes the CPIO input stream. - * - * @throws IOException - * if an I/O error has occurred - */ - @Override - public void close() throws IOException { - if (!this.closed) { - in.close(); - this.closed = true; - } - } - - /** - * Closes the current CPIO entry and positions the stream for reading the - * next entry. - * - * @throws IOException - * if an I/O error has occurred or if a CPIO file error has - * occurred - */ - private void closeEntry() throws IOException { - // the skip implementation of this class will not skip more - // than Integer.MAX_VALUE bytes - while (skip((long) Integer.MAX_VALUE) == Integer.MAX_VALUE) { // NOPMD - // do nothing - } - } - - /** - * Check to make sure that this stream has not been closed - * - * @throws IOException - * if the stream is already closed - */ - private void ensureOpen() throws IOException { - if (this.closed) { - throw new IOException("Stream closed"); - } - } - - /** - * Reads the next CPIO file entry and positions stream at the beginning of - * the entry data. - * - * @return the CpioArchiveEntry just read - * @throws IOException - * if an I/O error has occurred or if a CPIO file error has - * occurred - */ - public CpioArchiveEntry getNextCPIOEntry() throws IOException { - ensureOpen(); - if (this.entry != null) { - closeEntry(); - } - readFully(twoBytesBuf, 0, twoBytesBuf.length); - if (CpioUtil.byteArray2long(twoBytesBuf, false) == MAGIC_OLD_BINARY) { - this.entry = readOldBinaryEntry(false); - } else if (CpioUtil.byteArray2long(twoBytesBuf, true) - == MAGIC_OLD_BINARY) { - this.entry = readOldBinaryEntry(true); - } else { - System.arraycopy(twoBytesBuf, 0, sixBytesBuf, 0, - twoBytesBuf.length); - readFully(sixBytesBuf, twoBytesBuf.length, - fourBytesBuf.length); - final String magicString = ArchiveUtils.toAsciiString(sixBytesBuf); - switch (magicString) { - case MAGIC_NEW: - this.entry = readNewEntry(false); - break; - case MAGIC_NEW_CRC: - this.entry = readNewEntry(true); - break; - case MAGIC_OLD_ASCII: - this.entry = readOldAsciiEntry(); - break; - default: - throw new IOException("Unknown magic [" + magicString + "]. Occured at byte: " + getBytesRead()); - } - } - - this.entryBytesRead = 0; - this.entryEOF = false; - this.crc = 0; - - if (this.entry.getName().equals(CPIO_TRAILER)) { - this.entryEOF = true; - skipRemainderOfLastBlock(); - return null; - } - return this.entry; - } - - private void skip(final int bytes) throws IOException{ - // bytes cannot be more than 3 bytes - if (bytes > 0) { - readFully(fourBytesBuf, 0, bytes); - } - } - - /** - * Reads from the current CPIO entry into an array of bytes. Blocks until - * some input is available. - * - * @param b - * the buffer into which the data is read - * @param off - * the start offset of the data - * @param len - * the maximum number of bytes read - * @return the actual number of bytes read, or -1 if the end of the entry is - * reached - * @throws IOException - * if an I/O error has occurred or if a CPIO file error has - * occurred - */ - @Override - public int read(final byte[] b, final int off, final int len) - throws IOException { - ensureOpen(); - if (off < 0 || len < 0 || off > b.length - len) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - - if (this.entry == null || this.entryEOF) { - return -1; - } - if (this.entryBytesRead == this.entry.getSize()) { - skip(entry.getDataPadCount()); - this.entryEOF = true; - if (this.entry.getFormat() == FORMAT_NEW_CRC - && this.crc != this.entry.getChksum()) { - throw new IOException("CRC Error. Occured at byte: " - + getBytesRead()); - } - return -1; // EOF for this entry - } - final int tmplength = (int) Math.min(len, this.entry.getSize() - - this.entryBytesRead); - if (tmplength < 0) { - return -1; - } - - final int tmpread = readFully(b, off, tmplength); - if (this.entry.getFormat() == FORMAT_NEW_CRC) { - for (int pos = 0; pos < tmpread; pos++) { - this.crc += b[pos] & 0xFF; - this.crc &= 0xFFFFFFFFL; - } - } - this.entryBytesRead += tmpread; - - return tmpread; - } - - private final int readFully(final byte[] b, final int off, final int len) - throws IOException { - final int count = IOUtils.readFully(in, b, off, len); - count(count); - if (count < len) { - throw new EOFException(); - } - return count; - } - - private long readBinaryLong(final int length, final boolean swapHalfWord) - throws IOException { - final byte tmp[] = new byte[length]; - readFully(tmp, 0, tmp.length); - return CpioUtil.byteArray2long(tmp, swapHalfWord); - } - - private long readAsciiLong(final int length, final int radix) - throws IOException { - final byte tmpBuffer[] = new byte[length]; - readFully(tmpBuffer, 0, tmpBuffer.length); - return Long.parseLong(ArchiveUtils.toAsciiString(tmpBuffer), radix); - } - - private CpioArchiveEntry readNewEntry(final boolean hasCrc) - throws IOException { - CpioArchiveEntry ret; - if (hasCrc) { - ret = new CpioArchiveEntry(FORMAT_NEW_CRC); - } else { - ret = new CpioArchiveEntry(FORMAT_NEW); - } - - ret.setInode(readAsciiLong(8, 16)); - final long mode = readAsciiLong(8, 16); - if (CpioUtil.fileType(mode) != 0){ // mode is initialised to 0 - ret.setMode(mode); - } - ret.setUID(readAsciiLong(8, 16)); - ret.setGID(readAsciiLong(8, 16)); - ret.setNumberOfLinks(readAsciiLong(8, 16)); - ret.setTime(readAsciiLong(8, 16)); - ret.setSize(readAsciiLong(8, 16)); - ret.setDeviceMaj(readAsciiLong(8, 16)); - ret.setDeviceMin(readAsciiLong(8, 16)); - ret.setRemoteDeviceMaj(readAsciiLong(8, 16)); - ret.setRemoteDeviceMin(readAsciiLong(8, 16)); - final long namesize = readAsciiLong(8, 16); - ret.setChksum(readAsciiLong(8, 16)); - final String name = readCString((int) namesize); - ret.setName(name); - if (CpioUtil.fileType(mode) == 0 && !name.equals(CPIO_TRAILER)){ - throw new IOException("Mode 0 only allowed in the trailer. Found entry name: " - + ArchiveUtils.sanitize(name) - + " Occured at byte: " + getBytesRead()); - } - skip(ret.getHeaderPadCount()); - - return ret; - } - - private CpioArchiveEntry readOldAsciiEntry() throws IOException { - final CpioArchiveEntry ret = new CpioArchiveEntry(FORMAT_OLD_ASCII); - - ret.setDevice(readAsciiLong(6, 8)); - ret.setInode(readAsciiLong(6, 8)); - final long mode = readAsciiLong(6, 8); - if (CpioUtil.fileType(mode) != 0) { - ret.setMode(mode); - } - ret.setUID(readAsciiLong(6, 8)); - ret.setGID(readAsciiLong(6, 8)); - ret.setNumberOfLinks(readAsciiLong(6, 8)); - ret.setRemoteDevice(readAsciiLong(6, 8)); - ret.setTime(readAsciiLong(11, 8)); - final long namesize = readAsciiLong(6, 8); - ret.setSize(readAsciiLong(11, 8)); - final String name = readCString((int) namesize); - ret.setName(name); - if (CpioUtil.fileType(mode) == 0 && !name.equals(CPIO_TRAILER)){ - throw new IOException("Mode 0 only allowed in the trailer. Found entry: " - + ArchiveUtils.sanitize(name) - + " Occured at byte: " + getBytesRead()); - } - - return ret; - } - - private CpioArchiveEntry readOldBinaryEntry(final boolean swapHalfWord) - throws IOException { - final CpioArchiveEntry ret = new CpioArchiveEntry(FORMAT_OLD_BINARY); - - ret.setDevice(readBinaryLong(2, swapHalfWord)); - ret.setInode(readBinaryLong(2, swapHalfWord)); - final long mode = readBinaryLong(2, swapHalfWord); - if (CpioUtil.fileType(mode) != 0){ - ret.setMode(mode); - } - ret.setUID(readBinaryLong(2, swapHalfWord)); - ret.setGID(readBinaryLong(2, swapHalfWord)); - ret.setNumberOfLinks(readBinaryLong(2, swapHalfWord)); - ret.setRemoteDevice(readBinaryLong(2, swapHalfWord)); - ret.setTime(readBinaryLong(4, swapHalfWord)); - final long namesize = readBinaryLong(2, swapHalfWord); - ret.setSize(readBinaryLong(4, swapHalfWord)); - final String name = readCString((int) namesize); - ret.setName(name); - if (CpioUtil.fileType(mode) == 0 && !name.equals(CPIO_TRAILER)){ - throw new IOException("Mode 0 only allowed in the trailer. Found entry: " - + ArchiveUtils.sanitize(name) - + "Occured at byte: " + getBytesRead()); - } - skip(ret.getHeaderPadCount()); - - return ret; - } - - private String readCString(final int length) throws IOException { - // don't include trailing NUL in file name to decode - final byte tmpBuffer[] = new byte[length - 1]; - readFully(tmpBuffer, 0, tmpBuffer.length); - this.in.read(); - return zipEncoding.decode(tmpBuffer); - } - - /** - * Skips specified number of bytes in the current CPIO entry. - * - * @param n - * the number of bytes to skip - * @return the actual number of bytes skipped - * @throws IOException - * if an I/O error has occurred - * @throws IllegalArgumentException - * if n < 0 - */ - @Override - public long skip(final long n) throws IOException { - if (n < 0) { - throw new IllegalArgumentException("negative skip length"); - } - ensureOpen(); - final int max = (int) Math.min(n, Integer.MAX_VALUE); - int total = 0; - - while (total < max) { - int len = max - total; - if (len > this.tmpbuf.length) { - len = this.tmpbuf.length; - } - len = read(this.tmpbuf, 0, len); - if (len == -1) { - this.entryEOF = true; - break; - } - total += len; - } - return total; - } - - @Override - public ArchiveEntry getNextEntry() throws IOException { - return getNextCPIOEntry(); - } - - /** - * Skips the padding zeros written after the TRAILER!!! entry. - */ - private void skipRemainderOfLastBlock() throws IOException { - final long readFromLastBlock = getBytesRead() % blockSize; - long remainingBytes = readFromLastBlock == 0 ? 0 - : blockSize - readFromLastBlock; - while (remainingBytes > 0) { - final long skipped = skip(blockSize - readFromLastBlock); - if (skipped <= 0) { - break; - } - remainingBytes -= skipped; - } - } - - /** - * Checks if the signature matches one of the following magic values: - * - * Strings: - * - * "070701" - MAGIC_NEW - * "070702" - MAGIC_NEW_CRC - * "070707" - MAGIC_OLD_ASCII - * - * Octal Binary value: - * - * 070707 - MAGIC_OLD_BINARY (held as a short) = 0x71C7 or 0xC771 - * @param signature data to match - * @param length length of data - * @return whether the buffer seems to contain CPIO data - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < 6) { - return false; - } - - // Check binary values - if (signature[0] == 0x71 && (signature[1] & 0xFF) == 0xc7) { - return true; - } - if (signature[1] == 0x71 && (signature[0] & 0xFF) == 0xc7) { - return true; - } - - // Check Ascii (String) values - // 3037 3037 30nn - if (signature[0] != 0x30) { - return false; - } - if (signature[1] != 0x37) { - return false; - } - if (signature[2] != 0x30) { - return false; - } - if (signature[3] != 0x37) { - return false; - } - if (signature[4] != 0x30) { - return false; - } - // Check last byte - if (signature[5] == 0x31) { - return true; - } - if (signature[5] == 0x32) { - return true; - } - if (signature[5] == 0x37) { - return true; - } - - return false; - } -} diff --git a/src/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java b/src/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java deleted file mode 100644 index ed8e2d04910..00000000000 --- a/src/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.cpio; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.util.HashMap; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; -import org.apache.commons.compress.utils.ArchiveUtils; -import org.apache.commons.compress.utils.CharsetNames; - -/** - * CpioArchiveOutputStream is a stream for writing CPIO streams. All formats of - * CPIO are supported (old ASCII, old binary, new portable format and the new - * portable format with CRC). - * - *

An entry can be written by creating an instance of CpioArchiveEntry and fill - * it with the necessary values and put it into the CPIO stream. Afterwards - * write the contents of the file into the CPIO stream. Either close the stream - * by calling finish() or put a next entry into the cpio stream.

- * - *
- * CpioArchiveOutputStream out = new CpioArchiveOutputStream(
- *         new FileOutputStream(new File("test.cpio")));
- * CpioArchiveEntry entry = new CpioArchiveEntry();
- * entry.setName("testfile");
- * String contents = "12345";
- * entry.setFileSize(contents.length());
- * entry.setMode(CpioConstants.C_ISREG); // regular file
- * ... set other attributes, e.g. time, number of links
- * out.putArchiveEntry(entry);
- * out.write(testContents.getBytes());
- * out.close();
- * 
- * - *

Note: This implementation should be compatible to cpio 2.5

- * - *

This class uses mutable fields and is not considered threadsafe.

- * - *

based on code from the jRPM project (jrpm.sourceforge.net)

- */ -public class CpioArchiveOutputStream extends ArchiveOutputStream implements - CpioConstants { - - private CpioArchiveEntry entry; - - private boolean closed = false; - - /** indicates if this archive is finished */ - private boolean finished; - - /** - * See {@link CpioArchiveEntry#setFormat(short)} for possible values. - */ - private final short entryFormat; - - private final HashMap names = - new HashMap<>(); - - private long crc = 0; - - private long written; - - private final OutputStream out; - - private final int blockSize; - - private long nextArtificalDeviceAndInode = 1; - - /** - * The encoding to use for filenames and labels. - */ - private final ZipEncoding zipEncoding; - - // the provided encoding (for unit tests) - final String encoding; - - /** - * Construct the cpio output stream with a specified format, a - * blocksize of {@link CpioConstants#BLOCK_SIZE BLOCK_SIZE} and - * using ASCII as the file name encoding. - * - * @param out - * The cpio stream - * @param format - * The format of the stream - */ - public CpioArchiveOutputStream(final OutputStream out, final short format) { - this(out, format, BLOCK_SIZE, CharsetNames.US_ASCII); - } - - /** - * Construct the cpio output stream with a specified format using - * ASCII as the file name encoding. - * - * @param out - * The cpio stream - * @param format - * The format of the stream - * @param blockSize - * The block size of the archive. - * - * @since 1.1 - */ - public CpioArchiveOutputStream(final OutputStream out, final short format, - final int blockSize) { - this(out, format, blockSize, CharsetNames.US_ASCII); - } - - /** - * Construct the cpio output stream with a specified format using - * ASCII as the file name encoding. - * - * @param out - * The cpio stream - * @param format - * The format of the stream - * @param blockSize - * The block size of the archive. - * @param encoding - * The encoding of file names to write - use null for - * the platform's default. - * - * @since 1.6 - */ - public CpioArchiveOutputStream(final OutputStream out, final short format, - final int blockSize, final String encoding) { - this.out = out; - switch (format) { - case FORMAT_NEW: - case FORMAT_NEW_CRC: - case FORMAT_OLD_ASCII: - case FORMAT_OLD_BINARY: - break; - default: - throw new IllegalArgumentException("Unknown format: "+format); - - } - this.entryFormat = format; - this.blockSize = blockSize; - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - } - - /** - * Construct the cpio output stream. The format for this CPIO stream is the - * "new" format using ASCII encoding for file names - * - * @param out - * The cpio stream - */ - public CpioArchiveOutputStream(final OutputStream out) { - this(out, FORMAT_NEW); - } - - /** - * Construct the cpio output stream. The format for this CPIO stream is the - * "new" format. - * - * @param out - * The cpio stream - * @param encoding - * The encoding of file names to write - use null for - * the platform's default. - * @since 1.6 - */ - public CpioArchiveOutputStream(final OutputStream out, final String encoding) { - this(out, FORMAT_NEW, BLOCK_SIZE, encoding); - } - - /** - * Check to make sure that this stream has not been closed - * - * @throws IOException - * if the stream is already closed - */ - private void ensureOpen() throws IOException { - if (this.closed) { - throw new IOException("Stream closed"); - } - } - - /** - * Begins writing a new CPIO file entry and positions the stream to the - * start of the entry data. Closes the current entry if still active. The - * current time will be used if the entry has no set modification time and - * the default header format will be used if no other format is specified in - * the entry. - * - * @param entry - * the CPIO cpioEntry to be written - * @throws IOException - * if an I/O error has occurred or if a CPIO file error has - * occurred - * @throws ClassCastException if entry is not an instance of CpioArchiveEntry - */ - @Override - public void putArchiveEntry(final ArchiveEntry entry) throws IOException { - if(finished) { - throw new IOException("Stream has already been finished"); - } - - final CpioArchiveEntry e = (CpioArchiveEntry) entry; - ensureOpen(); - if (this.entry != null) { - closeArchiveEntry(); // close previous entry - } - if (e.getTime() == -1) { - e.setTime(System.currentTimeMillis() / 1000); - } - - final short format = e.getFormat(); - if (format != this.entryFormat){ - throw new IOException("Header format: "+format+" does not match existing format: "+this.entryFormat); - } - - if (this.names.put(e.getName(), e) != null) { - throw new IOException("duplicate entry: " + e.getName()); - } - - writeHeader(e); - this.entry = e; - this.written = 0; - } - - private void writeHeader(final CpioArchiveEntry e) throws IOException { - switch (e.getFormat()) { - case FORMAT_NEW: - out.write(ArchiveUtils.toAsciiBytes(MAGIC_NEW)); - count(6); - writeNewEntry(e); - break; - case FORMAT_NEW_CRC: - out.write(ArchiveUtils.toAsciiBytes(MAGIC_NEW_CRC)); - count(6); - writeNewEntry(e); - break; - case FORMAT_OLD_ASCII: - out.write(ArchiveUtils.toAsciiBytes(MAGIC_OLD_ASCII)); - count(6); - writeOldAsciiEntry(e); - break; - case FORMAT_OLD_BINARY: - final boolean swapHalfWord = true; - writeBinaryLong(MAGIC_OLD_BINARY, 2, swapHalfWord); - writeOldBinaryEntry(e, swapHalfWord); - break; - default: - throw new IOException("unknown format " + e.getFormat()); - } - } - - private void writeNewEntry(final CpioArchiveEntry entry) throws IOException { - long inode = entry.getInode(); - long devMin = entry.getDeviceMin(); - if (CPIO_TRAILER.equals(entry.getName())) { - inode = devMin = 0; - } else { - if (inode == 0 && devMin == 0) { - inode = nextArtificalDeviceAndInode & 0xFFFFFFFF; - devMin = (nextArtificalDeviceAndInode++ >> 32) & 0xFFFFFFFF; - } else { - nextArtificalDeviceAndInode = - Math.max(nextArtificalDeviceAndInode, - inode + 0x100000000L * devMin) + 1; - } - } - - writeAsciiLong(inode, 8, 16); - writeAsciiLong(entry.getMode(), 8, 16); - writeAsciiLong(entry.getUID(), 8, 16); - writeAsciiLong(entry.getGID(), 8, 16); - writeAsciiLong(entry.getNumberOfLinks(), 8, 16); - writeAsciiLong(entry.getTime(), 8, 16); - writeAsciiLong(entry.getSize(), 8, 16); - writeAsciiLong(entry.getDeviceMaj(), 8, 16); - writeAsciiLong(devMin, 8, 16); - writeAsciiLong(entry.getRemoteDeviceMaj(), 8, 16); - writeAsciiLong(entry.getRemoteDeviceMin(), 8, 16); - writeAsciiLong(entry.getName().length() + 1L, 8, 16); - writeAsciiLong(entry.getChksum(), 8, 16); - writeCString(entry.getName()); - pad(entry.getHeaderPadCount()); - } - - private void writeOldAsciiEntry(final CpioArchiveEntry entry) - throws IOException { - long inode = entry.getInode(); - long device = entry.getDevice(); - if (CPIO_TRAILER.equals(entry.getName())) { - inode = device = 0; - } else { - if (inode == 0 && device == 0) { - inode = nextArtificalDeviceAndInode & 0777777; - device = (nextArtificalDeviceAndInode++ >> 18) & 0777777; - } else { - nextArtificalDeviceAndInode = - Math.max(nextArtificalDeviceAndInode, - inode + 01000000 * device) + 1; - } - } - - writeAsciiLong(device, 6, 8); - writeAsciiLong(inode, 6, 8); - writeAsciiLong(entry.getMode(), 6, 8); - writeAsciiLong(entry.getUID(), 6, 8); - writeAsciiLong(entry.getGID(), 6, 8); - writeAsciiLong(entry.getNumberOfLinks(), 6, 8); - writeAsciiLong(entry.getRemoteDevice(), 6, 8); - writeAsciiLong(entry.getTime(), 11, 8); - writeAsciiLong(entry.getName().length() + 1L, 6, 8); - writeAsciiLong(entry.getSize(), 11, 8); - writeCString(entry.getName()); - } - - private void writeOldBinaryEntry(final CpioArchiveEntry entry, - final boolean swapHalfWord) throws IOException { - long inode = entry.getInode(); - long device = entry.getDevice(); - if (CPIO_TRAILER.equals(entry.getName())) { - inode = device = 0; - } else { - if (inode == 0 && device == 0) { - inode = nextArtificalDeviceAndInode & 0xFFFF; - device = (nextArtificalDeviceAndInode++ >> 16) & 0xFFFF; - } else { - nextArtificalDeviceAndInode = - Math.max(nextArtificalDeviceAndInode, - inode + 0x10000 * device) + 1; - } - } - - writeBinaryLong(device, 2, swapHalfWord); - writeBinaryLong(inode, 2, swapHalfWord); - writeBinaryLong(entry.getMode(), 2, swapHalfWord); - writeBinaryLong(entry.getUID(), 2, swapHalfWord); - writeBinaryLong(entry.getGID(), 2, swapHalfWord); - writeBinaryLong(entry.getNumberOfLinks(), 2, swapHalfWord); - writeBinaryLong(entry.getRemoteDevice(), 2, swapHalfWord); - writeBinaryLong(entry.getTime(), 4, swapHalfWord); - writeBinaryLong(entry.getName().length() + 1L, 2, swapHalfWord); - writeBinaryLong(entry.getSize(), 4, swapHalfWord); - writeCString(entry.getName()); - pad(entry.getHeaderPadCount()); - } - - /*(non-Javadoc) - * - * @see - * org.apache.commons.compress.archivers.ArchiveOutputStream#closeArchiveEntry - * () - */ - @Override - public void closeArchiveEntry() throws IOException { - if(finished) { - throw new IOException("Stream has already been finished"); - } - - ensureOpen(); - - if (entry == null) { - throw new IOException("Trying to close non-existent entry"); - } - - if (this.entry.getSize() != this.written) { - throw new IOException("invalid entry size (expected " - + this.entry.getSize() + " but got " + this.written - + " bytes)"); - } - pad(this.entry.getDataPadCount()); - if (this.entry.getFormat() == FORMAT_NEW_CRC - && this.crc != this.entry.getChksum()) { - throw new IOException("CRC Error"); - } - this.entry = null; - this.crc = 0; - this.written = 0; - } - - /** - * Writes an array of bytes to the current CPIO entry data. This method will - * block until all the bytes are written. - * - * @param b - * the data to be written - * @param off - * the start offset in the data - * @param len - * the number of bytes that are written - * @throws IOException - * if an I/O error has occurred or if a CPIO file error has - * occurred - */ - @Override - public void write(final byte[] b, final int off, final int len) - throws IOException { - ensureOpen(); - if (off < 0 || len < 0 || off > b.length - len) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - - if (this.entry == null) { - throw new IOException("no current CPIO entry"); - } - if (this.written + len > this.entry.getSize()) { - throw new IOException("attempt to write past end of STORED entry"); - } - out.write(b, off, len); - this.written += len; - if (this.entry.getFormat() == FORMAT_NEW_CRC) { - for (int pos = 0; pos < len; pos++) { - this.crc += b[pos] & 0xFF; - this.crc &= 0xFFFFFFFFL; - } - } - count(len); - } - - /** - * Finishes writing the contents of the CPIO output stream without closing - * the underlying stream. Use this method when applying multiple filters in - * succession to the same output stream. - * - * @throws IOException - * if an I/O exception has occurred or if a CPIO file error has - * occurred - */ - @Override - public void finish() throws IOException { - ensureOpen(); - if (finished) { - throw new IOException("This archive has already been finished"); - } - - if (this.entry != null) { - throw new IOException("This archive contains unclosed entries."); - } - this.entry = new CpioArchiveEntry(this.entryFormat); - this.entry.setName(CPIO_TRAILER); - this.entry.setNumberOfLinks(1); - writeHeader(this.entry); - closeArchiveEntry(); - - final int lengthOfLastBlock = (int) (getBytesWritten() % blockSize); - if (lengthOfLastBlock != 0) { - pad(blockSize - lengthOfLastBlock); - } - - finished = true; - } - - /** - * Closes the CPIO output stream as well as the stream being filtered. - * - * @throws IOException - * if an I/O error has occurred or if a CPIO file error has - * occurred - */ - @Override - public void close() throws IOException { - if(!finished) { - finish(); - } - - if (!this.closed) { - out.close(); - this.closed = true; - } - } - - private void pad(final int count) throws IOException{ - if (count > 0){ - final byte buff[] = new byte[count]; - out.write(buff); - count(count); - } - } - - private void writeBinaryLong(final long number, final int length, - final boolean swapHalfWord) throws IOException { - final byte tmp[] = CpioUtil.long2byteArray(number, length, swapHalfWord); - out.write(tmp); - count(tmp.length); - } - - private void writeAsciiLong(final long number, final int length, - final int radix) throws IOException { - final StringBuilder tmp = new StringBuilder(); - String tmpStr; - if (radix == 16) { - tmp.append(Long.toHexString(number)); - } else if (radix == 8) { - tmp.append(Long.toOctalString(number)); - } else { - tmp.append(Long.toString(number)); - } - - if (tmp.length() <= length) { - final int insertLength = length - tmp.length(); - for (int pos = 0; pos < insertLength; pos++) { - tmp.insert(0, "0"); - } - tmpStr = tmp.toString(); - } else { - tmpStr = tmp.substring(tmp.length() - length); - } - final byte[] b = ArchiveUtils.toAsciiBytes(tmpStr); - out.write(b); - count(b.length); - } - - /** - * Writes an ASCII string to the stream followed by \0 - * @param str the String to write - * @throws IOException if the string couldn't be written - */ - private void writeCString(final String str) throws IOException { - final ByteBuffer buf = zipEncoding.encode(str); - final int len = buf.limit() - buf.position(); - out.write(buf.array(), buf.arrayOffset(), len); - out.write('\0'); - count(len + 1); - } - - /** - * Creates a new ArchiveEntry. The entryName must be an ASCII encoded string. - * - * @see org.apache.commons.compress.archivers.ArchiveOutputStream#createArchiveEntry(java.io.File, java.lang.String) - */ - @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) - throws IOException { - if(finished) { - throw new IOException("Stream has already been finished"); - } - return new CpioArchiveEntry(inputFile, entryName); - } - -} diff --git a/src/org/apache/commons/compress/archivers/cpio/CpioConstants.java b/src/org/apache/commons/compress/archivers/cpio/CpioConstants.java deleted file mode 100644 index efba28251ba..00000000000 --- a/src/org/apache/commons/compress/archivers/cpio/CpioConstants.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.cpio; - -/** - * All constants needed by CPIO. - * - * based on code from the jRPM project (jrpm.sourceforge.net) - * - */ -public interface CpioConstants { - /** magic number of a cpio entry in the new format */ - String MAGIC_NEW = "070701"; - - /** magic number of a cpio entry in the new format with crc */ - String MAGIC_NEW_CRC = "070702"; - - /** magic number of a cpio entry in the old ascii format */ - String MAGIC_OLD_ASCII = "070707"; - - /** magic number of a cpio entry in the old binary format */ - int MAGIC_OLD_BINARY = 070707; - - // These FORMAT_ constants are internal to the code - - /** write/read a CpioArchiveEntry in the new format */ - short FORMAT_NEW = 1; - - /** write/read a CpioArchiveEntry in the new format with crc */ - short FORMAT_NEW_CRC = 2; - - /** write/read a CpioArchiveEntry in the old ascii format */ - short FORMAT_OLD_ASCII = 4; - - /** write/read a CpioArchiveEntry in the old binary format */ - short FORMAT_OLD_BINARY = 8; - - /** Mask for both new formats */ - short FORMAT_NEW_MASK = 3; - - /** Mask for both old formats */ - short FORMAT_OLD_MASK = 12; - - /* - * Constants for the MODE bits - */ - - /** Mask for all file type bits. */ - int S_IFMT = 0170000; - - // http://www.opengroup.org/onlinepubs/9699919799/basedefs/cpio.h.html - // has a list of the C_xxx constatnts - - /** Defines a socket */ - int C_ISSOCK = 0140000; - - /** Defines a symbolic link */ - int C_ISLNK = 0120000; - - /** HP/UX network special (C_ISCTG) */ - int C_ISNWK = 0110000; - - /** Defines a regular file */ - int C_ISREG = 0100000; - - /** Defines a block device */ - int C_ISBLK = 0060000; - - /** Defines a directory */ - int C_ISDIR = 0040000; - - /** Defines a character device */ - int C_ISCHR = 0020000; - - /** Defines a pipe */ - int C_ISFIFO = 0010000; - - - /** Set user ID */ - int C_ISUID = 0004000; - - /** Set group ID */ - int C_ISGID = 0002000; - - /** On directories, restricted deletion flag. */ - int C_ISVTX = 0001000; - - - /** Permits the owner of a file to read the file */ - int C_IRUSR = 0000400; - - /** Permits the owner of a file to write to the file */ - int C_IWUSR = 0000200; - - /** Permits the owner of a file to execute the file or to search the directory */ - int C_IXUSR = 0000100; - - - /** Permits a file's group to read the file */ - int C_IRGRP = 0000040; - - /** Permits a file's group to write to the file */ - int C_IWGRP = 0000020; - - /** Permits a file's group to execute the file or to search the directory */ - int C_IXGRP = 0000010; - - - /** Permits others to read the file */ - int C_IROTH = 0000004; - - /** Permits others to write to the file */ - int C_IWOTH = 0000002; - - /** Permits others to execute the file or to search the directory */ - int C_IXOTH = 0000001; - - /** The special trailer marker */ - String CPIO_TRAILER = "TRAILER!!!"; - - /** - * The default block size. - * - * @since 1.1 - */ - int BLOCK_SIZE = 512; -} diff --git a/src/org/apache/commons/compress/archivers/cpio/CpioUtil.java b/src/org/apache/commons/compress/archivers/cpio/CpioUtil.java deleted file mode 100644 index f53ea4424d1..00000000000 --- a/src/org/apache/commons/compress/archivers/cpio/CpioUtil.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.cpio; - -/** - * Package private utility class for Cpio - * - * @Immutable - */ -class CpioUtil { - - /** - * Extracts the file type bits from a mode. - */ - static long fileType(final long mode) { - return mode & CpioConstants.S_IFMT; - } - - /** - * Converts a byte array to a long. Halfwords can be swapped by setting - * swapHalfWord=true. - * - * @param number - * An array of bytes containing a number - * @param swapHalfWord - * Swap halfwords ([0][1][2][3]->[1][0][3][2]) - * @return The long value - * @throws UnsupportedOperationException if number length is not a multiple of 2 - */ - static long byteArray2long(final byte[] number, final boolean swapHalfWord) { - if (number.length % 2 != 0) { - throw new UnsupportedOperationException(); - } - - long ret = 0; - int pos = 0; - final byte tmp_number[] = new byte[number.length]; - System.arraycopy(number, 0, tmp_number, 0, number.length); - - if (!swapHalfWord) { - byte tmp = 0; - for (pos = 0; pos < tmp_number.length; pos++) { - tmp = tmp_number[pos]; - tmp_number[pos++] = tmp_number[pos]; - tmp_number[pos] = tmp; - } - } - - ret = tmp_number[0] & 0xFF; - for (pos = 1; pos < tmp_number.length; pos++) { - ret <<= 8; - ret |= tmp_number[pos] & 0xFF; - } - return ret; - } - - /** - * Converts a long number to a byte array - * Halfwords can be swapped by setting swapHalfWord=true. - * - * @param number - * the input long number to be converted - * - * @param length - * The length of the returned array - * @param swapHalfWord - * Swap halfwords ([0][1][2][3]->[1][0][3][2]) - * @return The long value - * @throws UnsupportedOperationException if the length is not a positive multiple of two - */ - static byte[] long2byteArray(final long number, final int length, - final boolean swapHalfWord) { - final byte[] ret = new byte[length]; - int pos = 0; - long tmp_number = 0; - - if (length % 2 != 0 || length < 2) { - throw new UnsupportedOperationException(); - } - - tmp_number = number; - for (pos = length - 1; pos >= 0; pos--) { - ret[pos] = (byte) (tmp_number & 0xFF); - tmp_number >>= 8; - } - - if (!swapHalfWord) { - byte tmp = 0; - for (pos = 0; pos < length; pos++) { - tmp = ret[pos]; - ret[pos++] = ret[pos]; - ret[pos] = tmp; - } - } - - return ret; - } -} diff --git a/src/org/apache/commons/compress/archivers/cpio/package.html b/src/org/apache/commons/compress/archivers/cpio/package.html deleted file mode 100644 index 985828725ec..00000000000 --- a/src/org/apache/commons/compress/archivers/cpio/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides stream classes for reading and writing archives using - the CPIO format.

- - diff --git a/src/org/apache/commons/compress/archivers/dump/Dirent.java b/src/org/apache/commons/compress/archivers/dump/Dirent.java deleted file mode 100644 index b5af964a381..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/Dirent.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -/** - * Directory entry. - */ -class Dirent { - private final int ino; - private final int parentIno; - private final int type; - private final String name; - - /** - * Constructor - * - * @param ino - * @param parentIno - * @param type - * @param name - */ - Dirent(final int ino, final int parentIno, final int type, final String name) { - this.ino = ino; - this.parentIno = parentIno; - this.type = type; - this.name = name; - } - - /** - * Get ino. - * @return the i-node - */ - int getIno() { - return ino; - } - - /** - * Get ino of parent directory. - * @return the parent i-node - */ - int getParentIno() { - return parentIno; - } - - /** - * Get entry type. - * @return the entry type - */ - int getType() { - return type; - } - - /** - * Get name of directory entry. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return the directory name - */ - String getName() { - return name; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return String.format("[%d]: %s", ino, name); - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/DumpArchiveConstants.java b/src/org/apache/commons/compress/archivers/dump/DumpArchiveConstants.java deleted file mode 100644 index 2430f4aa2a6..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/DumpArchiveConstants.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -/** - * Various constants associated with dump archives. - */ -public final class DumpArchiveConstants { - public static final int TP_SIZE = 1024; - public static final int NTREC = 10; - public static final int HIGH_DENSITY_NTREC = 32; - public static final int OFS_MAGIC = 60011; - public static final int NFS_MAGIC = 60012; - public static final int FS_UFS2_MAGIC = 0x19540119; - public static final int CHECKSUM = 84446; - public static final int LBLSIZE = 16; - public static final int NAMELEN = 64; - - /* do not instantiate */ - private DumpArchiveConstants() { - } - - /** - * The type of tape segment. - */ - public enum SEGMENT_TYPE { - TAPE(1), - INODE(2), - BITS(3), - ADDR(4), - END(5), - CLRI(6); - - int code; - - SEGMENT_TYPE(final int code) { - this.code = code; - } - - public static SEGMENT_TYPE find(final int code) { - for (final SEGMENT_TYPE t : values()) { - if (t.code == code) { - return t; - } - } - - return null; - } - } - - /** - * The type of compression. - */ - public enum COMPRESSION_TYPE { - ZLIB(0), - BZLIB(1), - LZO(2); - - int code; - - COMPRESSION_TYPE(final int code) { - this.code = code; - } - - public static COMPRESSION_TYPE find(final int code) { - for (final COMPRESSION_TYPE t : values()) { - if (t.code == code) { - return t; - } - } - - return null; - } - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/DumpArchiveEntry.java b/src/org/apache/commons/compress/archivers/dump/DumpArchiveEntry.java deleted file mode 100644 index e284505f251..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/DumpArchiveEntry.java +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * This class represents an entry in a Dump archive. It consists - * of the entry's header, the entry's File and any extended attributes. - *

- * DumpEntries that are created from the header bytes read from - * an archive are instantiated with the DumpArchiveEntry( byte[] ) - * constructor. These entries will be used when extracting from - * or listing the contents of an archive. These entries have their - * header filled in using the header bytes. They also set the File - * to null, since they reference an archive entry not a file. - *

- * DumpEntries can also be constructed from nothing but a name. - * This allows the programmer to construct the entry by hand, for - * instance when only an InputStream is available for writing to - * the archive, and the header information is constructed from - * other information. In this case the header fields are set to - * defaults and the File is set to null. - * - *

- * The C structure for a Dump Entry's header is: - *

- * #define TP_BSIZE    1024          // size of each file block
- * #define NTREC       10            // number of blocks to write at once
- * #define HIGHDENSITYTREC 32        // number of blocks to write on high-density tapes
- * #define TP_NINDIR   (TP_BSIZE/2)  // number if indirect inodes in record
- * #define TP_NINOS    (TP_NINDIR / sizeof (int32_t))
- * #define LBLSIZE     16
- * #define NAMELEN     64
- *
- * #define OFS_MAGIC     (int)60011  // old format magic value
- * #define NFS_MAGIC     (int)60012  // new format magic value
- * #define FS_UFS2_MAGIC (int)0x19540119
- * #define CHECKSUM      (int)84446  // constant used in checksum algorithm
- *
- * struct  s_spcl {
- *   int32_t c_type;             // record type (see below)
- *   int32_t c_date;             // date of this dump
- *   int32_t c_ddate;            // date of previous dump
- *   int32_t c_volume;           // dump volume number
- *   u_int32_t c_tapea;          // logical block of this record
- *   dump_ino_t c_ino;           // number of inode
- *   int32_t c_magic;            // magic number (see above)
- *   int32_t c_checksum;         // record checksum
- * #ifdef  __linux__
- *   struct  new_bsd_inode c_dinode;
- * #else
- * #ifdef sunos
- *   struct  new_bsd_inode c_dinode;
- * #else
- *   struct  dinode  c_dinode;   // ownership and mode of inode
- * #endif
- * #endif
- *   int32_t c_count;            // number of valid c_addr entries
- *   union u_data c_data;        // see above
- *   char    c_label[LBLSIZE];   // dump label
- *   int32_t c_level;            // level of this dump
- *   char    c_filesys[NAMELEN]; // name of dumpped file system
- *   char    c_dev[NAMELEN];     // name of dumpped device
- *   char    c_host[NAMELEN];    // name of dumpped host
- *   int32_t c_flags;            // additional information (see below)
- *   int32_t c_firstrec;         // first record on volume
- *   int32_t c_ntrec;            // blocksize on volume
- *   int32_t c_extattributes;    // additional inode info (see below)
- *   int32_t c_spare[30];        // reserved for future uses
- * } s_spcl;
- *
- * //
- * // flag values
- * //
- * #define DR_NEWHEADER     0x0001  // new format tape header
- * #define DR_NEWINODEFMT   0x0002  // new format inodes on tape
- * #define DR_COMPRESSED    0x0080  // dump tape is compressed
- * #define DR_METAONLY      0x0100  // only the metadata of the inode has been dumped
- * #define DR_INODEINFO     0x0002  // [SIC] TS_END header contains c_inos information
- * #define DR_EXTATTRIBUTES 0x8000
- *
- * //
- * // extattributes inode info
- * //
- * #define EXT_REGULAR         0
- * #define EXT_MACOSFNDRINFO   1
- * #define EXT_MACOSRESFORK    2
- * #define EXT_XATTR           3
- *
- * // used for EA on tape
- * #define EXT2_GOOD_OLD_INODE_SIZE    128
- * #define EXT2_XATTR_MAGIC        0xEA020000  // block EA
- * #define EXT2_XATTR_MAGIC2       0xEA020001  // in inode EA
- * 
- *

- * The fields in bold are the same for all blocks. (This permitted - * multiple dumps to be written to a single tape.) - *

- * - *

- * The C structure for the inode (file) information is: - *

- * struct bsdtimeval {           //  **** alpha-*-linux is deviant
- *   __u32   tv_sec;
- *   __u32   tv_usec;
- * };
- *
- * #define NDADDR      12
- * #define NIADDR       3
- *
- * //
- * // This is the new (4.4) BSD inode structure
- * // copied from the FreeBSD 2.0 <ufs/ufs/dinode.h> include file
- * //
- * struct new_bsd_inode {
- *   __u16       di_mode;           // file type, standard Unix permissions
- *   __s16       di_nlink;          // number of hard links to file.
- *   union {
- *      __u16       oldids[2];
- *      __u32       inumber;
- *   }           di_u;
- *   u_quad_t    di_size;           // file size
- *   struct bsdtimeval   di_atime;  // time file was last accessed
- *   struct bsdtimeval   di_mtime;  // time file was last modified
- *   struct bsdtimeval   di_ctime;  // time file was created
- *   __u32       di_db[NDADDR];
- *   __u32       di_ib[NIADDR];
- *   __u32       di_flags;          //
- *   __s32       di_blocks;         // number of disk blocks
- *   __s32       di_gen;            // generation number
- *   __u32       di_uid;            // user id (see /etc/passwd)
- *   __u32       di_gid;            // group id (see /etc/group)
- *   __s32       di_spare[2];       // unused
- * };
- * 
- *

- * It is important to note that the header DOES NOT have the name of the - * file. It can't since hard links mean that you may have multiple filenames - * for a single physical file. You must read the contents of the directory - * entries to learn the mapping(s) from filename to inode. - *

- * - *

- * The C structure that indicates if a specific block is a real block - * that contains data or is a sparse block that is not persisted to the - * disk is:

- *
- * #define TP_BSIZE    1024
- * #define TP_NINDIR   (TP_BSIZE/2)
- *
- * union u_data {
- *   char    s_addrs[TP_NINDIR]; // 1 => data; 0 => hole in inode
- *   int32_t s_inos[TP_NINOS];   // table of first inode on each volume
- * } u_data;
- * 
- * - * @NotThreadSafe - */ -public class DumpArchiveEntry implements ArchiveEntry { - private String name; - private TYPE type = TYPE.UNKNOWN; - private int mode; - private Set permissions = Collections.emptySet(); - private long size; - private long atime; - private long mtime; - private int uid; - private int gid; - - /** - * Currently unused - */ - private final DumpArchiveSummary summary = null; - - // this information is available from standard index. - private final TapeSegmentHeader header = new TapeSegmentHeader(); - private String simpleName; - private String originalName; - - // this information is available from QFA index - private int volume; - private long offset; - private int ino; - private int nlink; - private long ctime; - private int generation; - private boolean isDeleted; - - /** - * Default constructor. - */ - public DumpArchiveEntry() { - } - - /** - * Constructor taking only filename. - * @param name pathname - * @param simpleName actual filename. - */ - public DumpArchiveEntry(final String name, final String simpleName) { - setName(name); - this.simpleName = simpleName; - } - - /** - * Constructor taking name, inode and type. - * - * @param name the name - * @param simpleName the simple name - * @param ino the ino - * @param type the type - */ - protected DumpArchiveEntry(final String name, final String simpleName, final int ino, - final TYPE type) { - setType(type); - setName(name); - this.simpleName = simpleName; - this.ino = ino; - this.offset = 0; - } - - /** - * Returns the path of the entry. - * @return the path of the entry. - */ - public String getSimpleName() { - return simpleName; - } - - /** - * Sets the path of the entry. - * @param simpleName the simple name - */ - protected void setSimpleName(final String simpleName) { - this.simpleName = simpleName; - } - - /** - * Returns the ino of the entry. - * @return the ino - */ - public int getIno() { - return header.getIno(); - } - - /** - * Return the number of hard links to the entry. - * @return the number of hard links - */ - public int getNlink() { - return nlink; - } - - /** - * Set the number of hard links. - * @param nlink the number of hard links - */ - public void setNlink(final int nlink) { - this.nlink = nlink; - } - - /** - * Get file creation time. - * @return the creation time - */ - public Date getCreationTime() { - return new Date(ctime); - } - - /** - * Set the file creation time. - * @param ctime the creation time - */ - public void setCreationTime(final Date ctime) { - this.ctime = ctime.getTime(); - } - - /** - * Return the generation of the file. - * @return the generation - */ - public int getGeneration() { - return generation; - } - - /** - * Set the generation of the file. - * @param generation the generation - */ - public void setGeneration(final int generation) { - this.generation = generation; - } - - /** - * Has this file been deleted? (On valid on incremental dumps.) - * @return whether the file has been deleted - */ - public boolean isDeleted() { - return isDeleted; - } - - /** - * Set whether this file has been deleted. - * @param isDeleted whether the file has been deleted - */ - public void setDeleted(final boolean isDeleted) { - this.isDeleted = isDeleted; - } - - /** - * Return the offset within the archive - * @return the offset - */ - public long getOffset() { - return offset; - } - - /** - * Set the offset within the archive. - * @param offset the offset - */ - public void setOffset(final long offset) { - this.offset = offset; - } - - /** - * Return the tape volume where this file is located. - * @return the volume - */ - public int getVolume() { - return volume; - } - - /** - * Set the tape volume. - * @param volume the volume - */ - public void setVolume(final int volume) { - this.volume = volume; - } - - /** - * Return the type of the tape segment header. - * @return the segment header - */ - public DumpArchiveConstants.SEGMENT_TYPE getHeaderType() { - return header.getType(); - } - - /** - * Return the number of records in this segment. - * @return the number of records - */ - public int getHeaderCount() { - return header.getCount(); - } - - /** - * Return the number of sparse records in this segment. - * @return the number of sparse records - */ - public int getHeaderHoles() { - return header.getHoles(); - } - - /** - * Is this a sparse record? - * @param idx index of the record to check - * @return whether this is a sparse record - */ - public boolean isSparseRecord(final int idx) { - return (header.getCdata(idx) & 0x01) == 0; - } - - @Override - public int hashCode() { - return ino; - } - - @Override - public boolean equals(final Object o) { - if (o == this) { - return true; - } else if (o == null || !o.getClass().equals(getClass())) { - return false; - } - - final DumpArchiveEntry rhs = (DumpArchiveEntry) o; - - if (rhs.header == null) { - return false; - } - - if (ino != rhs.ino) { - return false; - } - - // summary is always null right now, but this may change some day - if ((summary == null && rhs.summary != null) // NOSONAR - || (summary != null && !summary.equals(rhs.summary))) { // NOSONAR - return false; - } - - return true; - } - - @Override - public String toString() { - return getName(); - } - - /** - * Populate the dump archive entry and tape segment header with - * the contents of the buffer. - * - * @param buffer buffer to read content from - */ - static DumpArchiveEntry parse(final byte[] buffer) { - final DumpArchiveEntry entry = new DumpArchiveEntry(); - final TapeSegmentHeader header = entry.header; - - header.type = DumpArchiveConstants.SEGMENT_TYPE.find(DumpArchiveUtil.convert32( - buffer, 0)); - - //header.dumpDate = new Date(1000L * DumpArchiveUtil.convert32(buffer, 4)); - //header.previousDumpDate = new Date(1000L * DumpArchiveUtil.convert32( - // buffer, 8)); - header.volume = DumpArchiveUtil.convert32(buffer, 12); - //header.tapea = DumpArchiveUtil.convert32(buffer, 16); - entry.ino = header.ino = DumpArchiveUtil.convert32(buffer, 20); - - //header.magic = DumpArchiveUtil.convert32(buffer, 24); - //header.checksum = DumpArchiveUtil.convert32(buffer, 28); - final int m = DumpArchiveUtil.convert16(buffer, 32); - - // determine the type of the file. - entry.setType(TYPE.find((m >> 12) & 0x0F)); - - // determine the standard permissions - entry.setMode(m); - - entry.nlink = DumpArchiveUtil.convert16(buffer, 34); - // inumber, oldids? - entry.setSize(DumpArchiveUtil.convert64(buffer, 40)); - - long t = (1000L * DumpArchiveUtil.convert32(buffer, 48)) + - (DumpArchiveUtil.convert32(buffer, 52) / 1000); - entry.setAccessTime(new Date(t)); - t = (1000L * DumpArchiveUtil.convert32(buffer, 56)) + - (DumpArchiveUtil.convert32(buffer, 60) / 1000); - entry.setLastModifiedDate(new Date(t)); - t = (1000L * DumpArchiveUtil.convert32(buffer, 64)) + - (DumpArchiveUtil.convert32(buffer, 68) / 1000); - entry.ctime = t; - - // db: 72-119 - direct blocks - // id: 120-131 - indirect blocks - //entry.flags = DumpArchiveUtil.convert32(buffer, 132); - //entry.blocks = DumpArchiveUtil.convert32(buffer, 136); - entry.generation = DumpArchiveUtil.convert32(buffer, 140); - entry.setUserId(DumpArchiveUtil.convert32(buffer, 144)); - entry.setGroupId(DumpArchiveUtil.convert32(buffer, 148)); - // two 32-bit spare values. - header.count = DumpArchiveUtil.convert32(buffer, 160); - - header.holes = 0; - - for (int i = 0; (i < 512) && (i < header.count); i++) { - if (buffer[164 + i] == 0) { - header.holes++; - } - } - - System.arraycopy(buffer, 164, header.cdata, 0, 512); - - entry.volume = header.getVolume(); - - //entry.isSummaryOnly = false; - return entry; - } - - /** - * Update entry with information from next tape segment header. - */ - void update(final byte[] buffer) { - header.volume = DumpArchiveUtil.convert32(buffer, 16); - header.count = DumpArchiveUtil.convert32(buffer, 160); - - header.holes = 0; - - for (int i = 0; (i < 512) && (i < header.count); i++) { - if (buffer[164 + i] == 0) { - header.holes++; - } - } - - System.arraycopy(buffer, 164, header.cdata, 0, 512); - } - - /** - * Archive entry as stored on tape. There is one TSH for (at most) - * every 512k in the file. - */ - static class TapeSegmentHeader { - private DumpArchiveConstants.SEGMENT_TYPE type; - private int volume; - private int ino; - private int count; - private int holes; - private final byte[] cdata = new byte[512]; // map of any 'holes' - - public DumpArchiveConstants.SEGMENT_TYPE getType() { - return type; - } - - public int getVolume() { - return volume; - } - - public int getIno() { - return ino; - } - - void setIno(final int ino) { - this.ino = ino; - } - - public int getCount() { - return count; - } - - public int getHoles() { - return holes; - } - - public int getCdata(final int idx) { - return cdata[idx]; - } - } - - /** - * Returns the name of the entry. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return the name of the entry. - */ - @Override - public String getName() { - return name; - } - - /** - * Returns the unmodified name of the entry. - * @return the name of the entry. - */ - String getOriginalName() { - return originalName; - } - - /** - * Sets the name of the entry. - * @param name the name - */ - public final void setName(String name) { - this.originalName = name; - if (name != null) { - if (isDirectory() && !name.endsWith("/")) { - name += "/"; - } - if (name.startsWith("./")) { - name = name.substring(2); - } - } - this.name = name; - } - - /** - * The last modified date. - * @return the last modified date - */ - @Override - public Date getLastModifiedDate() { - return new Date(mtime); - } - - /** - * Is this a directory? - * @return whether this is a directory - */ - @Override - public boolean isDirectory() { - return type == TYPE.DIRECTORY; - } - - /** - * Is this a regular file? - * @return whether this is a regular file - */ - public boolean isFile() { - return type == TYPE.FILE; - } - - /** - * Is this a network device? - * @return whether this is a socket - */ - public boolean isSocket() { - return type == TYPE.SOCKET; - } - - /** - * Is this a character device? - * @return whether this is a character device - */ - public boolean isChrDev() { - return type == TYPE.CHRDEV; - } - - /** - * Is this a block device? - * @return whether this is a block device - */ - public boolean isBlkDev() { - return type == TYPE.BLKDEV; - } - - /** - * Is this a fifo/pipe? - * @return whether this is a fifo - */ - public boolean isFifo() { - return type == TYPE.FIFO; - } - - /** - * Get the type of the entry. - * @return the type - */ - public TYPE getType() { - return type; - } - - /** - * Set the type of the entry. - * @param type the type - */ - public void setType(final TYPE type) { - this.type = type; - } - - /** - * Return the access permissions on the entry. - * @return the access permissions - */ - public int getMode() { - return mode; - } - - /** - * Set the access permissions on the entry. - * @param mode the access permissions - */ - public void setMode(final int mode) { - this.mode = mode & 07777; - this.permissions = PERMISSION.find(mode); - } - - /** - * Returns the permissions on the entry. - * @return the permissions - */ - public Set getPermissions() { - return permissions; - } - - /** - * Returns the size of the entry. - * @return the size - */ - @Override - public long getSize() { - return isDirectory() ? SIZE_UNKNOWN : size; - } - - /** - * Returns the size of the entry as read from the archive. - */ - long getEntrySize() { - return size; - } - - /** - * Set the size of the entry. - * @param size the size - */ - public void setSize(final long size) { - this.size = size; - } - - /** - * Set the time the file was last modified. - * @param mtime the last modified time - */ - public void setLastModifiedDate(final Date mtime) { - this.mtime = mtime.getTime(); - } - - /** - * Returns the time the file was last accessed. - * @return the access time - */ - public Date getAccessTime() { - return new Date(atime); - } - - /** - * Set the time the file was last accessed. - * @param atime the access time - */ - public void setAccessTime(final Date atime) { - this.atime = atime.getTime(); - } - - /** - * Return the user id. - * @return the user id - */ - public int getUserId() { - return uid; - } - - /** - * Set the user id. - * @param uid the user id - */ - public void setUserId(final int uid) { - this.uid = uid; - } - - /** - * Return the group id - * @return the group id - */ - public int getGroupId() { - return gid; - } - - /** - * Set the group id. - * @param gid the group id - */ - public void setGroupId(final int gid) { - this.gid = gid; - } - - public enum TYPE { - WHITEOUT(14), - SOCKET(12), - LINK(10), - FILE(8), - BLKDEV(6), - DIRECTORY(4), - CHRDEV(2), - FIFO(1), - UNKNOWN(15); - - private int code; - - TYPE(final int code) { - this.code = code; - } - - public static TYPE find(final int code) { - TYPE type = UNKNOWN; - - for (final TYPE t : TYPE.values()) { - if (code == t.code) { - type = t; - } - } - - return type; - } - } - - public enum PERMISSION { - SETUID(04000), - SETGUI(02000), - STICKY(01000), - USER_READ(00400), - USER_WRITE(00200), - USER_EXEC(00100), - GROUP_READ(00040), - GROUP_WRITE(00020), - GROUP_EXEC(00010), - WORLD_READ(00004), - WORLD_WRITE(00002), - WORLD_EXEC(00001); - - private int code; - - PERMISSION(final int code) { - this.code = code; - } - - public static Set find(final int code) { - final Set set = new HashSet<>(); - - for (final PERMISSION p : PERMISSION.values()) { - if ((code & p.code) == p.code) { - set.add(p); - } - } - - if (set.isEmpty()) { - return Collections.emptySet(); - } - - return EnumSet.copyOf(set); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/DumpArchiveException.java b/src/org/apache/commons/compress/archivers/dump/DumpArchiveException.java deleted file mode 100644 index 635b1d9fbf0..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/DumpArchiveException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -import java.io.IOException; - - -/** - * Dump Archive Exception - */ -public class DumpArchiveException extends IOException { - private static final long serialVersionUID = 1L; - - public DumpArchiveException() { - } - - public DumpArchiveException(final String msg) { - super(msg); - } - - public DumpArchiveException(final Throwable cause) { - initCause(cause); - } - - public DumpArchiveException(final String msg, final Throwable cause) { - super(msg); - initCause(cause); - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/DumpArchiveInputStream.java b/src/org/apache/commons/compress/archivers/dump/DumpArchiveInputStream.java deleted file mode 100644 index ed4f02fa085..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/DumpArchiveInputStream.java +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.Queue; -import java.util.Stack; - -/** - * The DumpArchiveInputStream reads a UNIX dump archive as an InputStream. - * Methods are provided to position at each successive entry in - * the archive, and the read each entry as a normal input stream - * using read(). - * - * There doesn't seem to exist a hint on the encoding of string values - * in any piece documentation. Given the main purpose of dump/restore - * is backing up a system it seems very likely the format uses the - * current default encoding of the system. - * - * @NotThreadSafe - */ -public class DumpArchiveInputStream extends ArchiveInputStream { - private DumpArchiveSummary summary; - private DumpArchiveEntry active; - private boolean isClosed; - private boolean hasHitEOF; - private long entrySize; - private long entryOffset; - private int readIdx; - private final byte[] readBuf = new byte[DumpArchiveConstants.TP_SIZE]; - private byte[] blockBuffer; - private int recordOffset; - private long filepos; - protected TapeInputStream raw; - - // map of ino -> dirent entry. We can use this to reconstruct full paths. - private final Map names = new HashMap<>(); - - // map of ino -> (directory) entry when we're missing one or more elements in the path. - private final Map pending = new HashMap<>(); - - // queue of (directory) entries where we now have the full path. - private Queue queue; - - /** - * The encoding to use for filenames and labels. - */ - private final ZipEncoding zipEncoding; - - // the provided encoding (for unit tests) - final String encoding; - - /** - * Constructor using the platform's default encoding for file - * names. - * - * @param is stream to read from - * @throws ArchiveException on error - */ - public DumpArchiveInputStream(final InputStream is) throws ArchiveException { - this(is, null); - } - - /** - * Constructor. - * - * @param is stream to read from - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @since 1.6 - * @throws ArchiveException on error - */ - public DumpArchiveInputStream(final InputStream is, final String encoding) - throws ArchiveException { - this.raw = new TapeInputStream(is); - this.hasHitEOF = false; - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - - try { - // read header, verify it's a dump archive. - final byte[] headerBytes = raw.readRecord(); - - if (!DumpArchiveUtil.verify(headerBytes)) { - throw new UnrecognizedFormatException(); - } - - // get summary information - summary = new DumpArchiveSummary(headerBytes, this.zipEncoding); - - // reset buffer with actual block size. - raw.resetBlockSize(summary.getNTRec(), summary.isCompressed()); - - // allocate our read buffer. - blockBuffer = new byte[4 * DumpArchiveConstants.TP_SIZE]; - - // skip past CLRI and BITS segments since we don't handle them yet. - readCLRI(); - readBITS(); - } catch (final IOException ex) { - throw new ArchiveException(ex.getMessage(), ex); - } - - // put in a dummy record for the root node. - final Dirent root = new Dirent(2, 2, 4, "."); - names.put(2, root); - - // use priority based on queue to ensure parent directories are - // released first. - queue = new PriorityQueue<>(10, - new Comparator() { - @Override - public int compare(final DumpArchiveEntry p, final DumpArchiveEntry q) { - if (p.getOriginalName() == null || q.getOriginalName() == null) { - return Integer.MAX_VALUE; - } - - return p.getOriginalName().compareTo(q.getOriginalName()); - } - }); - } - - @Deprecated - @Override - public int getCount() { - return (int) getBytesRead(); - } - - @Override - public long getBytesRead() { - return raw.getBytesRead(); - } - - /** - * Return the archive summary information. - * @return the summary - */ - public DumpArchiveSummary getSummary() { - return summary; - } - - /** - * Read CLRI (deleted inode) segment. - */ - private void readCLRI() throws IOException { - final byte[] buffer = raw.readRecord(); - - if (!DumpArchiveUtil.verify(buffer)) { - throw new InvalidFormatException(); - } - - active = DumpArchiveEntry.parse(buffer); - - if (DumpArchiveConstants.SEGMENT_TYPE.CLRI != active.getHeaderType()) { - throw new InvalidFormatException(); - } - - // we don't do anything with this yet. - if (raw.skip((long) DumpArchiveConstants.TP_SIZE * active.getHeaderCount()) - == -1) { - throw new EOFException(); - } - readIdx = active.getHeaderCount(); - } - - /** - * Read BITS segment. - */ - private void readBITS() throws IOException { - final byte[] buffer = raw.readRecord(); - - if (!DumpArchiveUtil.verify(buffer)) { - throw new InvalidFormatException(); - } - - active = DumpArchiveEntry.parse(buffer); - - if (DumpArchiveConstants.SEGMENT_TYPE.BITS != active.getHeaderType()) { - throw new InvalidFormatException(); - } - - // we don't do anything with this yet. - if (raw.skip((long) DumpArchiveConstants.TP_SIZE * active.getHeaderCount()) - == -1) { - throw new EOFException(); - } - readIdx = active.getHeaderCount(); - } - - /** - * Read the next entry. - * @return the next entry - * @throws IOException on error - */ - public DumpArchiveEntry getNextDumpEntry() throws IOException { - return getNextEntry(); - } - - @Override - public DumpArchiveEntry getNextEntry() throws IOException { - DumpArchiveEntry entry = null; - String path = null; - - // is there anything in the queue? - if (!queue.isEmpty()) { - return queue.remove(); - } - - while (entry == null) { - if (hasHitEOF) { - return null; - } - - // skip any remaining records in this segment for prior file. - // we might still have holes... easiest to do it - // block by block. We may want to revisit this if - // the unnecessary decompression time adds up. - while (readIdx < active.getHeaderCount()) { - if (!active.isSparseRecord(readIdx++) - && raw.skip(DumpArchiveConstants.TP_SIZE) == -1) { - throw new EOFException(); - } - } - - readIdx = 0; - filepos = raw.getBytesRead(); - - byte[] headerBytes = raw.readRecord(); - - if (!DumpArchiveUtil.verify(headerBytes)) { - throw new InvalidFormatException(); - } - - active = DumpArchiveEntry.parse(headerBytes); - - // skip any remaining segments for prior file. - while (DumpArchiveConstants.SEGMENT_TYPE.ADDR == active.getHeaderType()) { - if (raw.skip((long) DumpArchiveConstants.TP_SIZE - * (active.getHeaderCount() - - active.getHeaderHoles())) == -1) { - throw new EOFException(); - } - - filepos = raw.getBytesRead(); - headerBytes = raw.readRecord(); - - if (!DumpArchiveUtil.verify(headerBytes)) { - throw new InvalidFormatException(); - } - - active = DumpArchiveEntry.parse(headerBytes); - } - - // check if this is an end-of-volume marker. - if (DumpArchiveConstants.SEGMENT_TYPE.END == active.getHeaderType()) { - hasHitEOF = true; - - return null; - } - - entry = active; - - if (entry.isDirectory()) { - readDirectoryEntry(active); - - // now we create an empty InputStream. - entryOffset = 0; - entrySize = 0; - readIdx = active.getHeaderCount(); - } else { - entryOffset = 0; - entrySize = active.getEntrySize(); - readIdx = 0; - } - - recordOffset = readBuf.length; - - path = getPath(entry); - - if (path == null) { - entry = null; - } - } - - entry.setName(path); - entry.setSimpleName(names.get(entry.getIno()).getName()); - entry.setOffset(filepos); - - return entry; - } - - /** - * Read directory entry. - */ - private void readDirectoryEntry(DumpArchiveEntry entry) - throws IOException { - long size = entry.getEntrySize(); - boolean first = true; - - while (first || - DumpArchiveConstants.SEGMENT_TYPE.ADDR == entry.getHeaderType()) { - // read the header that we just peeked at. - if (!first) { - raw.readRecord(); - } - - if (!names.containsKey(entry.getIno()) && - DumpArchiveConstants.SEGMENT_TYPE.INODE == entry.getHeaderType()) { - pending.put(entry.getIno(), entry); - } - - final int datalen = DumpArchiveConstants.TP_SIZE * entry.getHeaderCount(); - - if (blockBuffer.length < datalen) { - blockBuffer = new byte[datalen]; - } - - if (raw.read(blockBuffer, 0, datalen) != datalen) { - throw new EOFException(); - } - - int reclen = 0; - - for (int i = 0; i < datalen - 8 && i < size - 8; - i += reclen) { - final int ino = DumpArchiveUtil.convert32(blockBuffer, i); - reclen = DumpArchiveUtil.convert16(blockBuffer, i + 4); - - final byte type = blockBuffer[i + 6]; - - final String name = DumpArchiveUtil.decode(zipEncoding, blockBuffer, i + 8, blockBuffer[i + 7]); - - if (".".equals(name) || "..".equals(name)) { - // do nothing... - continue; - } - - final Dirent d = new Dirent(ino, entry.getIno(), type, name); - - /* - if ((type == 4) && names.containsKey(ino)) { - System.out.println("we already have ino: " + - names.get(ino)); - } - */ - - names.put(ino, d); - - // check whether this allows us to fill anything in the pending list. - for (final Map.Entry e : pending.entrySet()) { - final String path = getPath(e.getValue()); - - if (path != null) { - e.getValue().setName(path); - e.getValue() - .setSimpleName(names.get(e.getKey()).getName()); - queue.add(e.getValue()); - } - } - - // remove anything that we found. (We can't do it earlier - // because of concurrent modification exceptions.) - for (final DumpArchiveEntry e : queue) { - pending.remove(e.getIno()); - } - } - - final byte[] peekBytes = raw.peek(); - - if (!DumpArchiveUtil.verify(peekBytes)) { - throw new InvalidFormatException(); - } - - entry = DumpArchiveEntry.parse(peekBytes); - first = false; - size -= DumpArchiveConstants.TP_SIZE; - } - } - - /** - * Get full path for specified archive entry, or null if there's a gap. - * - * @param entry - * @return full path for specified archive entry, or null if there's a gap. - */ - private String getPath(final DumpArchiveEntry entry) { - // build the stack of elements. It's possible that we're - // still missing an intermediate value and if so we - final Stack elements = new Stack<>(); - Dirent dirent = null; - - for (int i = entry.getIno();; i = dirent.getParentIno()) { - if (!names.containsKey(i)) { - elements.clear(); - break; - } - - dirent = names.get(i); - elements.push(dirent.getName()); - - if (dirent.getIno() == dirent.getParentIno()) { - break; - } - } - - // if an element is missing defer the work and read next entry. - if (elements.isEmpty()) { - pending.put(entry.getIno(), entry); - - return null; - } - - // generate full path from stack of elements. - final StringBuilder sb = new StringBuilder(elements.pop()); - - while (!elements.isEmpty()) { - sb.append('/'); - sb.append(elements.pop()); - } - - return sb.toString(); - } - - /** - * Reads bytes from the current dump archive entry. - * - * This method is aware of the boundaries of the current - * entry in the archive and will deal with them as if they - * were this stream's start and EOF. - * - * @param buf The buffer into which to place bytes read. - * @param off The offset at which to place bytes read. - * @param len The number of bytes to read. - * @return The number of bytes read, or -1 at EOF. - * @throws IOException on error - */ - @Override - public int read(final byte[] buf, int off, int len) throws IOException { - int totalRead = 0; - - if (hasHitEOF || isClosed || entryOffset >= entrySize) { - return -1; - } - - if (active == null) { - throw new IllegalStateException("No current dump entry"); - } - - if (len + entryOffset > entrySize) { - len = (int) (entrySize - entryOffset); - } - - while (len > 0) { - final int sz = len > readBuf.length - recordOffset - ? readBuf.length - recordOffset : len; - - // copy any data we have - if (recordOffset + sz <= readBuf.length) { - System.arraycopy(readBuf, recordOffset, buf, off, sz); - totalRead += sz; - recordOffset += sz; - len -= sz; - off += sz; - } - - // load next block if necessary. - if (len > 0) { - if (readIdx >= 512) { - final byte[] headerBytes = raw.readRecord(); - - if (!DumpArchiveUtil.verify(headerBytes)) { - throw new InvalidFormatException(); - } - - active = DumpArchiveEntry.parse(headerBytes); - readIdx = 0; - } - - if (!active.isSparseRecord(readIdx++)) { - final int r = raw.read(readBuf, 0, readBuf.length); - if (r != readBuf.length) { - throw new EOFException(); - } - } else { - Arrays.fill(readBuf, (byte) 0); - } - - recordOffset = 0; - } - } - - entryOffset += totalRead; - - return totalRead; - } - - /** - * Closes the stream for this entry. - */ - @Override - public void close() throws IOException { - if (!isClosed) { - isClosed = true; - raw.close(); - } - } - - /** - * Look at the first few bytes of the file to decide if it's a dump - * archive. With 32 bytes we can look at the magic value, with a full - * 1k we can verify the checksum. - * @param buffer data to match - * @param length length of data - * @return whether the buffer seems to contain dump data - */ - public static boolean matches(final byte[] buffer, final int length) { - // do we have enough of the header? - if (length < 32) { - return false; - } - - // this is the best test - if (length >= DumpArchiveConstants.TP_SIZE) { - return DumpArchiveUtil.verify(buffer); - } - - // this will work in a pinch. - return DumpArchiveConstants.NFS_MAGIC == DumpArchiveUtil.convert32(buffer, - 24); - } - -} diff --git a/src/org/apache/commons/compress/archivers/dump/DumpArchiveSummary.java b/src/org/apache/commons/compress/archivers/dump/DumpArchiveSummary.java deleted file mode 100644 index f17e70f13ec..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/DumpArchiveSummary.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -import java.io.IOException; -import java.util.Date; - -import org.apache.commons.compress.archivers.zip.ZipEncoding; - -/** - * This class represents identifying information about a Dump archive volume. - * It consists the archive's dump date, label, hostname, device name and possibly - * last mount point plus the volume's volume id andfirst record number. - * - * For the corresponding C structure see the header of {@link DumpArchiveEntry}. - */ -public class DumpArchiveSummary { - private long dumpDate; - private long previousDumpDate; - private int volume; - private String label; - private int level; - private String filesys; - private String devname; - private String hostname; - private int flags; - private int firstrec; - private int ntrec; - - DumpArchiveSummary(final byte[] buffer, final ZipEncoding encoding) throws IOException { - dumpDate = 1000L * DumpArchiveUtil.convert32(buffer, 4); - previousDumpDate = 1000L * DumpArchiveUtil.convert32(buffer, 8); - volume = DumpArchiveUtil.convert32(buffer, 12); - label = DumpArchiveUtil.decode(encoding, buffer, 676, DumpArchiveConstants.LBLSIZE).trim(); - level = DumpArchiveUtil.convert32(buffer, 692); - filesys = DumpArchiveUtil.decode(encoding, buffer, 696, DumpArchiveConstants.NAMELEN).trim(); - devname = DumpArchiveUtil.decode(encoding, buffer, 760, DumpArchiveConstants.NAMELEN).trim(); - hostname = DumpArchiveUtil.decode(encoding, buffer, 824, DumpArchiveConstants.NAMELEN).trim(); - flags = DumpArchiveUtil.convert32(buffer, 888); - firstrec = DumpArchiveUtil.convert32(buffer, 892); - ntrec = DumpArchiveUtil.convert32(buffer, 896); - - //extAttributes = DumpArchiveUtil.convert32(buffer, 900); - } - - /** - * Get the date of this dump. - * @return the date of this dump. - */ - public Date getDumpDate() { - return new Date(dumpDate); - } - - /** - * Set dump date. - * @param dumpDate the dump date - */ - public void setDumpDate(final Date dumpDate) { - this.dumpDate = dumpDate.getTime(); - } - - /** - * Get the date of the previous dump at this level higher. - * @return dumpdate may be null - */ - public Date getPreviousDumpDate() { - return new Date(previousDumpDate); - } - - /** - * Set previous dump date. - * @param previousDumpDate the previous dump dat - */ - public void setPreviousDumpDate(final Date previousDumpDate) { - this.previousDumpDate = previousDumpDate.getTime(); - } - - /** - * Get volume (tape) number. - * @return volume (tape) number. - */ - public int getVolume() { - return volume; - } - - /** - * Set volume (tape) number. - * @param volume the volume number - */ - public void setVolume(final int volume) { - this.volume = volume; - } - - /** - * Get the level of this dump. This is a number between 0 and 9, inclusive, - * and a level 0 dump is a complete dump of the partition. For any other dump - * 'n' this dump contains all files that have changed since the last dump - * at this level or lower. This is used to support different levels of - * incremental backups. - * @return dump level - */ - public int getLevel() { - return level; - } - - /** - * Set level. - * @param level the level - */ - public void setLevel(final int level) { - this.level = level; - } - - /** - * Get dump label. This may be autogenerated or it may be specified - * bu the user. - * @return dump label - */ - public String getLabel() { - return label; - } - - /** - * Set dump label. - * @param label the label - */ - public void setLabel(final String label) { - this.label = label; - } - - /** - * Get the last mountpoint, e.g., /home. - * @return last mountpoint - */ - public String getFilesystem() { - return filesys; - } - - /** - * Set the last mountpoint. - * @param filesystem the last mountpoint - */ - public void setFilesystem(final String filesystem) { - this.filesys = filesystem; - } - - /** - * Get the device name, e.g., /dev/sda3 or /dev/mapper/vg0-home. - * @return device name - */ - public String getDevname() { - return devname; - } - - /** - * Set the device name. - * @param devname the device name - */ - public void setDevname(final String devname) { - this.devname = devname; - } - - /** - * Get the hostname of the system where the dump was performed. - * @return hostname the host name - */ - public String getHostname() { - return hostname; - } - - /** - * Set the hostname. - * @param hostname the host name - */ - public void setHostname(final String hostname) { - this.hostname = hostname; - } - - /** - * Get the miscellaneous flags. See below. - * @return flags - */ - public int getFlags() { - return flags; - } - - /** - * Set the miscellaneous flags. - * @param flags flags - */ - public void setFlags(final int flags) { - this.flags = flags; - } - - /** - * Get the inode of the first record on this volume. - * @return inode of the first record on this volume. - */ - public int getFirstRecord() { - return firstrec; - } - - /** - * Set the inode of the first record. - * @param firstrec the first record - */ - public void setFirstRecord(final int firstrec) { - this.firstrec = firstrec; - } - - /** - * Get the number of records per tape block. This is typically - * between 10 and 32. - * @return the number of records per tape block - */ - public int getNTRec() { - return ntrec; - } - - /** - * Set the number of records per tape block. - * @param ntrec the number of records per tape block - */ - public void setNTRec(final int ntrec) { - this.ntrec = ntrec; - } - - /** - * Is this the new header format? (We do not currently support the - * old format.) - * - * @return true if using new header format - */ - public boolean isNewHeader() { - return (flags & 0x0001) == 0x0001; - } - - /** - * Is this the new inode format? (We do not currently support the - * old format.) - * @return true if using new inode format - */ - public boolean isNewInode() { - return (flags & 0x0002) == 0x0002; - } - - /** - * Is this volume compressed? N.B., individual blocks may or may not be compressed. - * The first block is never compressed. - * @return true if volume is compressed - */ - public boolean isCompressed() { - return (flags & 0x0080) == 0x0080; - } - - /** - * Does this volume only contain metadata? - * @return true if volume only contains meta-data - */ - public boolean isMetaDataOnly() { - return (flags & 0x0100) == 0x0100; - } - - /** - * Does this volume cotain extended attributes. - * @return true if volume cotains extended attributes. - */ - public boolean isExtendedAttributes() { - return (flags & 0x8000) == 0x8000; - } - - @Override - public int hashCode() { - int hash = 17; - - if (label != null) { - hash = label.hashCode(); - } - - hash += 31 * dumpDate; - - if (hostname != null) { - hash = (31 * hostname.hashCode()) + 17; - } - - if (devname != null) { - hash = (31 * devname.hashCode()) + 17; - } - - return hash; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - - if (o == null || !o.getClass().equals(getClass())) { - return false; - } - - final DumpArchiveSummary rhs = (DumpArchiveSummary) o; - - if (dumpDate != rhs.dumpDate) { - return false; - } - - if ((getHostname() == null) || - !getHostname().equals(rhs.getHostname())) { - return false; - } - - if ((getDevname() == null) || !getDevname().equals(rhs.getDevname())) { - return false; - } - - return true; - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/DumpArchiveUtil.java b/src/org/apache/commons/compress/archivers/dump/DumpArchiveUtil.java deleted file mode 100644 index 20e1eb3f271..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/DumpArchiveUtil.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -import java.io.IOException; -import java.util.Arrays; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.utils.ByteUtils; - -/** - * Various utilities for dump archives. - */ -class DumpArchiveUtil { - /** - * Private constructor to prevent instantiation. - */ - private DumpArchiveUtil() { - } - - /** - * Calculate checksum for buffer. - * - * @param buffer buffer containing tape segment header - * @returns checksum - */ - public static int calculateChecksum(final byte[] buffer) { - int calc = 0; - - for (int i = 0; i < 256; i++) { - calc += DumpArchiveUtil.convert32(buffer, 4 * i); - } - - return DumpArchiveConstants.CHECKSUM - - (calc - DumpArchiveUtil.convert32(buffer, 28)); - } - - /** - * Verify that the buffer contains a tape segment header. - * - * @param buffer - */ - public static final boolean verify(final byte[] buffer) { - // verify magic. for now only accept NFS_MAGIC. - final int magic = convert32(buffer, 24); - - if (magic != DumpArchiveConstants.NFS_MAGIC) { - return false; - } - - //verify checksum... - final int checksum = convert32(buffer, 28); - - return checksum == calculateChecksum(buffer); - } - - /** - * Get the ino associated with this buffer. - * - * @param buffer - */ - public static final int getIno(final byte[] buffer) { - return convert32(buffer, 20); - } - - /** - * Read 8-byte integer from buffer. - * - * @param buffer - * @param offset - * @return the 8-byte entry as a long - */ - public static final long convert64(final byte[] buffer, final int offset) { - return ByteUtils.fromLittleEndian(buffer, offset, 8); - } - - /** - * Read 4-byte integer from buffer. - * - * @param buffer - * @param offset - * @return the 4-byte entry as an int - */ - public static final int convert32(final byte[] buffer, final int offset) { - return (int) ByteUtils.fromLittleEndian(buffer, offset, 4); - } - - /** - * Read 2-byte integer from buffer. - * - * @param buffer - * @param offset - * @return the 2-byte entry as an int - */ - public static final int convert16(final byte[] buffer, final int offset) { - return (int) ByteUtils.fromLittleEndian(buffer, offset, 2); - } - - /** - * Decodes a byte array to a string. - */ - static String decode(final ZipEncoding encoding, final byte[] b, final int offset, final int len) - throws IOException { - return encoding.decode(Arrays.copyOfRange(b, offset, offset + len)); - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/InvalidFormatException.java b/src/org/apache/commons/compress/archivers/dump/InvalidFormatException.java deleted file mode 100644 index 6169dfe90f5..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/InvalidFormatException.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - - -/** - * Invalid Format Exception. There was an error decoding a - * tape segment header. - */ -public class InvalidFormatException extends DumpArchiveException { - private static final long serialVersionUID = 1L; - protected long offset; - - public InvalidFormatException() { - super("there was an error decoding a tape segment"); - } - - public InvalidFormatException(final long offset) { - super("there was an error decoding a tape segment header at offset " + - offset + "."); - this.offset = offset; - } - - public long getOffset() { - return offset; - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/ShortFileException.java b/src/org/apache/commons/compress/archivers/dump/ShortFileException.java deleted file mode 100644 index e06c97cc08f..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/ShortFileException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - - -/** - * Short File Exception. There was an unexpected EOF when reading - * the input stream. - */ -public class ShortFileException extends DumpArchiveException { - private static final long serialVersionUID = 1L; - - public ShortFileException() { - super("unexpected EOF"); - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/TapeInputStream.java b/src/org/apache/commons/compress/archivers/dump/TapeInputStream.java deleted file mode 100644 index 5643decef8f..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/TapeInputStream.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -import java.util.Arrays; -import java.util.zip.DataFormatException; -import java.util.zip.Inflater; - -import org.apache.commons.compress.utils.IOUtils; - -/** - * Filter stream that mimics a physical tape drive capable of compressing - * the data stream. - * - * @NotThreadSafe - */ -class TapeInputStream extends FilterInputStream { - private byte[] blockBuffer = new byte[DumpArchiveConstants.TP_SIZE]; - private int currBlkIdx = -1; - private int blockSize = DumpArchiveConstants.TP_SIZE; - private static final int RECORD_SIZE = DumpArchiveConstants.TP_SIZE; - private int readOffset = DumpArchiveConstants.TP_SIZE; - private boolean isCompressed = false; - private long bytesRead = 0; - - /** - * Constructor - */ - public TapeInputStream(final InputStream in) { - super(in); - } - - /** - * Set the DumpArchive Buffer's block size. We need to sync the block size with the - * dump archive's actual block size since compression is handled at the - * block level. - * - * @param recsPerBlock - * records per block - * @param isCompressed - * true if the archive is compressed - * @throws IOException - * more than one block has been read - * @throws IOException - * there was an error reading additional blocks. - */ - public void resetBlockSize(final int recsPerBlock, final boolean isCompressed) - throws IOException { - this.isCompressed = isCompressed; - - blockSize = RECORD_SIZE * recsPerBlock; - - // save first block in case we need it again - final byte[] oldBuffer = blockBuffer; - - // read rest of new block - blockBuffer = new byte[blockSize]; - System.arraycopy(oldBuffer, 0, blockBuffer, 0, RECORD_SIZE); - readFully(blockBuffer, RECORD_SIZE, blockSize - RECORD_SIZE); - - this.currBlkIdx = 0; - this.readOffset = RECORD_SIZE; - } - - /** - * @see java.io.InputStream#available - */ - @Override - public int available() throws IOException { - if (readOffset < blockSize) { - return blockSize - readOffset; - } - - return in.available(); - } - - /** - * @see java.io.InputStream#read() - */ - @Override - public int read() throws IOException { - throw new IllegalArgumentException( - "all reads must be multiple of record size (" + RECORD_SIZE + - " bytes."); - } - - /** - * {@inheritDoc} - * - *

reads the full given length unless EOF is reached.

- * - * @param len length to read, must be a multiple of the stream's - * record size - */ - @Override - public int read(final byte[] b, int off, final int len) throws IOException { - if ((len % RECORD_SIZE) != 0) { - throw new IllegalArgumentException( - "all reads must be multiple of record size (" + RECORD_SIZE + - " bytes."); - } - - int bytes = 0; - - while (bytes < len) { - // we need to read from the underlying stream. - // this will reset readOffset value. - // return -1 if there's a problem. - if (readOffset == blockSize) { - try { - readBlock(true); - } catch (ShortFileException sfe) { // NOSONAR - return -1; - } - } - - int n = 0; - - if ((readOffset + (len - bytes)) <= blockSize) { - // we can read entirely from the buffer. - n = len - bytes; - } else { - // copy what we can from the buffer. - n = blockSize - readOffset; - } - - // copy data, increment counters. - System.arraycopy(blockBuffer, readOffset, b, off, n); - readOffset += n; - bytes += n; - off += n; - } - - return bytes; - } - - /** - * Skip bytes. Same as read but without the arraycopy. - * - *

skips the full given length unless EOF is reached.

- * - * @param len length to read, must be a multiple of the stream's - * record size - */ - @Override - public long skip(final long len) throws IOException { - if ((len % RECORD_SIZE) != 0) { - throw new IllegalArgumentException( - "all reads must be multiple of record size (" + RECORD_SIZE + - " bytes."); - } - - long bytes = 0; - - while (bytes < len) { - // we need to read from the underlying stream. - // this will reset readOffset value. We do not perform - // any decompression if we won't eventually read the data. - // return -1 if there's a problem. - if (readOffset == blockSize) { - try { - readBlock((len - bytes) < blockSize); - } catch (ShortFileException sfe) { // NOSONAR - return -1; - } - } - - long n = 0; - - if ((readOffset + (len - bytes)) <= blockSize) { - // we can read entirely from the buffer. - n = len - bytes; - } else { - // copy what we can from the buffer. - n = (long) blockSize - readOffset; - } - - // do not copy data but still increment counters. - readOffset += n; - bytes += n; - } - - return bytes; - } - - /** - * Close the input stream. - * - * @throws IOException on error - */ - @Override - public void close() throws IOException { - if (in != null && in != System.in) { - in.close(); - } - } - - /** - * Peek at the next record from the input stream and return the data. - * - * @return The record data. - * @throws IOException on error - */ - public byte[] peek() throws IOException { - // we need to read from the underlying stream. This - // isn't a problem since it would be the first step in - // any subsequent read() anyway. - if (readOffset == blockSize) { - try { - readBlock(true); - } catch (ShortFileException sfe) { // NOSONAR - return null; - } - } - - // copy data, increment counters. - final byte[] b = new byte[RECORD_SIZE]; - System.arraycopy(blockBuffer, readOffset, b, 0, b.length); - - return b; - } - - /** - * Read a record from the input stream and return the data. - * - * @return The record data. - * @throws IOException on error - */ - public byte[] readRecord() throws IOException { - final byte[] result = new byte[RECORD_SIZE]; - - // the read implementation will loop internally as long as - // input is available - if (-1 == read(result, 0, result.length)) { - throw new ShortFileException(); - } - - return result; - } - - /** - * Read next block. All decompression is handled here. - * - * @param decompress if false the buffer will not be decompressed. - * This is an optimization for longer seeks. - */ - private void readBlock(final boolean decompress) throws IOException { - if (in == null) { - throw new IOException("input buffer is closed"); - } - - if (!isCompressed || (currBlkIdx == -1)) { - // file is not compressed - readFully(blockBuffer, 0, blockSize); - bytesRead += blockSize; - } else { - readFully(blockBuffer, 0, 4); - bytesRead += 4; - - final int h = DumpArchiveUtil.convert32(blockBuffer, 0); - final boolean compressed = (h & 0x01) == 0x01; - - if (!compressed) { - // file is compressed but this block is not. - readFully(blockBuffer, 0, blockSize); - bytesRead += blockSize; - } else { - // this block is compressed. - final int flags = (h >> 1) & 0x07; - int length = (h >> 4) & 0x0FFFFFFF; - final byte[] compBuffer = new byte[length]; - readFully(compBuffer, 0, length); - bytesRead += length; - - if (!decompress) { - // just in case someone reads the data. - Arrays.fill(blockBuffer, (byte) 0); - } else { - switch (DumpArchiveConstants.COMPRESSION_TYPE.find(flags & - 0x03)) { - case ZLIB: - - final Inflater inflator = new Inflater(); - try { - inflator.setInput(compBuffer, 0, compBuffer.length); - length = inflator.inflate(blockBuffer); - - if (length != blockSize) { - throw new ShortFileException(); - } - } catch (final DataFormatException e) { - throw new DumpArchiveException("bad data", e); - } finally { - inflator.end(); - } - - break; - - case BZLIB: - throw new UnsupportedCompressionAlgorithmException( - "BZLIB2"); - - case LZO: - throw new UnsupportedCompressionAlgorithmException( - "LZO"); - - default: - throw new UnsupportedCompressionAlgorithmException(); - } - } - } - } - - currBlkIdx++; - readOffset = 0; - } - - /** - * Read buffer - */ - private void readFully(final byte[] b, final int off, final int len) - throws IOException { - final int count = IOUtils.readFully(in, b, off, len); - if (count < len) { - throw new ShortFileException(); - } - } - - /** - * Get number of bytes read. - */ - public long getBytesRead() { - return bytesRead; - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/UnrecognizedFormatException.java b/src/org/apache/commons/compress/archivers/dump/UnrecognizedFormatException.java deleted file mode 100644 index 333aeacd62b..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/UnrecognizedFormatException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - - -/** - * Unrecognized Format Exception. This is either not a recognized dump archive or there's - * a bad tape segment header. - */ -public class UnrecognizedFormatException extends DumpArchiveException { - private static final long serialVersionUID = 1L; - - public UnrecognizedFormatException() { - super("this is not a recognized format."); - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/UnsupportedCompressionAlgorithmException.java b/src/org/apache/commons/compress/archivers/dump/UnsupportedCompressionAlgorithmException.java deleted file mode 100644 index 8c604030423..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/UnsupportedCompressionAlgorithmException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.dump; - - -/** - * Unsupported compression algorithm. The dump archive uses an unsupported - * compression algorithm (BZLIB2 or LZO). - */ -public class UnsupportedCompressionAlgorithmException - extends DumpArchiveException { - private static final long serialVersionUID = 1L; - - public UnsupportedCompressionAlgorithmException() { - super("this file uses an unsupported compression algorithm."); - } - - public UnsupportedCompressionAlgorithmException(final String alg) { - super("this file uses an unsupported compression algorithm: " + alg + - "."); - } -} diff --git a/src/org/apache/commons/compress/archivers/dump/package.html b/src/org/apache/commons/compress/archivers/dump/package.html deleted file mode 100644 index 72f3c68c40a..00000000000 --- a/src/org/apache/commons/compress/archivers/dump/package.html +++ /dev/null @@ -1,56 +0,0 @@ - - - -

This package provides stream classes for reading archives - using the Unix DUMP format. This format is similar to (and - contemporary with) TAR but reads the raw filesystem directly. - This means that writers are filesystem-specific even though the - created archives are filesystem-agnostic. -

- -

Unlike other formats DUMP offers clean support for sparse files, - extended attributes, and other file metadata. In addition DUMP - supports incremental dump files can capture (most) file deletion. - It also provides a native form of compression and will soon support - native encryption as well. -

- -

In practice TAR archives are used for both distribution - and backups. DUMP archives are used exclusively for backups. -

- -

Like any 30+-year-old application there are a number of variants. - For pragmatic reasons we will only support archives with the - 'new' tape header and inode formats. Other restrictions: - -

    -
  • We only support ZLIB compression. The format - also permits LZO and BZLIB compression.
  • -
  • Sparse files will have the holes filled.
  • -
  • MacOS finder and resource streams are ignored.
  • -
  • Extended attributes are not currently provided.
  • -
  • SELinux labels are not currently provided.
  • -
-

- -

As of Apache Commons Compress 1.3 support for the dump format is - read-only.

- - diff --git a/src/org/apache/commons/compress/archivers/examples/Archive.java b/src/org/apache/commons/compress/archivers/examples/Archive.java deleted file mode 100644 index 1895a7d13db..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Archive.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Consumes files and passes them to a sink, usually used to create an archive of them. - * @since 1.17 - */ -public class Archive { - /** - * Sets up a chain of operations and consumes the files from a source of files. - * @since 1.17 - */ - public interface ChainBuilder { - /** - * Adds a filter to the chain. - * @param filter the filter to apply - * @return an updated builder - */ - ChainBuilder filter(Filter filter); - /** - * Adds a filter to the chain. - * @param filter the filter to apply - * @return an updated builder - */ - ChainBuilder filter(FileFilter filter); - /** - * Adds a filter to the chain that filters out entries that cannot be read. - * @return an updated builder - */ - ChainBuilder skipUnreadable(); - /** - * Adds a filter to the chain that filters out everything that is not a file. - * @return an updated builder - */ - ChainBuilder skipNonFiles(); - /** - * Adds a transformer to the chain. - * @param transformer transformer to apply - * @return an updated builder - */ - ChainBuilder map(Transformer transformer); - /** - * Adds a generic step to the chain. - * @param step step to perform - * @return an updated builder - */ - ChainBuilder withStep(ChainStep step); - /** - * Actually consumes all the files supplied. - * @param sink sink that the entries will be sent to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be written for other reasons - */ - void to(Sink sink) throws IOException, ArchiveException; - } - - /** - * Sets the source of files to be a directory. - * @param f the source directory - * @return a builder for the chain to be created and run - */ - public static ChainBuilder directory(File f) { - return source(new DirectoryBasedSource(f)); - } - - /** - * Sets the source of files to process. - * @param source the source directory - * @return a builder for the chain to be created and run - */ - public static ChainBuilder source(Source source) { - return new Builder(source); - } - - private static class Builder implements ChainBuilder { - private final Source source; - private ChainDefinition chainDef = new ChainDefinition<>(); - - Builder(Source source) { - this.source = source; - } - - @Override - public ChainBuilder filter(Filter filter) { - return withStep(filter); - } - @Override - public ChainBuilder filter(FileFilter filter) { - return filter(new FileFilterAdapter(filter)); - } - @Override - public ChainBuilder skipUnreadable() { - return filter(new FileFilter() { - @Override - public boolean accept(File f) { - return f.canRead(); - } - }); - } - @Override - public ChainBuilder skipNonFiles() { - return filter(new FileFilter() { - @Override - public boolean accept(File f) { - return f.isFile(); - } - }); - } - @Override - public ChainBuilder map(Transformer transformer) { - return withStep(transformer); - } - @Override - public ChainBuilder withStep(ChainStep step) { - chainDef.add(step); - return this; - } - @Override - public void to(Sink sink) throws IOException, ArchiveException { - chainDef.add(sink); - chainDef.freeze(); - new ChainRunner(source, chainDef, sink).run(); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/examples/ArchiveCli.java b/src/org/apache/commons/compress/archivers/examples/ArchiveCli.java deleted file mode 100644 index cb204602a8c..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ArchiveCli.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Simple command line tool that creates an archive from the contents of a directory. - * - *

Usage: ArchiveCli dir format archive

- * @since 1.17 - */ -public class ArchiveCli { - - public static void main(String[] args) throws IOException, ArchiveException { - if (args.length != 3) { - System.err.println("Usage: ArchiveCli dir format target"); - System.exit(1); - } - try (Sink sink = ArchiveSinks.forFile(args[1], new File(args[2]))) { - Archive.directory(new File(args[0])) - .to(sink); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/examples/ArchiveEntrySource.java b/src/org/apache/commons/compress/archivers/examples/ArchiveEntrySource.java deleted file mode 100644 index 402134fd3b1..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ArchiveEntrySource.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * Combines Source and a factory for filter that skips unreadable entries. - * @since 1.17 - */ -public interface ArchiveEntrySource extends Source { - - /** - * Provides a filter that can be used to skip entries the - * underlying source is unable to read the content of. - * @return filter that can be used to skip entries the underlying - * source is unable to read the content of - */ - Filter skipUnreadable(); -} diff --git a/src/org/apache/commons/compress/archivers/examples/ArchiveSinks.java b/src/org/apache/commons/compress/archivers/examples/ArchiveSinks.java deleted file mode 100644 index f00fc4f3886..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ArchiveSinks.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.FileOutputStream; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.StandardOpenOption; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveStreamFactory; -import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; - -/** - * Supplies factory methods for file sinks that write to archives, - * @since 1.17 - */ -public class ArchiveSinks { - /** - * Uses {@link ArchiveStreamFactory#createArchiveOutputStream}. - * - *

Will not support 7z.

- * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param os the stream to write to. - * @return a sink that consumes the files - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public static Sink forStream(String format, OutputStream os) throws IOException, ArchiveException { - return new FileToArchiveSink(new ArchiveStreamFactory().createArchiveOutputStream(format, os)); - } - - /** - * Uses {@link ArchiveStreamFactory#createArchiveOutputStream} unless - * special handling for ZIP or 7z is required. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the file to write to. - * @return a sink that consumes the files - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public static Sink forFile(String format, File target) throws IOException, ArchiveException { - if (prefersSeekableByteChannel(format)) { - return forChannel(format, FileChannel.open(target.toPath(), StandardOpenOption.WRITE, - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)); - } - return new FileToArchiveSink(new ArchiveStreamFactory() - .createArchiveOutputStream(format, new FileOutputStream(target))); - } - - /** - * Uses {@link ArchiveStreamFactory#createArchiveOutputStream} unless - * special handling for ZIP or 7z is required. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param c the channel to write to. - * @return a sink that consumes the files - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public static Sink forChannel(String format, SeekableByteChannel c) throws IOException, ArchiveException { - if (!prefersSeekableByteChannel(format)) { - return forStream(format, Channels.newOutputStream(c)); - } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) { - return new FileToArchiveSink(new ZipArchiveOutputStream(c)); - } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) { - return new SevenZOutputFileSink(c); - } else { - throw new ArchiveException("don't know how to handle format " + format); - } - } - - private static boolean prefersSeekableByteChannel(String format) { - return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ArchiveSources.java b/src/org/apache/commons/compress/archivers/examples/ArchiveSources.java deleted file mode 100644 index 670eb2f6a49..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ArchiveSources.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.FileInputStream; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.StandardOpenOption; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.ArchiveStreamFactory; -import org.apache.commons.compress.archivers.sevenz.SevenZFile; -import org.apache.commons.compress.archivers.zip.ZipFile; - -/** - * Supplies factory methods for ArchiveEntry sources that read from archives, - * @since 1.17 - */ -public class ArchiveSources { - /** - * Builder for {@link ArchiveEntrySource} that needs to know its format. - * @since 1.17 - */ - public interface PendingFormat { - /** - * Signals the format shall be detcted automatically. - * @return the configured source - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - ArchiveEntrySource detectFormat() throws IOException, ArchiveException; - /** - * Explicitly provides the expected format of the archive. - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @return the configured source - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - ArchiveEntrySource withFormat(String format) throws IOException, ArchiveException; - } - - /** - * Uses {@link ArchiveStreamFactory#createArchiveInputStream} unless special handling for ZIP or /z is required. - * - * @param f the file to read from - * @return a builder that needs to know the format - */ - public static PendingFormat forFile(final File f) { - return new PendingFormat() { - @Override - public ArchiveEntrySource detectFormat() throws IOException, ArchiveException { - String format = null; - try (InputStream i = new BufferedInputStream(new FileInputStream(f))) { - format = new ArchiveStreamFactory().detect(i); - } - return withFormat(format); - } - @Override - public ArchiveEntrySource withFormat(String format) throws IOException, ArchiveException { - if (prefersSeekableByteChannel(format)) { - return forChannel(format, FileChannel.open(f.toPath(), StandardOpenOption.READ)); - } - return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory() - .createArchiveInputStream(format, new BufferedInputStream(new FileInputStream(f)))); - } - }; - } - - /** - * Uses {@link ArchiveStreamFactory#createArchiveInputStream} unless special handling for ZIP or /z is required. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param c the channel to read from - * @return the configured source - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public static ArchiveEntrySource forChannel(String format, SeekableByteChannel c) - throws IOException, ArchiveException { - if (!prefersSeekableByteChannel(format)) { - return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory() - .createArchiveInputStream(format, Channels.newInputStream(c))); - } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) { - return new ZipArchiveEntrySource(c); - } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) { - return new SevenZArchiveEntrySource(c); - } - throw new ArchiveException("don't know how to handle format " + format); - } - - /** - * Uses {@link ArchiveStreamFactory#createArchiveInputStream}. - * - *

Will not support 7z.

- * - * @param in the stream to read from - * @return a builder that needs to know the format - */ - public static PendingFormat forStream(final InputStream in) { - return new PendingFormat() { - @Override - public ArchiveEntrySource detectFormat() throws IOException, ArchiveException { - return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory().createArchiveInputStream(in)); - } - @Override - public ArchiveEntrySource withFormat(String format) throws IOException, ArchiveException { - return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory() - .createArchiveInputStream(format, in)); - } - }; - } - - private static boolean prefersSeekableByteChannel(String format) { - return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/Archiver.java b/src/org/apache/commons/compress/archivers/examples/Archiver.java deleted file mode 100644 index b34d16bb786..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Archiver.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.archivers.ArchiveStreamFactory; -import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile; -import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Provides a high level API for creating archives. - * @since 1.17 - */ -public class Archiver { - - private interface ArchiveEntryCreator { - ArchiveEntry create(File f, String entryName) throws IOException; - } - - private interface ArchiveEntryConsumer { - void accept(File source, ArchiveEntry entry) throws IOException; - } - - private interface Finisher { - void finish() throws IOException; - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the file to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, File target, File directory) throws IOException, ArchiveException { - if (prefersSeekableByteChannel(format)) { - try (SeekableByteChannel c = FileChannel.open(target.toPath(), StandardOpenOption.WRITE, - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - create(format, c, directory); - } - return; - } - try (OutputStream o = Files.newOutputStream(target.toPath())) { - create(format, o, directory); - } - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the stream to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, OutputStream target, File directory) throws IOException, ArchiveException { - create(new ArchiveStreamFactory().createArchiveOutputStream(format, target), directory); - } - - /** - * Creates an archive {@code target} using the format {@code - * format} by recursively including all files and directories in - * {@code directory}. - * - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @param target the channel to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(String format, SeekableByteChannel target, File directory) - throws IOException, ArchiveException { - if (!prefersSeekableByteChannel(format)) { - create(format, Channels.newOutputStream(target), directory); - } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) { - create(new ZipArchiveOutputStream(target), directory); - } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) { - create(new SevenZOutputFile(target), directory); - } else { - // never reached as prefersSeekableByteChannel only returns true for ZIP and 7z - throw new ArchiveException("don't know how to handle format " + format); - } - } - - /** - * Creates an archive {@code target} by recursively including all - * files and directories in {@code directory}. - * - * @param target the stream to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be created for other reasons - */ - public void create(final ArchiveOutputStream target, File directory) - throws IOException, ArchiveException { - create(directory, new ArchiveEntryCreator() { - public ArchiveEntry create(File f, String entryName) throws IOException { - return target.createArchiveEntry(f, entryName); - } - }, new ArchiveEntryConsumer() { - public void accept(File source, ArchiveEntry e) throws IOException { - target.putArchiveEntry(e); - if (!e.isDirectory()) { - try (InputStream in = new BufferedInputStream(Files.newInputStream(source.toPath()))) { - IOUtils.copy(in, target); - } - } - target.closeArchiveEntry(); - } - }, new Finisher() { - public void finish() throws IOException { - target.finish(); - } - }); - } - - /** - * Creates an archive {@code target} by recursively including all - * files and directories in {@code directory}. - * - * @param target the file to write the new archive to. - * @param directory the directory that contains the files to archive. - * @throws IOException if an I/O error occurs - */ - public void create(final SevenZOutputFile target, File directory) throws IOException { - create(directory, new ArchiveEntryCreator() { - public ArchiveEntry create(File f, String entryName) throws IOException { - return target.createArchiveEntry(f, entryName); - } - }, new ArchiveEntryConsumer() { - public void accept(File source, ArchiveEntry e) throws IOException { - target.putArchiveEntry(e); - if (!e.isDirectory()) { - final byte[] buffer = new byte[8024]; - int n = 0; - long count = 0; - try (InputStream in = new BufferedInputStream(Files.newInputStream(source.toPath()))) { - while (-1 != (n = in.read(buffer))) { - target.write(buffer, 0, n); - count += n; - } - } - } - target.closeArchiveEntry(); - } - }, new Finisher() { - public void finish() throws IOException { - target.finish(); - } - }); - } - - private boolean prefersSeekableByteChannel(String format) { - return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format); - } - - private void create(File directory, ArchiveEntryCreator creator, ArchiveEntryConsumer consumer, - Finisher finisher) throws IOException { - create("", directory, creator, consumer); - finisher.finish(); - } - - private void create(String prefix, File directory, ArchiveEntryCreator creator, ArchiveEntryConsumer consumer) - throws IOException { - File[] children = directory.listFiles(); - if (children == null) { - return; - } - for (File f : children) { - String entryName = prefix + f.getName() + (f.isDirectory() ? "/" : ""); - consumer.accept(f, creator.create(f, entryName)); - if (f.isDirectory()) { - create(entryName, f, creator, consumer); - } - } - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/Chain.java b/src/org/apache/commons/compress/archivers/examples/Chain.java deleted file mode 100644 index 86d2e1c60d8..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Chain.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import java.util.Iterator; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Encapsulates the execution flow of a chain of operations. - * @since 1.17 - */ -public class Chain { - - private final Iterator> chain; - - /** - * Instantiates a new chain. - * - * @param chain the steps to take in order. - */ - public Chain(Iterator> chain) { - this.chain = chain; - } - - /** - * Invokes the next step of the chain. - * - * @param payload the payload to pass to the next step - * @throws IOException if an I/O error occurs - * @throws ArchiveException if an archive format related error occurs - */ - public void next(ChainPayload payload) throws IOException, ArchiveException { - if (chain.hasNext()) { - chain.next().process(payload, this); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ChainDefinition.java b/src/org/apache/commons/compress/archivers/examples/ChainDefinition.java deleted file mode 100644 index d8a387f8485..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ChainDefinition.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.util.Deque; -import java.util.LinkedList; - -/** - * The recipe for building a {@link Chain}. - * @since 1.17 - */ -class ChainDefinition { - private final Deque> steps = new LinkedList<>(); - private volatile boolean frozen = false; - - /** - * Adds a step. - * @throws IllegalStateException if the definition is already frozen. - */ - void add(ChainStep step) { - if (frozen) { - throw new IllegalStateException("the definition is already frozen"); - } - steps.addLast(step); - } - - /** - * Freezes the definition. - * - *

Once this method has been invoked {@link #add} can no longer be invoked.

- * - * @throws IllegalStateException if the last step of the definition is not a sink. - */ - void freeze() { - if (!frozen) { - frozen = true; - if (!(steps.getLast() instanceof Sink)) { - throw new IllegalStateException("this definition doesn't end in a sink"); - } - } - } - - /** - * Returns a chain for this definition. - * - * @throws IllegalStateException if the definition is not frozen. - */ - Chain chain() { - if (!frozen) { - throw new IllegalStateException("the definition hasn't been frozen, yet"); - } - return new Chain(steps.iterator()); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ChainPayload.java b/src/org/apache/commons/compress/archivers/examples/ChainPayload.java deleted file mode 100644 index 11d86181226..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ChainPayload.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.InputStream; - -/** - * The data that is pushed through a chain. - * @since 1.17 - */ -public class ChainPayload { - private final T entry; - private final String entryName; - private final Supplier input; - /** - * Constructs the payload. - * @param entry entry the actual payload - * @param entryName the local name of the entry. This may - for - * example - be the file name relative to a directory. - * @param input supplies an input stream to the entry's - * content. Is not expected to be called more than once. - */ - public ChainPayload(T entry, String entryName, Supplier input) { - this.entry = entry; - this.entryName = entryName; - this.input = input; - } - /** - * Provides the real payload. - * @return the real playoad - * - */ - public T getEntry() { - return entry; - } - /** - * Provides the local name of the entry. - * - *

This may - for example - be the file name relative to a - * directory.

- * - * @return local name of the entry - */ - public String getEntryName() { - return entryName; - } - /** - * Returns a {@link Supplier} that can be used to read the entry's content. - * - *

The supplier is not required to be callable more than - * once.

- * - * @return supplier of input - */ - public Supplier getInput() { - return input; - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ChainRunner.java b/src/org/apache/commons/compress/archivers/examples/ChainRunner.java deleted file mode 100644 index 5f435890bff..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ChainRunner.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Contains the execution logic of a full chain including a source. - * @since 1.17 - */ -class ChainRunner { - private final Source source; - private final ChainDefinition chainDef; - private final Sink sink; - - ChainRunner(Source source, ChainDefinition chainDef, Sink sink) { - this.source = source; - this.chainDef = chainDef; - this.sink = sink; - } - - void run() throws IOException, ArchiveException { - ThrowingIterator> iter = source.get(); - while (iter.hasNext()) { - chainDef.chain().next(iter.next()); - } - sink.finish(); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ChainStep.java b/src/org/apache/commons/compress/archivers/examples/ChainStep.java deleted file mode 100644 index ee0e4b3acf5..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ChainStep.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * A step inside of a {@link Chain}. - * @since 1.17 - */ -public interface ChainStep { - /** - * Process the chain's payload. - * - *

Any non-terminal step that invokes the {@link Supplier} of - * the payload is responsible for providing a fresh supplier if - * the chain is to be continued.

- * - * @param payload the payload. - * @param chain chain to return control to once processing is done. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if an archive format related error occurs - */ - void process(ChainPayload payload, Chain chain) throws IOException, ArchiveException; -} diff --git a/src/org/apache/commons/compress/archivers/examples/DirectoryBasedSource.java b/src/org/apache/commons/compress/archivers/examples/DirectoryBasedSource.java deleted file mode 100644 index c6ca484c582..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/DirectoryBasedSource.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Recursively returns all files and directories contained inside of a base directory. - * @since 1.17 - */ -public class DirectoryBasedSource implements Source { - - private final File dir; - - /** - * Sets up a directory as source. - * - * @param dir the directory to provide entries from. - * @throws IllegalArgumentException if dir doesn't exist or is not a directory - */ - public DirectoryBasedSource(File dir) { - if (!dir.isDirectory()) { - throw new IllegalArgumentException("dir is not a readable directory"); - } - this.dir = dir; - } - - @Override - public ThrowingIterator> get() throws IOException { - return new DirectoryIterator("", dir); - } - - @Override - public void close() { - } - - private static class DirectoryIterator implements ThrowingIterator> { - private final Iterator files; - private final String namePrefix; - private DirectoryIterator nestedIterator; - DirectoryIterator(String namePrefix, File dir) throws IOException { - this.namePrefix = namePrefix; - File[] fs = dir.listFiles(); - files = fs == null ? Collections.emptyIterator() : Arrays.asList(fs).iterator(); - } - - @Override - public boolean hasNext() throws IOException { - if (nestedIterator != null && nestedIterator.hasNext()) { - return true; - } - if (nestedIterator != null) { - nestedIterator = null; - } - return files.hasNext(); - } - - @Override - public ChainPayload next() throws IOException { - if (!hasNext()) { - throw new NoSuchElementException(); - } - if (nestedIterator != null) { - return nestedIterator.next(); - } - final File f = files.next(); - String entryName = namePrefix + f.getName(); - if (f.isDirectory()) { - entryName += "/"; - nestedIterator = new DirectoryIterator(entryName, f); - } - return new ChainPayload(f, entryName, new Supplier() { - @Override - public InputStream get() throws IOException { - return new FileInputStream(f); - } - }); - } - - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/DirectoryBasedSupplier.java b/src/org/apache/commons/compress/archivers/examples/DirectoryBasedSupplier.java deleted file mode 100644 index 1b8cc9180ea..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/DirectoryBasedSupplier.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Recursively returns all files and directories contained inside of a base directory. - * @since 1.17 - */ -public class DirectoryBasedSupplier - implements Supplier>> { - - private final File dir; - - /** - * @param dir the directory to provide entries from. - */ - public DirectoryBasedSupplier(File dir) { - if (!dir.isDirectory()) { - throw new IllegalArgumentException("dir is not a readable directory"); - } - this.dir = dir; - } - - @Override - public ThrowingIterator> get() throws IOException { - return new DirectoryIterator("", dir); - } - - private static class DirectoryIterator implements ThrowingIterator> { - private final Iterator files; - private final String namePrefix; - private DirectoryIterator nestedIterator; - DirectoryIterator(String namePrefix, File dir) throws IOException { - this.namePrefix = namePrefix; - File[] fs = dir.listFiles(); - files = fs == null ? Collections.emptyIterator() : Arrays.asList(fs).iterator(); - } - - @Override - public boolean hasNext() throws IOException { - if (nestedIterator != null && nestedIterator.hasNext()) { - return true; - } - if (nestedIterator != null) { - nestedIterator = null; - } - return files.hasNext(); - } - - @Override - public ChainPayload next() throws IOException { - if (!hasNext()) { - throw new NoSuchElementException(); - } - if (nestedIterator != null) { - return nestedIterator.next(); - } - final File f = files.next(); - String entryName = namePrefix + f.getName(); - if (f.isDirectory()) { - entryName += "/"; - nestedIterator = new DirectoryIterator(entryName, f); - } - return new ChainPayload(f, entryName, new Supplier() { - @Override - public InputStream get() throws IOException { - return new FileInputStream(f); - } - }); - } - - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/DirectorySink.java b/src/org/apache/commons/compress/archivers/examples/DirectorySink.java deleted file mode 100644 index 7a34858cf69..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/DirectorySink.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.utils.IOUtils; - -/** - * A sink that expands archive entries into a directory. - * @since 1.17 - */ -public class DirectorySink extends Sink { - private final File dir; - private final String dirPath; - - /** - * Sets up a directory as sink. - * - * @param dir the directory to provide entries from. - * @throws IOException if the canonical path of the directory cannot be determined - * @throws IllegalArgumentException if dir doesn't exist or is not a directory - */ - public DirectorySink(File dir) throws IOException { - if (!dir.isDirectory()) { - throw new IllegalArgumentException("dir is not a readable directory"); - } - this.dir = dir; - dirPath = dir.getCanonicalPath(); - } - - @Override - public void consume(ChainPayload payload) throws IOException, ArchiveException { - File f = new File(dir, payload.getEntryName()); - if (!f.getCanonicalPath().startsWith(dirPath)) { - throw new IOException("expanding " + payload.getEntryName() + " would create file outside of " + dir); - } - if (payload.getEntry().isDirectory()) { - f.mkdirs(); - } else { - f.getParentFile().mkdirs(); - try (OutputStream o = new FileOutputStream(f); - InputStream i = payload.getInput().get()) { - IOUtils.copy(i, o); - } - } - } - - @Override - public void close() { - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/Expand.java b/src/org/apache/commons/compress/archivers/examples/Expand.java deleted file mode 100644 index d6ece27a3f7..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Expand.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Consumes archive entries and passes them to a sink, usually used to - * expand an archive. - * @since 1.17 - */ -public class Expand { - /** - * Sets up a chain of operations and consumes the entries from a source of archive entries. - * @since 1.17 - */ - public interface ChainBuilder { - /** - * Adds a filter to the chain. - * @param filter the filter to apply - * @return an updated builder - */ - ChainBuilder filter(Filter filter); - /** - * Adds a filter to the chain that filters out entries that cannot be read. - * @return an updated builder - */ - ChainBuilder skipUnreadable(); - /** - * Adds a filter to the chain that suppresses all directory entries. - * @return an updated builder - */ - ChainBuilder skipDirectories(); - /** - * Adds a transformer to the chain. - * @param transformer transformer to apply - * @return an updated builder - */ - ChainBuilder map(Transformer transformer); - /** - * Adds a generic step to the chain. - * @return an updated builder - * @param step step to perform - */ - ChainBuilder withStep(ChainStep step); - /** - * Actually consumes all the entries supplied. - * @param sink sink that the entries will be sent to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the source archive cannot be read for other reasons - */ - void to(Sink sink) throws IOException, ArchiveException; - } - - /** - * Sets the source of entries to process. - * @param source the source - * @return a builder for the chain to be created and run - */ - public static ChainBuilder source(ArchiveEntrySource source) { - return new Builder(source); - } - - private static class Builder implements ChainBuilder { - private final ArchiveEntrySource source; - private ChainDefinition chainDef = new ChainDefinition<>(); - - Builder(ArchiveEntrySource source) { - this.source = source; - } - - @Override - public ChainBuilder filter(Filter filter) { - return withStep(filter); - } - @Override - public ChainBuilder skipUnreadable() { - return filter(source.skipUnreadable()); - } - @Override - public ChainBuilder skipDirectories() { - return filter(new Filter() { - @Override - public boolean accept(String entryName, ArchiveEntry e) { - return !e.isDirectory(); - } - }); - } - @Override - public ChainBuilder map(Transformer transformer) { - return withStep(transformer); - } - @Override - public ChainBuilder withStep(ChainStep step) { - chainDef.add(step); - return this; - } - @Override - public void to(Sink sink) throws IOException, ArchiveException { - chainDef.add(sink); - chainDef.freeze(); - new ChainRunner(source, chainDef, sink).run(); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ExpandCli.java b/src/org/apache/commons/compress/archivers/examples/ExpandCli.java deleted file mode 100644 index fd264ce82c1..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ExpandCli.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Simple command line tool that extracts an archive into a directory. - * - *

Usage: ExpandCli archive dir [format]

- * @since 1.17 - */ -public class ExpandCli { - - public static void main(String[] args) throws IOException, ArchiveException { - if (args.length < 2 || args.length > 3) { - System.err.println("Usage: ExpandCli dir archive [format]"); - System.exit(1); - } else if (args.length == 2) { - try (ArchiveEntrySource source = ArchiveSources.forFile(new File(args[0])).detectFormat()) { - Expand.source(source).to(new DirectorySink(new File(args[1]))); - } - } else { - try (ArchiveEntrySource source = ArchiveSources.forFile(new File(args[0])).withFormat(args[2])) { - Expand.source(source).to(new DirectorySink(new File(args[1]))); - } - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/examples/Expander.java b/src/org/apache/commons/compress/archivers/examples/Expander.java deleted file mode 100644 index 5644451f66c..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Expander.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.Enumeration; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.ArchiveStreamFactory; -import org.apache.commons.compress.archivers.sevenz.SevenZFile; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipFile; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Provides a high level API for expanding archives. - * @since 1.17 - */ -public class Expander { - - private interface ArchiveEntrySupplier { - ArchiveEntry getNextReadableEntry() throws IOException; - } - - private interface EntryWriter { - void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException; - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - *

Tries to auto-detect the archive's format.

- * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(File archive, File targetDirectory) throws IOException, ArchiveException { - String format = null; - try (InputStream i = new BufferedInputStream(Files.newInputStream(archive.toPath()))) { - format = new ArchiveStreamFactory().detect(i); - } - expand(format, archive, targetDirectory); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, File archive, File targetDirectory) throws IOException, ArchiveException { - if (prefersSeekableByteChannel(format)) { - try (SeekableByteChannel c = FileChannel.open(archive.toPath(), StandardOpenOption.READ)) { - expand(format, c, targetDirectory); - } - return; - } - try (InputStream i = new BufferedInputStream(Files.newInputStream(archive.toPath()))) { - expand(format, i, targetDirectory); - } - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - *

Tries to auto-detect the archive's format.

- * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(InputStream archive, File targetDirectory) throws IOException, ArchiveException { - expand(new ArchiveStreamFactory().createArchiveInputStream(archive), targetDirectory); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, InputStream archive, File targetDirectory) - throws IOException, ArchiveException { - expand(new ArchiveStreamFactory().createArchiveInputStream(format, archive), targetDirectory); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @param format the archive format. This uses the same format as - * accepted by {@link ArchiveStreamFactory}. - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(String format, SeekableByteChannel archive, File targetDirectory) - throws IOException, ArchiveException { - if (!prefersSeekableByteChannel(format)) { - expand(format, Channels.newInputStream(archive), targetDirectory); - } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) { - expand(new ZipFile(archive), targetDirectory); - } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) { - expand(new SevenZFile(archive), targetDirectory); - } else { - // never reached as prefersSeekableByteChannel only returns true for ZIP and 7z - throw new ArchiveException("don't know how to handle format " + format); - } - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(final ArchiveInputStream archive, File targetDirectory) - throws IOException, ArchiveException { - expand(new ArchiveEntrySupplier() { - @Override - public ArchiveEntry getNextReadableEntry() throws IOException { - ArchiveEntry next = archive.getNextEntry(); - while (next != null && !archive.canReadEntryData(next)) { - next = archive.getNextEntry(); - } - return next; - } - }, new EntryWriter() { - @Override - public void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException { - IOUtils.copy(archive, out); - } - }, targetDirectory); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(final ZipFile archive, File targetDirectory) - throws IOException, ArchiveException { - final Enumeration entries = archive.getEntries(); - expand(new ArchiveEntrySupplier() { - @Override - public ArchiveEntry getNextReadableEntry() throws IOException { - ZipArchiveEntry next = entries.hasMoreElements() ? entries.nextElement() : null; - while (next != null && !archive.canReadEntryData(next)) { - next = entries.hasMoreElements() ? entries.nextElement() : null; - } - return next; - } - }, new EntryWriter() { - @Override - public void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException { - try (InputStream in = archive.getInputStream((ZipArchiveEntry) entry)) { - IOUtils.copy(in, out); - } - } - }, targetDirectory); - } - - /** - * Expands {@code archive} into {@code targetDirectory}. - * - * @param archive the file to expand - * @param targetDirectory the directory to write to - * @throws IOException if an I/O error occurs - * @throws ArchiveException if the archive cannot be read for other reasons - */ - public void expand(final SevenZFile archive, File targetDirectory) - throws IOException, ArchiveException { - expand(new ArchiveEntrySupplier() { - @Override - public ArchiveEntry getNextReadableEntry() throws IOException { - return archive.getNextEntry(); - } - }, new EntryWriter() { - @Override - public void writeEntryDataTo(ArchiveEntry entry, OutputStream out) throws IOException { - final byte[] buffer = new byte[8024]; - int n = 0; - long count = 0; - while (-1 != (n = archive.read(buffer))) { - out.write(buffer, 0, n); - count += n; - } - } - }, targetDirectory); - } - - private boolean prefersSeekableByteChannel(String format) { - return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format); - } - - private void expand(ArchiveEntrySupplier supplier, EntryWriter writer, File targetDirectory) - throws IOException { - String targetDirPath = targetDirectory.getCanonicalPath() + File.separatorChar; - ArchiveEntry nextEntry = supplier.getNextReadableEntry(); - while (nextEntry != null) { - File f = new File(targetDirectory, nextEntry.getName()); - if (!f.getCanonicalPath().startsWith(targetDirPath)) { - throw new IOException("expanding " + nextEntry.getName() - + " would create file outside of " + targetDirectory); - } - if (nextEntry.isDirectory()) { - if (!f.isDirectory() && !f.mkdirs()) { - throw new IOException("failed to create directory " + f); - } - } else { - File parent = f.getParentFile(); - if (!parent.isDirectory() && !parent.mkdirs()) { - throw new IOException("failed to create directory " + parent); - } - try (OutputStream o = Files.newOutputStream(f.toPath())) { - writer.writeEntryDataTo(nextEntry, o); - } - } - nextEntry = supplier.getNextReadableEntry(); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/examples/FileFilterAdapter.java b/src/org/apache/commons/compress/archivers/examples/FileFilterAdapter.java deleted file mode 100644 index 9f5a8464587..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/FileFilterAdapter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.FileFilter; - -/** - * @since 1.17 - */ -public class FileFilterAdapter extends Filter { - private final FileFilter filter; - public FileFilterAdapter(FileFilter f) { - filter = f; - } - - @Override - public boolean accept(String entryName, File entry) { - return filter.accept(entry); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/FileToArchiveSink.java b/src/org/apache/commons/compress/archivers/examples/FileToArchiveSink.java deleted file mode 100644 index 7f9fa3d4776..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/FileToArchiveSink.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Sink that creates an archive from files. - * @since 1.17 - */ -public class FileToArchiveSink extends Sink { - private final ArchiveOutputStream os; - - /** - * Wraps an ArchiveOutputStream. - * - * @param os the stream to write to - */ - public FileToArchiveSink(ArchiveOutputStream os) { - this.os = os; - } - - @Override - public void consume(ChainPayload payload) throws IOException, ArchiveException { - ArchiveEntry e = os.createArchiveEntry(payload.getEntry(), payload.getEntryName()); - os.putArchiveEntry(e); - if (!payload.getEntry().isDirectory()) { - try (InputStream in = new BufferedInputStream(payload.getInput().get())) { - IOUtils.copy(in, os); - } - } - os.closeArchiveEntry(); - } - - @Override - public void finish() throws IOException { - os.finish(); - } - - @Override - public void close() throws IOException { - os.close(); - } - -} diff --git a/src/org/apache/commons/compress/archivers/examples/Filter.java b/src/org/apache/commons/compress/archivers/examples/Filter.java deleted file mode 100644 index 84e670cd4b7..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Filter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Filtering stage of a {@link Expand} or {@link Archive} chain. - * @since 1.17 - */ -public abstract class Filter implements ChainStep { - /** - * Decides whether to process an entry or not. - * - * @param entryName name of the entry - * @param entry the entry - * @return true if the entry shall be processed. - */ - public abstract boolean accept(String entryName, T entry); - - @Override - public void process(ChainPayload payload, Chain chain) throws IOException, ArchiveException { - if (accept(payload.getEntryName(), payload.getEntry())) { - chain.next(payload); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ListerCli.java b/src/org/apache/commons/compress/archivers/examples/ListerCli.java deleted file mode 100644 index 36f6efab2c3..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ListerCli.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * Simple command line application that lists the contents of an archive. - * - *

The name of the archive must be given as a command line argument.

- *

The optional second argument defines the archive type, in case the format is not recognized.

- * - * @since 1.17 - */ -public final class ListerCli { - - public static void main(final String[] args) throws Exception { - if (args.length == 0) { - usage(); - return; - } - System.out.println("Analysing " + args[0]); - final Sink sink = new Sink() { - @Override - public void consume(ChainPayload payload) { - System.out.println(payload.getEntry().getName()); - } - @Override - public void close() { - } - }; - - final File f = new File(args[0]); - if (!f.isFile()) { - System.err.println(f + " doesn't exist or is a directory"); - } else if (args.length == 1) { - try (ArchiveEntrySource source = ArchiveSources.forFile(f).detectFormat()) { - Expand.source(source).to(sink); - } - } else { - try (ArchiveEntrySource source = ArchiveSources.forFile(f).withFormat(args[1])) { - Expand.source(source).to(sink); - } - } - } - - private static void usage() { - System.out.println("Parameters: archive-name [archive-type]"); - } - -} diff --git a/src/org/apache/commons/compress/archivers/examples/SevenZArchiveEntrySource.java b/src/org/apache/commons/compress/archivers/examples/SevenZArchiveEntrySource.java deleted file mode 100644 index 9f38b386b87..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/SevenZArchiveEntrySource.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.channels.SeekableByteChannel; -import java.util.NoSuchElementException; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.utils.NoCloseInputStream; -import org.apache.commons.compress.archivers.sevenz.SevenZFile; - -/** - * Supplier based on {@link SevenZFile}s. - * @since 1.17 - */ -public class SevenZArchiveEntrySource implements ArchiveEntrySource { - - private final SevenZFile sf; - - public SevenZArchiveEntrySource(File f) throws IOException { - this(new SevenZFile(f)); - } - - public SevenZArchiveEntrySource(SeekableByteChannel c) throws IOException { - this(new SevenZFile(c)); - } - - public SevenZArchiveEntrySource(SevenZFile sf) { - this.sf = sf; - } - - @Override - public ThrowingIterator> get() throws IOException { - return new SevenZFileIterator(sf); - } - - @Override - public void close() throws IOException { - sf.close(); - } - - @Override - public Filter skipUnreadable() { - return new Filter() { - @Override - public boolean accept(String entryName, ArchiveEntry entry) { - return true; - } - }; - } - - private static class SevenZFileIterator implements ThrowingIterator> { - private final SevenZFile sf; - private ArchiveEntry nextEntry; - private boolean nextEntryConsumed; - SevenZFileIterator(SevenZFile sf) throws IOException { - this.sf = sf; - nextEntry = sf.getNextEntry(); - nextEntryConsumed = false; - } - - @Override - public boolean hasNext() throws IOException { - if (nextEntry == null || nextEntryConsumed) { - nextEntry = sf.getNextEntry(); - nextEntryConsumed = false; - } - return nextEntry != null && !nextEntryConsumed; - } - - @Override - public ChainPayload next() throws IOException { - if (!hasNext()) { - throw new NoSuchElementException(); - } - nextEntryConsumed = true; - return new ChainPayload(nextEntry, nextEntry.getName(), new Supplier() { - @Override - public InputStream get() throws IOException { - return new SevenZFileInputStream(sf); - } - }); - } - - } - - private static class SevenZFileInputStream extends InputStream { - private final SevenZFile sf; - SevenZFileInputStream(SevenZFile sf) { - this.sf = sf; - } - @Override - public int read() throws IOException { - return sf.read(); - } - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - return sf.read(b, off, len); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/SevenZOutputFileSink.java b/src/org/apache/commons/compress/archivers/examples/SevenZOutputFileSink.java deleted file mode 100644 index f9a1e14e95a..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/SevenZOutputFileSink.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.channels.SeekableByteChannel; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Sink that creates a 7z archive from files. - * @since 1.17 - */ -public class SevenZOutputFileSink extends Sink { - - private final SevenZOutputFile outFile; - - public SevenZOutputFileSink(File f) throws IOException { - this(new SevenZOutputFile(f)); - } - - public SevenZOutputFileSink(SeekableByteChannel c) throws IOException { - this(new SevenZOutputFile(c)); - } - - public SevenZOutputFileSink(SevenZOutputFile outFile) { - this.outFile = outFile; - } - - @Override - public void consume(ChainPayload payload) throws IOException, ArchiveException { - ArchiveEntry e = outFile.createArchiveEntry(payload.getEntry(), payload.getEntryName()); - outFile.putArchiveEntry(e); - if (!payload.getEntry().isDirectory()) { - final byte[] buffer = new byte[8024]; - int n = 0; - long count = 0; - try (InputStream in = new BufferedInputStream(payload.getInput().get())) { - while (-1 != (n = in.read(buffer))) { - outFile.write(buffer, 0, n); - count += n; - } - } - } - outFile.closeArchiveEntry(); - } - - @Override - public void finish() throws IOException { - outFile.finish(); - } - - @Override - public void close() throws IOException { - outFile.close(); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/Sink.java b/src/org/apache/commons/compress/archivers/examples/Sink.java deleted file mode 100644 index 7e143696f59..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Sink.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.Closeable; -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Final stage of a {@link Expand} or {@link Archive} chain. - * @since 1.17 - */ -public abstract class Sink implements ChainStep, Closeable { - /** - * Consume a single entry. - * - * @param payload the entry to consume - * @throws IOException if an I/O error occurs - * @throws ArchiveException if an archive format related error occurs - */ - public abstract void consume(ChainPayload payload) throws IOException, ArchiveException; - - /** - * Is invoked once all entries have been processed. - * - *

This implementation is empty. - * - * @throws IOException if an I/O error occurs - * @throws ArchiveException if an archive format related error occurs - */ - public void finish() throws IOException, ArchiveException { - } - - @Override - public void process(ChainPayload payload, Chain chain) throws IOException, ArchiveException { - consume(payload); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/Source.java b/src/org/apache/commons/compress/archivers/examples/Source.java deleted file mode 100644 index 4a51efe237b..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Source.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.Closeable; - -/** - * Describes the contract of a source for {@link Archive} or {@link Expand}. - * @since 1.17 - */ -public interface Source extends Supplier>>, Closeable { -} diff --git a/src/org/apache/commons/compress/archivers/examples/StreamBasedArchiveEntrySource.java b/src/org/apache/commons/compress/archivers/examples/StreamBasedArchiveEntrySource.java deleted file mode 100644 index 19aa55b5174..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/StreamBasedArchiveEntrySource.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import java.io.InputStream; -import java.util.NoSuchElementException; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveException; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.ArchiveStreamFactory; -import org.apache.commons.compress.utils.NoCloseInputStream; - -/** - * Supplier based on {@link ArchiveInputStream}s. - * @since 1.17 - */ -public class StreamBasedArchiveEntrySource implements ArchiveEntrySource { - - private final ArchiveInputStream in; - - public StreamBasedArchiveEntrySource(ArchiveInputStream in) { - this.in = in; - } - - @Override - public ThrowingIterator> get() throws IOException { - return new ArchiveInputStreamIterator(in); - } - - @Override - public void close() throws IOException { - in.close(); - } - - @Override - public Filter skipUnreadable() { - return new Filter() { - @Override - public boolean accept(String entryName, ArchiveEntry entry) { - return in.canReadEntryData(entry); - } - }; - } - - private static class ArchiveInputStreamIterator implements ThrowingIterator> { - private final ArchiveInputStream in; - private ArchiveEntry nextEntry; - private boolean nextEntryConsumed; - ArchiveInputStreamIterator(ArchiveInputStream in) throws IOException { - this.in = in; - nextEntry = in.getNextEntry(); - nextEntryConsumed = false; - } - - @Override - public boolean hasNext() throws IOException { - if (nextEntry == null || nextEntryConsumed) { - nextEntry = in.getNextEntry(); - nextEntryConsumed = false; - } - return nextEntry != null && !nextEntryConsumed; - } - - @Override - public ChainPayload next() throws IOException { - if (!hasNext()) { - throw new NoSuchElementException(); - } - nextEntryConsumed = true; - return new ChainPayload(nextEntry, nextEntry.getName(), new Supplier() { - @Override - public InputStream get() throws IOException { - return new NoCloseInputStream(in); - } - }); - } - - } - -} diff --git a/src/org/apache/commons/compress/archivers/examples/Supplier.java b/src/org/apache/commons/compress/archivers/examples/Supplier.java deleted file mode 100644 index aba61133d37..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Supplier.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Used inside of {@link ChainPayload} as well as {@link Archive} and {@link Expand}. - * @since 1.12 - */ -public interface Supplier { - /** - * Supplies the object. - * - * @throws IOException if an I/O error occurs - * @throws ArchiveException if an archive format related error occurs - * @return the asked for object - */ - T get() throws IOException, ArchiveException; -} diff --git a/src/org/apache/commons/compress/archivers/examples/ThrowingIterator.java b/src/org/apache/commons/compress/archivers/examples/ThrowingIterator.java deleted file mode 100644 index 4a7bad8543a..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ThrowingIterator.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Specialized iterator that is allowed to throw Exceptions. - */ -public interface ThrowingIterator { - boolean hasNext() throws IOException, ArchiveException; - T next() throws IOException, ArchiveException; -} diff --git a/src/org/apache/commons/compress/archivers/examples/Transformer.java b/src/org/apache/commons/compress/archivers/examples/Transformer.java deleted file mode 100644 index b09167854b3..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/Transformer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.IOException; -import org.apache.commons.compress.archivers.ArchiveException; - -/** - * Transforming stage of a {@link Expand} or {@link Archive} chain. - * @since 1.17 - */ -public abstract class Transformer implements ChainStep { - /** - * Transforms an entry. - * - * @param entry the entry - * @return the transformed entry - */ - public abstract ChainPayload transform(ChainPayload entry); - - @Override - public void process(ChainPayload payload, Chain chain) throws IOException, ArchiveException { - chain.next(transform(payload)); - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/ZipArchiveEntrySource.java b/src/org/apache/commons/compress/archivers/examples/ZipArchiveEntrySource.java deleted file mode 100644 index d5e84bcb74e..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/ZipArchiveEntrySource.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.examples; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.channels.SeekableByteChannel; -import java.util.Enumeration; -import java.util.NoSuchElementException; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipFile; - -/** - * Supplier based on {@link ZipFile}s. - * @since 1.17 - */ -public class ZipArchiveEntrySource implements ArchiveEntrySource { - - private final ZipFile zf; - - public ZipArchiveEntrySource(File f) throws IOException { - this(new ZipFile(f)); - } - - public ZipArchiveEntrySource(SeekableByteChannel c) throws IOException { - this(new ZipFile(c)); - } - - public ZipArchiveEntrySource(ZipFile file) { - zf = file; - } - - @Override - public ThrowingIterator> get() throws IOException { - return new ZipFileIterator(zf, zf.getEntries()); - } - - @Override - public void close() throws IOException { - zf.close(); - } - - @Override - public Filter skipUnreadable() { - return new Filter() { - @Override - public boolean accept(String entryName, ArchiveEntry entry) { - return entry instanceof ZipArchiveEntry && zf.canReadEntryData((ZipArchiveEntry) entry); - } - }; - } - - private static class ZipFileIterator implements ThrowingIterator> { - private final ZipFile zf; - private final Enumeration iter; - ZipFileIterator(ZipFile zf, Enumeration iter) { - this.zf = zf; - this.iter = iter; - } - - @Override - public boolean hasNext() throws IOException { - return iter.hasMoreElements(); - } - - @Override - public ChainPayload next() throws IOException { - final ZipArchiveEntry z = iter.nextElement(); - return new ChainPayload(z, z.getName(), new Supplier() { - @Override - public InputStream get() throws IOException { - return zf.getInputStream(z); - } - }); - } - - } -} diff --git a/src/org/apache/commons/compress/archivers/examples/package.html b/src/org/apache/commons/compress/archivers/examples/package.html deleted file mode 100644 index 443d5fc8fc7..00000000000 --- a/src/org/apache/commons/compress/archivers/examples/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - -

Contains example code that is not guaranteed to provide a - stable API across releases of Commons Compress.

- - - diff --git a/src/org/apache/commons/compress/archivers/jar/JarArchiveEntry.java b/src/org/apache/commons/compress/archivers/jar/JarArchiveEntry.java deleted file mode 100644 index f0c05f046a4..00000000000 --- a/src/org/apache/commons/compress/archivers/jar/JarArchiveEntry.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.jar; - -import java.security.cert.Certificate; -import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; - -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; - -/** - * - * @NotThreadSafe (parent is not thread-safe) - */ -public class JarArchiveEntry extends ZipArchiveEntry { - - // These are always null - see https://issues.apache.org/jira/browse/COMPRESS-18 for discussion - private final Attributes manifestAttributes = null; - private final Certificate[] certificates = null; - - public JarArchiveEntry(final ZipEntry entry) throws ZipException { - super(entry); - } - - public JarArchiveEntry(final String name) { - super(name); - } - - public JarArchiveEntry(final ZipArchiveEntry entry) throws ZipException { - super(entry); - } - - public JarArchiveEntry(final JarEntry entry) throws ZipException { - super(entry); - - } - - /** - * This method is not implemented and won't ever be. - * The JVM equivalent has a different name {@link java.util.jar.JarEntry#getAttributes()} - * - * @deprecated since 1.5, do not use; always returns null - * @return Always returns null. - */ - @Deprecated - public Attributes getManifestAttributes() { - return manifestAttributes; - } - - /** - * Return a copy of the list of certificates or null if there are none. - * - * @return Always returns null in the current implementation - * - * @deprecated since 1.5, not currently implemented - */ - @Deprecated - public Certificate[] getCertificates() { - if (certificates != null) { // never true currently // NOSONAR - final Certificate[] certs = new Certificate[certificates.length]; - System.arraycopy(certificates, 0, certs, 0, certs.length); - return certs; - } - /* - * Note, the method - * Certificate[] java.util.jar.JarEntry.getCertificates() - * also returns null or the list of certificates (but not copied) - */ - return null; - } - -} diff --git a/src/org/apache/commons/compress/archivers/jar/JarArchiveInputStream.java b/src/org/apache/commons/compress/archivers/jar/JarArchiveInputStream.java deleted file mode 100644 index 47b1583ca48..00000000000 --- a/src/org/apache/commons/compress/archivers/jar/JarArchiveInputStream.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.jar; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; - -/** - * Implements an input stream that can read entries from jar files. - * - * @NotThreadSafe - */ -public class JarArchiveInputStream extends ZipArchiveInputStream { - - /** - * Creates an instance from the input stream using the default encoding. - * - * @param inputStream the input stream to wrap - */ - public JarArchiveInputStream( final InputStream inputStream ) { - super(inputStream); - } - - /** - * Creates an instance from the input stream using the specified encoding. - * - * @param inputStream the input stream to wrap - * @param encoding the encoding to use - * @since 1.10 - */ - public JarArchiveInputStream( final InputStream inputStream, final String encoding ) { - super(inputStream, encoding); - } - - public JarArchiveEntry getNextJarEntry() throws IOException { - final ZipArchiveEntry entry = getNextZipEntry(); - return entry == null ? null : new JarArchiveEntry(entry); - } - - @Override - public ArchiveEntry getNextEntry() throws IOException { - return getNextJarEntry(); - } - - /** - * Checks if the signature matches what is expected for a jar file - * (in this case it is the same as for a zip file). - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is a jar archive stream, false otherwise - */ - public static boolean matches(final byte[] signature, final int length ) { - return ZipArchiveInputStream.matches(signature, length); - } -} diff --git a/src/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java b/src/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java deleted file mode 100644 index 5e2c7a8e576..00000000000 --- a/src/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.jar; - -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.zip.JarMarker; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; - -/** - * Subclass that adds a special extra field to the very first entry - * which allows the created archive to be used as an executable jar on - * Solaris. - * - * @NotThreadSafe - */ -public class JarArchiveOutputStream extends ZipArchiveOutputStream { - - private boolean jarMarkerAdded = false; - - public JarArchiveOutputStream(final OutputStream out) { - super(out); - } - - /** - * Create and instance that wraps the output stream using the provided encoding. - * - * @param out the output stream to wrap - * @param encoding the encoding to use. Use null for the platform default. - * @since 1.10 - */ - public JarArchiveOutputStream(final OutputStream out, final String encoding) { - super(out); - setEncoding(encoding); - } - - // @throws ClassCastException if entry is not an instance of ZipArchiveEntry - @Override - public void putArchiveEntry(final ArchiveEntry ze) throws IOException { - if (!jarMarkerAdded) { - ((ZipArchiveEntry)ze).addAsFirstExtraField(JarMarker.getInstance()); - jarMarkerAdded = true; - } - super.putArchiveEntry(ze); - } -} diff --git a/src/org/apache/commons/compress/archivers/jar/package.html b/src/org/apache/commons/compress/archivers/jar/package.html deleted file mode 100644 index 09829ae6a8a..00000000000 --- a/src/org/apache/commons/compress/archivers/jar/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - -

Provides stream classes for reading and writing archives using - the ZIP format with some extensions for the special case of JAR - archives.

- - diff --git a/src/org/apache/commons/compress/archivers/package.html b/src/org/apache/commons/compress/archivers/package.html deleted file mode 100644 index df1922b4a10..00000000000 --- a/src/org/apache/commons/compress/archivers/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides a unified API and factories for dealing with archives - in different formats.

- - diff --git a/src/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java b/src/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java deleted file mode 100644 index aca9777fd85..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.IOException; -import java.io.InputStream; -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import org.apache.commons.compress.PasswordRequiredException; - -class AES256SHA256Decoder extends CoderBase { - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] passwordBytes) throws IOException { - return new InputStream() { - private boolean isInitialized = false; - private CipherInputStream cipherInputStream = null; - - private CipherInputStream init() throws IOException { - if (isInitialized) { - return cipherInputStream; - } - final int byte0 = 0xff & coder.properties[0]; - final int numCyclesPower = byte0 & 0x3f; - final int byte1 = 0xff & coder.properties[1]; - final int ivSize = ((byte0 >> 6) & 1) + (byte1 & 0x0f); - final int saltSize = ((byte0 >> 7) & 1) + (byte1 >> 4); - if (2 + saltSize + ivSize > coder.properties.length) { - throw new IOException("Salt size + IV size too long in " + archiveName); - } - final byte[] salt = new byte[saltSize]; - System.arraycopy(coder.properties, 2, salt, 0, saltSize); - final byte[] iv = new byte[16]; - System.arraycopy(coder.properties, 2 + saltSize, iv, 0, ivSize); - - if (passwordBytes == null) { - throw new PasswordRequiredException(archiveName); - } - final byte[] aesKeyBytes; - if (numCyclesPower == 0x3f) { - aesKeyBytes = new byte[32]; - System.arraycopy(salt, 0, aesKeyBytes, 0, saltSize); - System.arraycopy(passwordBytes, 0, aesKeyBytes, saltSize, - Math.min(passwordBytes.length, aesKeyBytes.length - saltSize)); - } else { - final MessageDigest digest; - try { - digest = MessageDigest.getInstance("SHA-256"); - } catch (final NoSuchAlgorithmException noSuchAlgorithmException) { - throw new IOException("SHA-256 is unsupported by your Java implementation", - noSuchAlgorithmException); - } - final byte[] extra = new byte[8]; - for (long j = 0; j < (1L << numCyclesPower); j++) { - digest.update(salt); - digest.update(passwordBytes); - digest.update(extra); - for (int k = 0; k < extra.length; k++) { - ++extra[k]; - if (extra[k] != 0) { - break; - } - } - } - aesKeyBytes = digest.digest(); - } - - final SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES"); - try { - final Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv)); - cipherInputStream = new CipherInputStream(in, cipher); - isInitialized = true; - return cipherInputStream; - } catch (final GeneralSecurityException generalSecurityException) { - throw new IOException("Decryption error " + - "(do you have the JCE Unlimited Strength Jurisdiction Policy Files installed?)", - generalSecurityException); - } - } - - @Override - public int read() throws IOException { - return init().read(); - } - - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - return init().read(b, off, len); - } - - @Override - public void close() { - } - }; - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/Archive.java b/src/org/apache/commons/compress/archivers/sevenz/Archive.java deleted file mode 100644 index dd1c75aa210..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/Archive.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.util.BitSet; - -class Archive { - /// Offset from beginning of file + SIGNATURE_HEADER_SIZE to packed streams. - long packPos; - /// Size of each packed stream. - long[] packSizes; - /// Whether each particular packed streams has a CRC. - BitSet packCrcsDefined; - /// CRCs for each packed stream, valid only if that packed stream has one. - long[] packCrcs; - /// Properties of solid compression blocks. - Folder[] folders; - /// Temporary properties for non-empty files (subsumed into the files array later). - SubStreamsInfo subStreamsInfo; - /// The files and directories in the archive. - SevenZArchiveEntry[] files; - /// Mapping between folders, files and streams. - StreamMap streamMap; - - @Override - public String toString() { - return "Archive with packed streams starting at offset " + packPos - + ", " + lengthOf(packSizes) + " pack sizes, " + lengthOf(packCrcs) - + " CRCs, " + lengthOf(folders) + " folders, " + lengthOf(files) - + " files and " + streamMap; - } - - private static String lengthOf(final long[] a) { - return a == null ? "(null)" : String.valueOf(a.length); - } - - private static String lengthOf(final Object[] a) { - return a == null ? "(null)" : String.valueOf(a.length); - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/BindPair.java b/src/org/apache/commons/compress/archivers/sevenz/BindPair.java deleted file mode 100644 index 2710b72ff43..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/BindPair.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -class BindPair { - long inIndex; - long outIndex; - - @Override - public String toString() { - return "BindPair binding input " + inIndex + " to output " + outIndex; - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/BoundedSeekableByteChannelInputStream.java b/src/org/apache/commons/compress/archivers/sevenz/BoundedSeekableByteChannelInputStream.java deleted file mode 100644 index 32b3bda7bd7..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/BoundedSeekableByteChannelInputStream.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.SeekableByteChannel; - -class BoundedSeekableByteChannelInputStream extends InputStream { - private static final int MAX_BUF_LEN = 8192; - private final ByteBuffer buffer; - private final SeekableByteChannel channel; - private long bytesRemaining; - - public BoundedSeekableByteChannelInputStream(final SeekableByteChannel channel, - final long size) { - this.channel = channel; - this.bytesRemaining = size; - if (size < MAX_BUF_LEN && size > 0) { - buffer = ByteBuffer.allocate((int) size); - } else { - buffer = ByteBuffer.allocate(MAX_BUF_LEN); - } - } - - @Override - public int read() throws IOException { - if (bytesRemaining > 0) { - --bytesRemaining; - int read = read(1); - if (read < 0) { - return read; - } - return buffer.get() & 0xff; - } - return -1; - } - - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (bytesRemaining == 0) { - return -1; - } - int bytesToRead = len; - if (bytesToRead > bytesRemaining) { - bytesToRead = (int) bytesRemaining; - } - int bytesRead; - ByteBuffer buf; - if (bytesToRead <= buffer.capacity()) { - buf = buffer; - bytesRead = read(bytesToRead); - } else { - buf = ByteBuffer.allocate(bytesToRead); - bytesRead = channel.read(buf); - buf.flip(); - } - if (bytesRead >= 0) { - buf.get(b, off, bytesRead); - bytesRemaining -= bytesRead; - } - return bytesRead; - } - - private int read(int len) throws IOException { - buffer.rewind().limit(len); - int read = channel.read(buffer); - buffer.flip(); - return read; - } - - @Override - public void close() { - // the nested channel is controlled externally - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/CLI.java b/src/org/apache/commons/compress/archivers/sevenz/CLI.java deleted file mode 100644 index a40f2b318f4..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/CLI.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -public class CLI { - - - private enum Mode { - LIST("Analysing") { - @Override - public void takeAction(final SevenZFile archive, final SevenZArchiveEntry entry) { - System.out.print(entry.getName()); - if (entry.isDirectory()) { - System.out.print(" dir"); - } else { - System.out.print(" " + entry.getCompressedSize() - + "/" + entry.getSize()); - } - if (entry.getHasLastModifiedDate()) { - System.out.print(" " + entry.getLastModifiedDate()); - } else { - System.out.print(" no last modified date"); - } - if (!entry.isDirectory()) { - System.out.println(" " + getContentMethods(entry)); - } else { - System.out.println(""); - } - } - - private String getContentMethods(final SevenZArchiveEntry entry) { - final StringBuilder sb = new StringBuilder(); - boolean first = true; - for (final SevenZMethodConfiguration m : entry.getContentMethods()) { - if (!first) { - sb.append(", "); - } - first = false; - sb.append(m.getMethod()); - if (m.getOptions() != null) { - sb.append("(").append(m.getOptions()).append(")"); - } - } - return sb.toString(); - } - }, - EXTRACT("Extracting") { - private final byte[] buf = new byte[8192]; - @Override - public void takeAction(final SevenZFile archive, final SevenZArchiveEntry entry) - throws IOException { - final File outFile = new File(entry.getName()); - if (entry.isDirectory()) { - if (!outFile.isDirectory() && !outFile.mkdirs()) { - throw new IOException("Cannot create directory " + outFile); - } - System.out.println("created directory " + outFile); - return; - } - - System.out.println("extracting to " + outFile); - final File parent = outFile.getParentFile(); - if (parent != null && !parent.exists() && !parent.mkdirs()) { - throw new IOException("Cannot create " + parent); - } - try (final FileOutputStream fos = new FileOutputStream(outFile)) { - final long total = entry.getSize(); - long off = 0; - while (off < total) { - final int toRead = (int) Math.min(total - off, buf.length); - final int bytesRead = archive.read(buf, 0, toRead); - if (bytesRead < 1) { - throw new IOException("reached end of entry " - + entry.getName() - + " after " + off - + " bytes, expected " - + total); - } - off += bytesRead; - fos.write(buf, 0, bytesRead); - } - } - } - }; - - private final String message; - Mode(final String message) { - this.message = message; - } - public String getMessage() { - return message; - } - public abstract void takeAction(SevenZFile archive, SevenZArchiveEntry entry) - throws IOException; - } - - public static void main(final String[] args) throws Exception { - if (args.length == 0) { - usage(); - return; - } - final Mode mode = grabMode(args); - System.out.println(mode.getMessage() + " " + args[0]); - final File f = new File(args[0]); - if (!f.isFile()) { - System.err.println(f + " doesn't exist or is a directory"); - } - try (final SevenZFile archive = new SevenZFile(f)) { - SevenZArchiveEntry ae; - while((ae=archive.getNextEntry()) != null) { - mode.takeAction(archive, ae); - } - } - } - - private static void usage() { - System.out.println("Parameters: archive-name [list|extract]"); - } - - private static Mode grabMode(final String[] args) { - if (args.length < 2) { - return Mode.LIST; - } - return Enum.valueOf(Mode.class, args[1].toUpperCase()); - } - -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/Coder.java b/src/org/apache/commons/compress/archivers/sevenz/Coder.java deleted file mode 100644 index cbd271d1df6..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/Coder.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -class Coder { - byte[] decompressionMethodId; - long numInStreams; - long numOutStreams; - byte[] properties = null; -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/CoderBase.java b/src/org/apache/commons/compress/archivers/sevenz/CoderBase.java deleted file mode 100644 index 38425139527..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/CoderBase.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Base Codec class. - */ -abstract class CoderBase { - private final Class[] acceptableOptions; - private static final byte[] NONE = new byte[0]; - - /** - * @param acceptableOptions types that can be used as options for this codec. - */ - protected CoderBase(final Class... acceptableOptions) { - this.acceptableOptions = acceptableOptions; - } - - /** - * @return whether this method can extract options from the given object. - */ - boolean canAcceptOptions(final Object opts) { - for (final Class c : acceptableOptions) { - if (c.isInstance(opts)) { - return true; - } - } - return false; - } - - /** - * @return property-bytes to write in a Folder block - */ - byte[] getOptionsAsProperties(final Object options) throws IOException { - return NONE; - } - - /** - * @return configuration options that have been used to create the given InputStream from the given Coder - */ - Object getOptionsFromCoder(final Coder coder, final InputStream in) throws IOException { - return null; - } - - /** - * @return a stream that reads from in using the configured coder and password. - */ - abstract InputStream decode(final String archiveName, - final InputStream in, long uncomressedLength, - final Coder coder, byte[] password) throws IOException; - - /** - * @return a stream that writes to out using the given configuration. - */ - OutputStream encode(final OutputStream out, final Object options) throws IOException { - throw new UnsupportedOperationException("method doesn't support writing"); - } - - /** - * If the option represents a number, return its integer - * value, otherwise return the given default value. - */ - protected static int numberOptionOrDefault(final Object options, final int defaultValue) { - return options instanceof Number ? ((Number) options).intValue() : defaultValue; - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/Coders.java b/src/org/apache/commons/compress/archivers/sevenz/Coders.java deleted file mode 100644 index 729a1a3d8d3..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/Coders.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.SequenceInputStream; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; -import org.apache.commons.compress.compressors.deflate64.Deflate64CompressorInputStream; -import org.apache.commons.compress.utils.FlushShieldFilterOutputStream; -import org.tukaani.xz.ARMOptions; -import org.tukaani.xz.ARMThumbOptions; -import org.tukaani.xz.FilterOptions; -import org.tukaani.xz.FinishableWrapperOutputStream; -import org.tukaani.xz.IA64Options; -import org.tukaani.xz.PowerPCOptions; -import org.tukaani.xz.SPARCOptions; -import org.tukaani.xz.X86Options; - -class Coders { - private static final Map CODER_MAP = new HashMap() { - - private static final long serialVersionUID = 1664829131806520867L; - { - put(SevenZMethod.COPY, new CopyDecoder()); - put(SevenZMethod.LZMA, new LZMADecoder()); - put(SevenZMethod.LZMA2, new LZMA2Decoder()); - put(SevenZMethod.DEFLATE, new DeflateDecoder()); - put(SevenZMethod.DEFLATE64, new Deflate64Decoder()); - put(SevenZMethod.BZIP2, new BZIP2Decoder()); - put(SevenZMethod.AES256SHA256, new AES256SHA256Decoder()); - put(SevenZMethod.BCJ_X86_FILTER, new BCJDecoder(new X86Options())); - put(SevenZMethod.BCJ_PPC_FILTER, new BCJDecoder(new PowerPCOptions())); - put(SevenZMethod.BCJ_IA64_FILTER, new BCJDecoder(new IA64Options())); - put(SevenZMethod.BCJ_ARM_FILTER, new BCJDecoder(new ARMOptions())); - put(SevenZMethod.BCJ_ARM_THUMB_FILTER, new BCJDecoder(new ARMThumbOptions())); - put(SevenZMethod.BCJ_SPARC_FILTER, new BCJDecoder(new SPARCOptions())); - put(SevenZMethod.DELTA_FILTER, new DeltaDecoder()); - }}; - - static CoderBase findByMethod(final SevenZMethod method) { - return CODER_MAP.get(method); - } - - static InputStream addDecoder(final String archiveName, final InputStream is, final long uncompressedLength, - final Coder coder, final byte[] password) throws IOException { - final CoderBase cb = findByMethod(SevenZMethod.byId(coder.decompressionMethodId)); - if (cb == null) { - throw new IOException("Unsupported compression method " + - Arrays.toString(coder.decompressionMethodId) - + " used in " + archiveName); - } - return cb.decode(archiveName, is, uncompressedLength, coder, password); - } - - static OutputStream addEncoder(final OutputStream out, final SevenZMethod method, - final Object options) throws IOException { - final CoderBase cb = findByMethod(method); - if (cb == null) { - throw new IOException("Unsupported compression method " + method); - } - return cb.encode(out, options); - } - - static class CopyDecoder extends CoderBase { - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) throws IOException { - return in; - } - @Override - OutputStream encode(final OutputStream out, final Object options) { - return out; - } - } - - static class BCJDecoder extends CoderBase { - private final FilterOptions opts; - BCJDecoder(final FilterOptions opts) { - this.opts = opts; - } - - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) throws IOException { - try { - return opts.getInputStream(in); - } catch (final AssertionError e) { - throw new IOException("BCJ filter used in " + archiveName - + " needs XZ for Java > 1.4 - see " - + "https://commons.apache.org/proper/commons-compress/limitations.html#7Z", - e); - } - } - - @SuppressWarnings("resource") - @Override - OutputStream encode(final OutputStream out, final Object options) { - return new FlushShieldFilterOutputStream(opts.getOutputStream(new FinishableWrapperOutputStream(out))); - } - } - - static class DeflateDecoder extends CoderBase { - private static final byte[] ONE_ZERO_BYTE = new byte[1]; - DeflateDecoder() { - super(Number.class); - } - - @SuppressWarnings("resource") // caller must close the InputStream - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) - throws IOException { - final Inflater inflater = new Inflater(true); - // Inflater with nowrap=true has this odd contract for a zero padding - // byte following the data stream; this used to be zlib's requirement - // and has been fixed a long time ago, but the contract persists so - // we comply. - // https://docs.oracle.com/javase/7/docs/api/java/util/zip/Inflater.html#Inflater(boolean) - final InflaterInputStream inflaterInputStream = new InflaterInputStream(new SequenceInputStream(in, - new ByteArrayInputStream(ONE_ZERO_BYTE)), inflater); - return new DeflateDecoderInputStream(inflaterInputStream, inflater); - } - @Override - OutputStream encode(final OutputStream out, final Object options) { - final int level = numberOptionOrDefault(options, 9); - final Deflater deflater = new Deflater(level, true); - final DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(out, deflater); - return new DeflateDecoderOutputStream(deflaterOutputStream, deflater); - } - - static class DeflateDecoderInputStream extends InputStream { - - InflaterInputStream inflaterInputStream; - Inflater inflater; - - public DeflateDecoderInputStream(InflaterInputStream inflaterInputStream, - Inflater inflater) { - this.inflaterInputStream = inflaterInputStream; - this.inflater = inflater; - } - - @Override - public int read() throws IOException { - return inflaterInputStream.read(); - } - - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - return inflaterInputStream.read(b, off, len); - } - - @Override - public int read(final byte[] b) throws IOException { - return inflaterInputStream.read(b); - } - - @Override - public void close() throws IOException { - try { - inflaterInputStream.close(); - } finally { - inflater.end(); - } - } - } - - static class DeflateDecoderOutputStream extends OutputStream { - - DeflaterOutputStream deflaterOutputStream; - Deflater deflater; - - public DeflateDecoderOutputStream(DeflaterOutputStream deflaterOutputStream, - Deflater deflater) { - this.deflaterOutputStream = deflaterOutputStream; - this.deflater = deflater; - } - - @Override - public void write(final int b) throws IOException { - deflaterOutputStream.write(b); - } - - @Override - public void write(final byte[] b) throws IOException { - deflaterOutputStream.write(b); - } - - @Override - public void write(final byte[] b, final int off, final int len) throws IOException { - deflaterOutputStream.write(b, off, len); - } - - @Override - public void close() throws IOException { - try { - deflaterOutputStream.close(); - } finally { - deflater.end(); - } - } - } - } - - static class Deflate64Decoder extends CoderBase { - Deflate64Decoder() { - super(Number.class); - } - - @SuppressWarnings("resource") // caller must close the InputStream - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) - throws IOException { - return new Deflate64CompressorInputStream(in); - } - } - - static class BZIP2Decoder extends CoderBase { - BZIP2Decoder() { - super(Number.class); - } - - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) - throws IOException { - return new BZip2CompressorInputStream(in); - } - @Override - OutputStream encode(final OutputStream out, final Object options) - throws IOException { - final int blockSize = numberOptionOrDefault(options, BZip2CompressorOutputStream.MAX_BLOCKSIZE); - return new BZip2CompressorOutputStream(out, blockSize); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/DeltaDecoder.java b/src/org/apache/commons/compress/archivers/sevenz/DeltaDecoder.java deleted file mode 100644 index bc58c636d74..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/DeltaDecoder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import org.tukaani.xz.DeltaOptions; -import org.tukaani.xz.FinishableWrapperOutputStream; -import org.tukaani.xz.UnsupportedOptionsException; - -class DeltaDecoder extends CoderBase { - DeltaDecoder() { - super(Number.class); - } - - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) throws IOException { - return new DeltaOptions(getOptionsFromCoder(coder)).getInputStream(in); - } - - @SuppressWarnings("resource") - @Override - OutputStream encode(final OutputStream out, final Object options) throws IOException { - final int distance = numberOptionOrDefault(options, 1); - try { - return new DeltaOptions(distance).getOutputStream(new FinishableWrapperOutputStream(out)); - } catch (final UnsupportedOptionsException ex) { - throw new IOException(ex.getMessage()); - } - } - - @Override - byte[] getOptionsAsProperties(final Object options) { - return new byte[] { - (byte) (numberOptionOrDefault(options, 1) - 1) - }; - } - - @Override - Object getOptionsFromCoder(final Coder coder, final InputStream in) { - return getOptionsFromCoder(coder); - } - - private int getOptionsFromCoder(final Coder coder) { - if (coder.properties == null || coder.properties.length == 0) { - return 1; - } - return (0xff & coder.properties[0]) + 1; - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/Folder.java b/src/org/apache/commons/compress/archivers/sevenz/Folder.java deleted file mode 100644 index 128cba928e3..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/Folder.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.util.LinkedList; - -/** - * The unit of solid compression. - */ -class Folder { - /// List of coders used in this folder, eg. one for compression, one for encryption. - Coder[] coders; - /// Total number of input streams across all coders. - /// this field is currently unused but technically part of the 7z API - long totalInputStreams; - /// Total number of output streams across all coders. - long totalOutputStreams; - /// Mapping between input and output streams. - BindPair[] bindPairs; - /// Indeces of input streams, one per input stream not listed in bindPairs. - long[] packedStreams; - /// Unpack sizes, per each output stream. - long[] unpackSizes; - /// Whether the folder has a CRC. - boolean hasCrc; - /// The CRC, if present. - long crc; - /// The number of unpack substreams, product of the number of - /// output streams and the nuber of non-empty files in this - /// folder. - int numUnpackSubStreams; - - /** - * Sorts Coders using bind pairs. - *

The first coder reads from the packed stream (we currently - * only support single input stream decoders), the second reads - * from the output of the first and so on.

- */ - Iterable getOrderedCoders() { - final LinkedList l = new LinkedList<>(); - int current = (int) packedStreams[0]; // more that 2^31 coders? - while (current != -1) { - l.addLast(coders[current]); - final int pair = findBindPairForOutStream(current); - current = pair != -1 ? (int) bindPairs[pair].inIndex : -1; - } - return l; - } - - int findBindPairForInStream(final int index) { - for (int i = 0; i < bindPairs.length; i++) { - if (bindPairs[i].inIndex == index) { - return i; - } - } - return -1; - } - - int findBindPairForOutStream(final int index) { - for (int i = 0; i < bindPairs.length; i++) { - if (bindPairs[i].outIndex == index) { - return i; - } - } - return -1; - } - - long getUnpackSize() { - if (totalOutputStreams == 0) { - return 0; - } - for (int i = ((int)totalOutputStreams) - 1; i >= 0; i--) { - if (findBindPairForOutStream(i) < 0) { - return unpackSizes[i]; - } - } - return 0; - } - - long getUnpackSizeForCoder(final Coder coder) { - if (coders != null) { - for (int i = 0; i < coders.length; i++) { - if (coders[i] == coder) { - return unpackSizes[i]; - } - } - } - return 0; - } - - @Override - public String toString() { - return "Folder with " + coders.length + " coders, " + totalInputStreams - + " input streams, " + totalOutputStreams + " output streams, " - + bindPairs.length + " bind pairs, " + packedStreams.length - + " packed streams, " + unpackSizes.length + " unpack sizes, " - + (hasCrc ? "with CRC " + crc : "without CRC") - + " and " + numUnpackSubStreams + " unpack streams"; - } -} - diff --git a/src/org/apache/commons/compress/archivers/sevenz/LZMA2Decoder.java b/src/org/apache/commons/compress/archivers/sevenz/LZMA2Decoder.java deleted file mode 100644 index 0f13ca95c73..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/LZMA2Decoder.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.tukaani.xz.FinishableWrapperOutputStream; -import org.tukaani.xz.FinishableOutputStream; -import org.tukaani.xz.LZMA2InputStream; -import org.tukaani.xz.LZMA2Options; - -class LZMA2Decoder extends CoderBase { - LZMA2Decoder() { - super(LZMA2Options.class, Number.class); - } - - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) throws IOException { - try { - final int dictionarySize = getDictionarySize(coder); - return new LZMA2InputStream(in, dictionarySize); - } catch (final IllegalArgumentException ex) { - throw new IOException(ex.getMessage()); - } - } - - @Override - OutputStream encode(final OutputStream out, final Object opts) - throws IOException { - final LZMA2Options options = getOptions(opts); - final FinishableOutputStream wrapped = new FinishableWrapperOutputStream(out); - return options.getOutputStream(wrapped); - } - - @Override - byte[] getOptionsAsProperties(final Object opts) { - final int dictSize = getDictSize(opts); - final int lead = Integer.numberOfLeadingZeros(dictSize); - final int secondBit = (dictSize >>> (30 - lead)) - 2; - return new byte[] { - (byte) ((19 - lead) * 2 + secondBit) - }; - } - - @Override - Object getOptionsFromCoder(final Coder coder, final InputStream in) { - return getDictionarySize(coder); - } - - private int getDictSize(final Object opts) { - if (opts instanceof LZMA2Options) { - return ((LZMA2Options) opts).getDictSize(); - } - return numberOptionOrDefault(opts); - } - - private int getDictionarySize(final Coder coder) throws IllegalArgumentException { - final int dictionarySizeBits = 0xff & coder.properties[0]; - if ((dictionarySizeBits & (~0x3f)) != 0) { - throw new IllegalArgumentException("Unsupported LZMA2 property bits"); - } - if (dictionarySizeBits > 40) { - throw new IllegalArgumentException("Dictionary larger than 4GiB maximum size"); - } - if (dictionarySizeBits == 40) { - return 0xFFFFffff; - } - return (2 | (dictionarySizeBits & 0x1)) << (dictionarySizeBits / 2 + 11); - } - - private LZMA2Options getOptions(final Object opts) throws IOException { - if (opts instanceof LZMA2Options) { - return (LZMA2Options) opts; - } - final LZMA2Options options = new LZMA2Options(); - options.setDictSize(numberOptionOrDefault(opts)); - return options; - } - - private int numberOptionOrDefault(final Object opts) { - return numberOptionOrDefault(opts, LZMA2Options.DICT_SIZE_DEFAULT); - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java b/src/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java deleted file mode 100644 index 6e3d46ccc25..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.apache.commons.compress.utils.ByteUtils; -import org.apache.commons.compress.utils.FlushShieldFilterOutputStream; -import org.tukaani.xz.LZMA2Options; -import org.tukaani.xz.LZMAInputStream; -import org.tukaani.xz.LZMAOutputStream; - -class LZMADecoder extends CoderBase { - LZMADecoder() { - super(LZMA2Options.class, Number.class); - } - - @Override - InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, - final Coder coder, final byte[] password) throws IOException { - final byte propsByte = coder.properties[0]; - final int dictSize = getDictionarySize(coder); - if (dictSize > LZMAInputStream.DICT_SIZE_MAX) { - throw new IOException("Dictionary larger than 4GiB maximum size used in " + archiveName); - } - return new LZMAInputStream(in, uncompressedLength, propsByte, dictSize); - } - - @SuppressWarnings("resource") - @Override - OutputStream encode(final OutputStream out, final Object opts) - throws IOException { - // NOOP as LZMAOutputStream throws an exception in flush - return new FlushShieldFilterOutputStream(new LZMAOutputStream(out, getOptions(opts), false)); - } - - @Override - byte[] getOptionsAsProperties(final Object opts) throws IOException { - final LZMA2Options options = getOptions(opts); - final byte props = (byte) ((options.getPb() * 5 + options.getLp()) * 9 + options.getLc()); - int dictSize = options.getDictSize(); - byte[] o = new byte[5]; - o[0] = props; - ByteUtils.toLittleEndian(o, dictSize, 1, 4); - return o; - } - - @Override - Object getOptionsFromCoder(final Coder coder, final InputStream in) throws IOException { - final byte propsByte = coder.properties[0]; - int props = propsByte & 0xFF; - int pb = props / (9 * 5); - props -= pb * 9 * 5; - int lp = props / 9; - int lc = props - lp * 9; - LZMA2Options opts = new LZMA2Options(); - opts.setPb(pb); - opts.setLcLp(lc, lp); - opts.setDictSize(getDictionarySize(coder)); - return opts; - } - - private int getDictionarySize(final Coder coder) throws IllegalArgumentException { - return (int) ByteUtils.fromLittleEndian(coder.properties, 1, 4); - } - - private LZMA2Options getOptions(final Object opts) throws IOException { - if (opts instanceof LZMA2Options) { - return (LZMA2Options) opts; - } - final LZMA2Options options = new LZMA2Options(); - options.setDictSize(numberOptionOrDefault(opts)); - return options; - } - - private int numberOptionOrDefault(final Object opts) { - return numberOptionOrDefault(opts, LZMA2Options.DICT_SIZE_DEFAULT); - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/NID.java b/src/org/apache/commons/compress/archivers/sevenz/NID.java deleted file mode 100644 index 89a813a2a19..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/NID.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -final class NID { - public static final int kEnd = 0x00; - public static final int kHeader = 0x01; - public static final int kArchiveProperties = 0x02; - public static final int kAdditionalStreamsInfo = 0x03; - public static final int kMainStreamsInfo = 0x04; - public static final int kFilesInfo = 0x05; - public static final int kPackInfo = 0x06; - public static final int kUnpackInfo = 0x07; - public static final int kSubStreamsInfo = 0x08; - public static final int kSize = 0x09; - public static final int kCRC = 0x0A; - public static final int kFolder = 0x0B; - public static final int kCodersUnpackSize = 0x0C; - public static final int kNumUnpackStream = 0x0D; - public static final int kEmptyStream = 0x0E; - public static final int kEmptyFile = 0x0F; - public static final int kAnti = 0x10; - public static final int kName = 0x11; - public static final int kCTime = 0x12; - public static final int kATime = 0x13; - public static final int kMTime = 0x14; - public static final int kWinAttributes = 0x15; - public static final int kComment = 0x16; - public static final int kEncodedHeader = 0x17; - public static final int kStartPos = 0x18; - public static final int kDummy = 0x19; -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/SevenZArchiveEntry.java b/src/org/apache/commons/compress/archivers/sevenz/SevenZArchiveEntry.java deleted file mode 100644 index f95426b652b..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/SevenZArchiveEntry.java +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.LinkedList; -import java.util.TimeZone; - -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * An entry in a 7z archive. - * - * @NotThreadSafe - * @since 1.6 - */ -public class SevenZArchiveEntry implements ArchiveEntry { - private String name; - private boolean hasStream; - private boolean isDirectory; - private boolean isAntiItem; - private boolean hasCreationDate; - private boolean hasLastModifiedDate; - private boolean hasAccessDate; - private long creationDate; - private long lastModifiedDate; - private long accessDate; - private boolean hasWindowsAttributes; - private int windowsAttributes; - private boolean hasCrc; - private long crc, compressedCrc; - private long size, compressedSize; - private Iterable contentMethods; - - public SevenZArchiveEntry() { - } - - /** - * Get this entry's name. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return This entry's name. - */ - @Override - public String getName() { - return name; - } - - /** - * Set this entry's name. - * - * @param name This entry's new name. - */ - public void setName(final String name) { - this.name = name; - } - - /** - * Whether there is any content associated with this entry. - * @return whether there is any content associated with this entry. - */ - public boolean hasStream() { - return hasStream; - } - - /** - * Sets whether there is any content associated with this entry. - * @param hasStream whether there is any content associated with this entry. - */ - public void setHasStream(final boolean hasStream) { - this.hasStream = hasStream; - } - - /** - * Return whether or not this entry represents a directory. - * - * @return True if this entry is a directory. - */ - @Override - public boolean isDirectory() { - return isDirectory; - } - - /** - * Sets whether or not this entry represents a directory. - * - * @param isDirectory True if this entry is a directory. - */ - public void setDirectory(final boolean isDirectory) { - this.isDirectory = isDirectory; - } - - /** - * Indicates whether this is an "anti-item" used in differential backups, - * meaning it should delete the same file from a previous backup. - * @return true if it is an anti-item, false otherwise - */ - public boolean isAntiItem() { - return isAntiItem; - } - - /** - * Sets whether this is an "anti-item" used in differential backups, - * meaning it should delete the same file from a previous backup. - * @param isAntiItem true if it is an anti-item, false otherwise - */ - public void setAntiItem(final boolean isAntiItem) { - this.isAntiItem = isAntiItem; - } - - /** - * Returns whether this entry has got a creation date at all. - * @return whether the entry has got a creation date - */ - public boolean getHasCreationDate() { - return hasCreationDate; - } - - /** - * Sets whether this entry has got a creation date at all. - * @param hasCreationDate whether the entry has got a creation date - */ - public void setHasCreationDate(final boolean hasCreationDate) { - this.hasCreationDate = hasCreationDate; - } - - /** - * Gets the creation date. - * @throws UnsupportedOperationException if the entry hasn't got a - * creation date. - * @return the creation date - */ - public Date getCreationDate() { - if (hasCreationDate) { - return ntfsTimeToJavaTime(creationDate); - } - throw new UnsupportedOperationException( - "The entry doesn't have this timestamp"); - } - - /** - * Sets the creation date using NTFS time (100 nanosecond units - * since 1 January 1601) - * @param ntfsCreationDate the creation date - */ - public void setCreationDate(final long ntfsCreationDate) { - this.creationDate = ntfsCreationDate; - } - - /** - * Sets the creation date, - * @param creationDate the creation date - */ - public void setCreationDate(final Date creationDate) { - hasCreationDate = creationDate != null; - if (hasCreationDate) { - this.creationDate = javaTimeToNtfsTime(creationDate); - } - } - - /** - * Returns whether this entry has got a last modified date at all. - * @return whether this entry has got a last modified date at all - */ - public boolean getHasLastModifiedDate() { - return hasLastModifiedDate; - } - - /** - * Sets whether this entry has got a last modified date at all. - * @param hasLastModifiedDate whether this entry has got a last - * modified date at all - */ - public void setHasLastModifiedDate(final boolean hasLastModifiedDate) { - this.hasLastModifiedDate = hasLastModifiedDate; - } - - /** - * Gets the last modified date. - * @throws UnsupportedOperationException if the entry hasn't got a - * last modified date. - * @return the last modified date - */ - @Override - public Date getLastModifiedDate() { - if (hasLastModifiedDate) { - return ntfsTimeToJavaTime(lastModifiedDate); - } - throw new UnsupportedOperationException( - "The entry doesn't have this timestamp"); - } - - /** - * Sets the last modified date using NTFS time (100 nanosecond - * units since 1 January 1601) - * @param ntfsLastModifiedDate the last modified date - */ - public void setLastModifiedDate(final long ntfsLastModifiedDate) { - this.lastModifiedDate = ntfsLastModifiedDate; - } - - /** - * Sets the last modified date, - * @param lastModifiedDate the last modified date - */ - public void setLastModifiedDate(final Date lastModifiedDate) { - hasLastModifiedDate = lastModifiedDate != null; - if (hasLastModifiedDate) { - this.lastModifiedDate = javaTimeToNtfsTime(lastModifiedDate); - } - } - - /** - * Returns whether this entry has got an access date at all. - * @return whether this entry has got an access date at all. - */ - public boolean getHasAccessDate() { - return hasAccessDate; - } - - /** - * Sets whether this entry has got an access date at all. - * @param hasAcessDate whether this entry has got an access date at all. - */ - public void setHasAccessDate(final boolean hasAcessDate) { - this.hasAccessDate = hasAcessDate; - } - - /** - * Gets the access date. - * @throws UnsupportedOperationException if the entry hasn't got a - * access date. - * @return the access date - */ - public Date getAccessDate() { - if (hasAccessDate) { - return ntfsTimeToJavaTime(accessDate); - } - throw new UnsupportedOperationException( - "The entry doesn't have this timestamp"); - } - - /** - * Sets the access date using NTFS time (100 nanosecond units - * since 1 January 1601) - * @param ntfsAccessDate the access date - */ - public void setAccessDate(final long ntfsAccessDate) { - this.accessDate = ntfsAccessDate; - } - - /** - * Sets the access date, - * @param accessDate the access date - */ - public void setAccessDate(final Date accessDate) { - hasAccessDate = accessDate != null; - if (hasAccessDate) { - this.accessDate = javaTimeToNtfsTime(accessDate); - } - } - - /** - * Returns whether this entry has windows attributes. - * @return whether this entry has windows attributes. - */ - public boolean getHasWindowsAttributes() { - return hasWindowsAttributes; - } - - /** - * Sets whether this entry has windows attributes. - * @param hasWindowsAttributes whether this entry has windows attributes. - */ - public void setHasWindowsAttributes(final boolean hasWindowsAttributes) { - this.hasWindowsAttributes = hasWindowsAttributes; - } - - /** - * Gets the windows attributes. - * @return the windows attributes - */ - public int getWindowsAttributes() { - return windowsAttributes; - } - - /** - * Sets the windows attributes. - * @param windowsAttributes the windows attributes - */ - public void setWindowsAttributes(final int windowsAttributes) { - this.windowsAttributes = windowsAttributes; - } - - /** - * Returns whether this entry has got a crc. - * - *

In general entries without streams don't have a CRC either.

- * @return whether this entry has got a crc. - */ - public boolean getHasCrc() { - return hasCrc; - } - - /** - * Sets whether this entry has got a crc. - * @param hasCrc whether this entry has got a crc. - */ - public void setHasCrc(final boolean hasCrc) { - this.hasCrc = hasCrc; - } - - /** - * Gets the CRC. - * @deprecated use getCrcValue instead. - * @return the CRC - */ - @Deprecated - public int getCrc() { - return (int) crc; - } - - /** - * Sets the CRC. - * @deprecated use setCrcValue instead. - * @param crc the CRC - */ - @Deprecated - public void setCrc(final int crc) { - this.crc = crc; - } - - /** - * Gets the CRC. - * @since Compress 1.7 - * @return the CRC - */ - public long getCrcValue() { - return crc; - } - - /** - * Sets the CRC. - * @since Compress 1.7 - * @param crc the CRC - */ - public void setCrcValue(final long crc) { - this.crc = crc; - } - - /** - * Gets the compressed CRC. - * @deprecated use getCompressedCrcValue instead. - * @return the compressed CRC - */ - @Deprecated - int getCompressedCrc() { - return (int) compressedCrc; - } - - /** - * Sets the compressed CRC. - * @deprecated use setCompressedCrcValue instead. - * @param crc the CRC - */ - @Deprecated - void setCompressedCrc(final int crc) { - this.compressedCrc = crc; - } - - /** - * Gets the compressed CRC. - * @since Compress 1.7 - * @return the CRC - */ - long getCompressedCrcValue() { - return compressedCrc; - } - - /** - * Sets the compressed CRC. - * @since Compress 1.7 - * @param crc the CRC - */ - void setCompressedCrcValue(final long crc) { - this.compressedCrc = crc; - } - - /** - * Get this entry's file size. - * - * @return This entry's file size. - */ - @Override - public long getSize() { - return size; - } - - /** - * Set this entry's file size. - * - * @param size This entry's new file size. - */ - public void setSize(final long size) { - this.size = size; - } - - /** - * Get this entry's compressed file size. - * - * @return This entry's compressed file size. - */ - long getCompressedSize() { - return compressedSize; - } - - /** - * Set this entry's compressed file size. - * - * @param size This entry's new compressed file size. - */ - void setCompressedSize(final long size) { - this.compressedSize = size; - } - - /** - * Sets the (compression) methods to use for entry's content - the - * default is LZMA2. - * - *

Currently only {@link SevenZMethod#COPY}, {@link - * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link - * SevenZMethod#DEFLATE} are supported when writing archives.

- * - *

The methods will be consulted in iteration order to create - * the final output.

- * - * @param methods the methods to use for the content - * @since 1.8 - */ - public void setContentMethods(final Iterable methods) { - if (methods != null) { - final LinkedList l = new LinkedList<>(); - for (final SevenZMethodConfiguration m : methods) { - l.addLast(m); - } - contentMethods = Collections.unmodifiableList(l); - } else { - contentMethods = null; - } - } - - /** - * Gets the (compression) methods to use for entry's content - the - * default is LZMA2. - * - *

Currently only {@link SevenZMethod#COPY}, {@link - * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link - * SevenZMethod#DEFLATE} are supported when writing archives.

- * - *

The methods will be consulted in iteration order to create - * the final output.

- * - * @since 1.8 - * @return the methods to use for the content - */ - public Iterable getContentMethods() { - return contentMethods; - } - - /** - * Converts NTFS time (100 nanosecond units since 1 January 1601) - * to Java time. - * @param ntfsTime the NTFS time in 100 nanosecond units - * @return the Java time - */ - public static Date ntfsTimeToJavaTime(final long ntfsTime) { - final Calendar ntfsEpoch = Calendar.getInstance(); - ntfsEpoch.setTimeZone(TimeZone.getTimeZone("GMT+0")); - ntfsEpoch.set(1601, 0, 1, 0, 0, 0); - ntfsEpoch.set(Calendar.MILLISECOND, 0); - final long realTime = ntfsEpoch.getTimeInMillis() + (ntfsTime / (10*1000)); - return new Date(realTime); - } - - /** - * Converts Java time to NTFS time. - * @param date the Java time - * @return the NTFS time - */ - public static long javaTimeToNtfsTime(final Date date) { - final Calendar ntfsEpoch = Calendar.getInstance(); - ntfsEpoch.setTimeZone(TimeZone.getTimeZone("GMT+0")); - ntfsEpoch.set(1601, 0, 1, 0, 0, 0); - ntfsEpoch.set(Calendar.MILLISECOND, 0); - return ((date.getTime() - ntfsEpoch.getTimeInMillis())* 1000 * 10); - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/SevenZFile.java b/src/org/apache/commons/compress/archivers/sevenz/SevenZFile.java deleted file mode 100644 index 421c34abac6..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/SevenZFile.java +++ /dev/null @@ -1,1211 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.Closeable; -import java.io.DataInputStream; -import java.io.File; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.CharBuffer; -import java.nio.channels.SeekableByteChannel; -import java.nio.charset.StandardCharsets; -import java.nio.charset.CharsetEncoder; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.EnumSet; -import java.util.LinkedList; -import java.util.zip.CRC32; - -import org.apache.commons.compress.utils.BoundedInputStream; -import org.apache.commons.compress.utils.CRC32VerifyingInputStream; -import org.apache.commons.compress.utils.CharsetNames; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * Reads a 7z file, using SeekableByteChannel under - * the covers. - *

- * The 7z file format is a flexible container - * that can contain many compression and - * encryption types, but at the moment only - * only Copy, LZMA, LZMA2, BZIP2, Deflate and AES-256 + SHA-256 - * are supported. - *

- * The format is very Windows/Intel specific, - * so it uses little-endian byte order, - * doesn't store user/group or permission bits, - * and represents times using NTFS timestamps - * (100 nanosecond units since 1 January 1601). - * Hence the official tools recommend against - * using it for backup purposes on *nix, and - * recommend .tar.7z or .tar.lzma or .tar.xz - * instead. - *

- * Both the header and file contents may be - * compressed and/or encrypted. With both - * encrypted, neither file names nor file - * contents can be read, but the use of - * encryption isn't plausibly deniable. - * - * @NotThreadSafe - * @since 1.6 - */ -public class SevenZFile implements Closeable { - static final int SIGNATURE_HEADER_SIZE = 32; - - private final String fileName; - private SeekableByteChannel channel; - private final Archive archive; - private int currentEntryIndex = -1; - private int currentFolderIndex = -1; - private InputStream currentFolderInputStream = null; - private byte[] password; - - private long compressedBytesReadFromCurrentEntry; - private long uncompressedBytesReadFromCurrentEntry; - - private final ArrayList deferredBlockStreams = new ArrayList<>(); - - // shared with SevenZOutputFile and tests, neither mutates it - static final byte[] sevenZSignature = { //NOSONAR - (byte)'7', (byte)'z', (byte)0xBC, (byte)0xAF, (byte)0x27, (byte)0x1C - }; - - /** - * Reads a file as 7z archive - * - * @param filename the file to read - * @param password optional password if the archive is encrypted - * @throws IOException if reading the archive fails - * @since 1.17 - */ - public SevenZFile(final File filename, final char[] password) throws IOException { - this(Files.newByteChannel(filename.toPath(), EnumSet.of(StandardOpenOption.READ)), - filename.getAbsolutePath(), utf16Decode(password), true); - } - - /** - * Reads a file as 7z archive - * - * @param filename the file to read - * @param password optional password if the archive is encrypted - - * the byte array is supposed to be the UTF16-LE encoded - * representation of the password. - * @throws IOException if reading the archive fails - * @deprecated use the char[]-arg version for the password instead - */ - public SevenZFile(final File filename, final byte[] password) throws IOException { - this(Files.newByteChannel(filename.toPath(), EnumSet.of(StandardOpenOption.READ)), - filename.getAbsolutePath(), password, true); - } - - /** - * Reads a SeekableByteChannel as 7z archive - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the channel to read - * @throws IOException if reading the archive fails - * @since 1.13 - */ - public SevenZFile(final SeekableByteChannel channel) throws IOException { - this(channel, "unknown archive", (char[]) null); - } - - /** - * Reads a SeekableByteChannel as 7z archive - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the channel to read - * @param password optional password if the archive is encrypted - * @throws IOException if reading the archive fails - * @since 1.17 - */ - public SevenZFile(final SeekableByteChannel channel, - final char[] password) throws IOException { - this(channel, "unknown archive", utf16Decode(password)); - } - - /** - * Reads a SeekableByteChannel as 7z archive - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the channel to read - * @param filename name of the archive - only used for error reporting - * @param password optional password if the archive is encrypted - * @throws IOException if reading the archive fails - * @since 1.17 - */ - public SevenZFile(final SeekableByteChannel channel, String filename, - final char[] password) throws IOException { - this(channel, filename, utf16Decode(password), false); - } - - /** - * Reads a SeekableByteChannel as 7z archive - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the channel to read - * @param filename name of the archive - only used for error reporting - * @throws IOException if reading the archive fails - * @since 1.17 - */ - public SevenZFile(final SeekableByteChannel channel, String filename) - throws IOException { - this(channel, filename, null, false); - } - - /** - * Reads a SeekableByteChannel as 7z archive - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the channel to read - * @param password optional password if the archive is encrypted - - * the byte array is supposed to be the UTF16-LE encoded - * representation of the password. - * @throws IOException if reading the archive fails - * @since 1.13 - * @deprecated use the char[]-arg version for the password instead - */ - public SevenZFile(final SeekableByteChannel channel, - final byte[] password) throws IOException { - this(channel, "unknown archive", password); - } - - /** - * Reads a SeekableByteChannel as 7z archive - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the channel to read - * @param filename name of the archive - only used for error reporting - * @param password optional password if the archive is encrypted - - * the byte array is supposed to be the UTF16-LE encoded - * representation of the password. - * @throws IOException if reading the archive fails - * @since 1.13 - * @deprecated use the char[]-arg version for the password instead - */ - public SevenZFile(final SeekableByteChannel channel, String filename, - final byte[] password) throws IOException { - this(channel, filename, password, false); - } - - private SevenZFile(final SeekableByteChannel channel, String filename, - final byte[] password, boolean closeOnError) throws IOException { - boolean succeeded = false; - this.channel = channel; - this.fileName = filename; - try { - archive = readHeaders(password); - if (password != null) { - this.password = Arrays.copyOf(password, password.length); - } else { - this.password = null; - } - succeeded = true; - } finally { - if (!succeeded && closeOnError) { - this.channel.close(); - } - } - } - - /** - * Reads a file as unencrypted 7z archive - * - * @param filename the file to read - * @throws IOException if reading the archive fails - */ - public SevenZFile(final File filename) throws IOException { - this(filename, (char[]) null); - } - - /** - * Closes the archive. - * @throws IOException if closing the file fails - */ - @Override - public void close() throws IOException { - if (channel != null) { - try { - channel.close(); - } finally { - channel = null; - if (password != null) { - Arrays.fill(password, (byte) 0); - } - password = null; - } - } - } - - /** - * Returns the next Archive Entry in this archive. - * - * @return the next entry, - * or {@code null} if there are no more entries - * @throws IOException if the next entry could not be read - */ - public SevenZArchiveEntry getNextEntry() throws IOException { - if (currentEntryIndex >= archive.files.length - 1) { - return null; - } - ++currentEntryIndex; - final SevenZArchiveEntry entry = archive.files[currentEntryIndex]; - buildDecodingStream(); - uncompressedBytesReadFromCurrentEntry = compressedBytesReadFromCurrentEntry = 0; - return entry; - } - - /** - * Returns meta-data of all archive entries. - * - *

This method only provides meta-data, the entries can not be - * used to read the contents, you still need to process all - * entries in order using {@link #getNextEntry} for that.

- * - *

The content methods are only available for entries that have - * already been reached via {@link #getNextEntry}.

- * - * @return meta-data of all archive entries. - * @since 1.11 - */ - public Iterable getEntries() { - return Arrays.asList(archive.files); - } - - private Archive readHeaders(final byte[] password) throws IOException { - ByteBuffer buf = ByteBuffer.allocate(12 /* signature + 2 bytes version + 4 bytes CRC */) - .order(ByteOrder.LITTLE_ENDIAN); - readFully(buf); - final byte[] signature = new byte[6]; - buf.get(signature); - if (!Arrays.equals(signature, sevenZSignature)) { - throw new IOException("Bad 7z signature"); - } - // 7zFormat.txt has it wrong - it's first major then minor - final byte archiveVersionMajor = buf.get(); - final byte archiveVersionMinor = buf.get(); - if (archiveVersionMajor != 0) { - throw new IOException(String.format("Unsupported 7z version (%d,%d)", - archiveVersionMajor, archiveVersionMinor)); - } - - final long startHeaderCrc = 0xffffFFFFL & buf.getInt(); - final StartHeader startHeader = readStartHeader(startHeaderCrc); - - final int nextHeaderSizeInt = (int) startHeader.nextHeaderSize; - if (nextHeaderSizeInt != startHeader.nextHeaderSize) { - throw new IOException("cannot handle nextHeaderSize " + startHeader.nextHeaderSize); - } - channel.position(SIGNATURE_HEADER_SIZE + startHeader.nextHeaderOffset); - buf = ByteBuffer.allocate(nextHeaderSizeInt).order(ByteOrder.LITTLE_ENDIAN); - readFully(buf); - final CRC32 crc = new CRC32(); - crc.update(buf.array()); - if (startHeader.nextHeaderCrc != crc.getValue()) { - throw new IOException("NextHeader CRC mismatch"); - } - - Archive archive = new Archive(); - int nid = getUnsignedByte(buf); - if (nid == NID.kEncodedHeader) { - buf = readEncodedHeader(buf, archive, password); - // Archive gets rebuilt with the new header - archive = new Archive(); - nid = getUnsignedByte(buf); - } - if (nid == NID.kHeader) { - readHeader(buf, archive); - } else { - throw new IOException("Broken or unsupported archive: no Header"); - } - return archive; - } - - private StartHeader readStartHeader(final long startHeaderCrc) throws IOException { - final StartHeader startHeader = new StartHeader(); - // using Stream rather than ByteBuffer for the benefit of the - // built-in CRC check - try (DataInputStream dataInputStream = new DataInputStream(new CRC32VerifyingInputStream( - new BoundedSeekableByteChannelInputStream(channel, 20), 20, startHeaderCrc))) { - startHeader.nextHeaderOffset = Long.reverseBytes(dataInputStream.readLong()); - startHeader.nextHeaderSize = Long.reverseBytes(dataInputStream.readLong()); - startHeader.nextHeaderCrc = 0xffffFFFFL & Integer.reverseBytes(dataInputStream.readInt()); - return startHeader; - } - } - - private void readHeader(final ByteBuffer header, final Archive archive) throws IOException { - int nid = getUnsignedByte(header); - - if (nid == NID.kArchiveProperties) { - readArchiveProperties(header); - nid = getUnsignedByte(header); - } - - if (nid == NID.kAdditionalStreamsInfo) { - throw new IOException("Additional streams unsupported"); - //nid = header.readUnsignedByte(); - } - - if (nid == NID.kMainStreamsInfo) { - readStreamsInfo(header, archive); - nid = getUnsignedByte(header); - } - - if (nid == NID.kFilesInfo) { - readFilesInfo(header, archive); - nid = getUnsignedByte(header); - } - - if (nid != NID.kEnd) { - throw new IOException("Badly terminated header, found " + nid); - } - } - - private void readArchiveProperties(final ByteBuffer input) throws IOException { - // FIXME: the reference implementation just throws them away? - int nid = getUnsignedByte(input); - while (nid != NID.kEnd) { - final long propertySize = readUint64(input); - final byte[] property = new byte[(int)propertySize]; - input.get(property); - nid = getUnsignedByte(input); - } - } - - private ByteBuffer readEncodedHeader(final ByteBuffer header, final Archive archive, - final byte[] password) throws IOException { - readStreamsInfo(header, archive); - - // FIXME: merge with buildDecodingStream()/buildDecoderStack() at some stage? - final Folder folder = archive.folders[0]; - final int firstPackStreamIndex = 0; - final long folderOffset = SIGNATURE_HEADER_SIZE + archive.packPos + - 0; - - channel.position(folderOffset); - InputStream inputStreamStack = new BoundedSeekableByteChannelInputStream(channel, - archive.packSizes[firstPackStreamIndex]); - for (final Coder coder : folder.getOrderedCoders()) { - if (coder.numInStreams != 1 || coder.numOutStreams != 1) { - throw new IOException("Multi input/output stream coders are not yet supported"); - } - inputStreamStack = Coders.addDecoder(fileName, inputStreamStack, //NOSONAR - folder.getUnpackSizeForCoder(coder), coder, password); - } - if (folder.hasCrc) { - inputStreamStack = new CRC32VerifyingInputStream(inputStreamStack, - folder.getUnpackSize(), folder.crc); - } - final byte[] nextHeader = new byte[(int)folder.getUnpackSize()]; - try (DataInputStream nextHeaderInputStream = new DataInputStream(inputStreamStack)) { - nextHeaderInputStream.readFully(nextHeader); - } - return ByteBuffer.wrap(nextHeader).order(ByteOrder.LITTLE_ENDIAN); - } - - private void readStreamsInfo(final ByteBuffer header, final Archive archive) throws IOException { - int nid = getUnsignedByte(header); - - if (nid == NID.kPackInfo) { - readPackInfo(header, archive); - nid = getUnsignedByte(header); - } - - if (nid == NID.kUnpackInfo) { - readUnpackInfo(header, archive); - nid = getUnsignedByte(header); - } else { - // archive without unpack/coders info - archive.folders = new Folder[0]; - } - - if (nid == NID.kSubStreamsInfo) { - readSubStreamsInfo(header, archive); - nid = getUnsignedByte(header); - } - - if (nid != NID.kEnd) { - throw new IOException("Badly terminated StreamsInfo"); - } - } - - private void readPackInfo(final ByteBuffer header, final Archive archive) throws IOException { - archive.packPos = readUint64(header); - final long numPackStreams = readUint64(header); - int nid = getUnsignedByte(header); - if (nid == NID.kSize) { - archive.packSizes = new long[(int)numPackStreams]; - for (int i = 0; i < archive.packSizes.length; i++) { - archive.packSizes[i] = readUint64(header); - } - nid = getUnsignedByte(header); - } - - if (nid == NID.kCRC) { - archive.packCrcsDefined = readAllOrBits(header, (int)numPackStreams); - archive.packCrcs = new long[(int)numPackStreams]; - for (int i = 0; i < (int)numPackStreams; i++) { - if (archive.packCrcsDefined.get(i)) { - archive.packCrcs[i] = 0xffffFFFFL & header.getInt(); - } - } - - nid = getUnsignedByte(header); - } - - if (nid != NID.kEnd) { - throw new IOException("Badly terminated PackInfo (" + nid + ")"); - } - } - - private void readUnpackInfo(final ByteBuffer header, final Archive archive) throws IOException { - int nid = getUnsignedByte(header); - if (nid != NID.kFolder) { - throw new IOException("Expected kFolder, got " + nid); - } - final long numFolders = readUint64(header); - final Folder[] folders = new Folder[(int)numFolders]; - archive.folders = folders; - final int external = getUnsignedByte(header); - if (external != 0) { - throw new IOException("External unsupported"); - } - for (int i = 0; i < (int)numFolders; i++) { - folders[i] = readFolder(header); - } - - nid = getUnsignedByte(header); - if (nid != NID.kCodersUnpackSize) { - throw new IOException("Expected kCodersUnpackSize, got " + nid); - } - for (final Folder folder : folders) { - folder.unpackSizes = new long[(int)folder.totalOutputStreams]; - for (int i = 0; i < folder.totalOutputStreams; i++) { - folder.unpackSizes[i] = readUint64(header); - } - } - - nid = getUnsignedByte(header); - if (nid == NID.kCRC) { - final BitSet crcsDefined = readAllOrBits(header, (int)numFolders); - for (int i = 0; i < (int)numFolders; i++) { - if (crcsDefined.get(i)) { - folders[i].hasCrc = true; - folders[i].crc = 0xffffFFFFL & header.getInt(); - } else { - folders[i].hasCrc = false; - } - } - - nid = getUnsignedByte(header); - } - - if (nid != NID.kEnd) { - throw new IOException("Badly terminated UnpackInfo"); - } - } - - private void readSubStreamsInfo(final ByteBuffer header, final Archive archive) throws IOException { - for (final Folder folder : archive.folders) { - folder.numUnpackSubStreams = 1; - } - int totalUnpackStreams = archive.folders.length; - - int nid = getUnsignedByte(header); - if (nid == NID.kNumUnpackStream) { - totalUnpackStreams = 0; - for (final Folder folder : archive.folders) { - final long numStreams = readUint64(header); - folder.numUnpackSubStreams = (int)numStreams; - totalUnpackStreams += numStreams; - } - nid = getUnsignedByte(header); - } - - final SubStreamsInfo subStreamsInfo = new SubStreamsInfo(); - subStreamsInfo.unpackSizes = new long[totalUnpackStreams]; - subStreamsInfo.hasCrc = new BitSet(totalUnpackStreams); - subStreamsInfo.crcs = new long[totalUnpackStreams]; - - int nextUnpackStream = 0; - for (final Folder folder : archive.folders) { - if (folder.numUnpackSubStreams == 0) { - continue; - } - long sum = 0; - if (nid == NID.kSize) { - for (int i = 0; i < folder.numUnpackSubStreams - 1; i++) { - final long size = readUint64(header); - subStreamsInfo.unpackSizes[nextUnpackStream++] = size; - sum += size; - } - } - subStreamsInfo.unpackSizes[nextUnpackStream++] = folder.getUnpackSize() - sum; - } - if (nid == NID.kSize) { - nid = getUnsignedByte(header); - } - - int numDigests = 0; - for (final Folder folder : archive.folders) { - if (folder.numUnpackSubStreams != 1 || !folder.hasCrc) { - numDigests += folder.numUnpackSubStreams; - } - } - - if (nid == NID.kCRC) { - final BitSet hasMissingCrc = readAllOrBits(header, numDigests); - final long[] missingCrcs = new long[numDigests]; - for (int i = 0; i < numDigests; i++) { - if (hasMissingCrc.get(i)) { - missingCrcs[i] = 0xffffFFFFL & header.getInt(); - } - } - int nextCrc = 0; - int nextMissingCrc = 0; - for (final Folder folder: archive.folders) { - if (folder.numUnpackSubStreams == 1 && folder.hasCrc) { - subStreamsInfo.hasCrc.set(nextCrc, true); - subStreamsInfo.crcs[nextCrc] = folder.crc; - ++nextCrc; - } else { - for (int i = 0; i < folder.numUnpackSubStreams; i++) { - subStreamsInfo.hasCrc.set(nextCrc, hasMissingCrc.get(nextMissingCrc)); - subStreamsInfo.crcs[nextCrc] = missingCrcs[nextMissingCrc]; - ++nextCrc; - ++nextMissingCrc; - } - } - } - - nid = getUnsignedByte(header); - } - - if (nid != NID.kEnd) { - throw new IOException("Badly terminated SubStreamsInfo"); - } - - archive.subStreamsInfo = subStreamsInfo; - } - - private Folder readFolder(final ByteBuffer header) throws IOException { - final Folder folder = new Folder(); - - final long numCoders = readUint64(header); - final Coder[] coders = new Coder[(int)numCoders]; - long totalInStreams = 0; - long totalOutStreams = 0; - for (int i = 0; i < coders.length; i++) { - coders[i] = new Coder(); - final int bits = getUnsignedByte(header); - final int idSize = bits & 0xf; - final boolean isSimple = (bits & 0x10) == 0; - final boolean hasAttributes = (bits & 0x20) != 0; - final boolean moreAlternativeMethods = (bits & 0x80) != 0; - - coders[i].decompressionMethodId = new byte[idSize]; - header.get(coders[i].decompressionMethodId); - if (isSimple) { - coders[i].numInStreams = 1; - coders[i].numOutStreams = 1; - } else { - coders[i].numInStreams = readUint64(header); - coders[i].numOutStreams = readUint64(header); - } - totalInStreams += coders[i].numInStreams; - totalOutStreams += coders[i].numOutStreams; - if (hasAttributes) { - final long propertiesSize = readUint64(header); - coders[i].properties = new byte[(int)propertiesSize]; - header.get(coders[i].properties); - } - // would need to keep looping as above: - while (moreAlternativeMethods) { - throw new IOException("Alternative methods are unsupported, please report. " + - "The reference implementation doesn't support them either."); - } - } - folder.coders = coders; - folder.totalInputStreams = totalInStreams; - folder.totalOutputStreams = totalOutStreams; - - if (totalOutStreams == 0) { - throw new IOException("Total output streams can't be 0"); - } - final long numBindPairs = totalOutStreams - 1; - final BindPair[] bindPairs = new BindPair[(int)numBindPairs]; - for (int i = 0; i < bindPairs.length; i++) { - bindPairs[i] = new BindPair(); - bindPairs[i].inIndex = readUint64(header); - bindPairs[i].outIndex = readUint64(header); - } - folder.bindPairs = bindPairs; - - if (totalInStreams < numBindPairs) { - throw new IOException("Total input streams can't be less than the number of bind pairs"); - } - final long numPackedStreams = totalInStreams - numBindPairs; - final long packedStreams[] = new long[(int)numPackedStreams]; - if (numPackedStreams == 1) { - int i; - for (i = 0; i < (int)totalInStreams; i++) { - if (folder.findBindPairForInStream(i) < 0) { - break; - } - } - if (i == (int)totalInStreams) { - throw new IOException("Couldn't find stream's bind pair index"); - } - packedStreams[0] = i; - } else { - for (int i = 0; i < (int)numPackedStreams; i++) { - packedStreams[i] = readUint64(header); - } - } - folder.packedStreams = packedStreams; - - return folder; - } - - private BitSet readAllOrBits(final ByteBuffer header, final int size) throws IOException { - final int areAllDefined = getUnsignedByte(header); - final BitSet bits; - if (areAllDefined != 0) { - bits = new BitSet(size); - for (int i = 0; i < size; i++) { - bits.set(i, true); - } - } else { - bits = readBits(header, size); - } - return bits; - } - - private BitSet readBits(final ByteBuffer header, final int size) throws IOException { - final BitSet bits = new BitSet(size); - int mask = 0; - int cache = 0; - for (int i = 0; i < size; i++) { - if (mask == 0) { - mask = 0x80; - cache = getUnsignedByte(header); - } - bits.set(i, (cache & mask) != 0); - mask >>>= 1; - } - return bits; - } - - private void readFilesInfo(final ByteBuffer header, final Archive archive) throws IOException { - final long numFiles = readUint64(header); - final SevenZArchiveEntry[] files = new SevenZArchiveEntry[(int)numFiles]; - for (int i = 0; i < files.length; i++) { - files[i] = new SevenZArchiveEntry(); - } - BitSet isEmptyStream = null; - BitSet isEmptyFile = null; - BitSet isAnti = null; - while (true) { - final int propertyType = getUnsignedByte(header); - if (propertyType == 0) { - break; - } - final long size = readUint64(header); - switch (propertyType) { - case NID.kEmptyStream: { - isEmptyStream = readBits(header, files.length); - break; - } - case NID.kEmptyFile: { - if (isEmptyStream == null) { // protect against NPE - throw new IOException("Header format error: kEmptyStream must appear before kEmptyFile"); - } - isEmptyFile = readBits(header, isEmptyStream.cardinality()); - break; - } - case NID.kAnti: { - if (isEmptyStream == null) { // protect against NPE - throw new IOException("Header format error: kEmptyStream must appear before kAnti"); - } - isAnti = readBits(header, isEmptyStream.cardinality()); - break; - } - case NID.kName: { - final int external = getUnsignedByte(header); - if (external != 0) { - throw new IOException("Not implemented"); - } - if (((size - 1) & 1) != 0) { - throw new IOException("File names length invalid"); - } - final byte[] names = new byte[(int)(size - 1)]; - header.get(names); - int nextFile = 0; - int nextName = 0; - for (int i = 0; i < names.length; i += 2) { - if (names[i] == 0 && names[i+1] == 0) { - files[nextFile++].setName(new String(names, nextName, i-nextName, CharsetNames.UTF_16LE)); - nextName = i + 2; - } - } - if (nextName != names.length || nextFile != files.length) { - throw new IOException("Error parsing file names"); - } - break; - } - case NID.kCTime: { - final BitSet timesDefined = readAllOrBits(header, files.length); - final int external = getUnsignedByte(header); - if (external != 0) { - throw new IOException("Unimplemented"); - } - for (int i = 0; i < files.length; i++) { - files[i].setHasCreationDate(timesDefined.get(i)); - if (files[i].getHasCreationDate()) { - files[i].setCreationDate(header.getLong()); - } - } - break; - } - case NID.kATime: { - final BitSet timesDefined = readAllOrBits(header, files.length); - final int external = getUnsignedByte(header); - if (external != 0) { - throw new IOException("Unimplemented"); - } - for (int i = 0; i < files.length; i++) { - files[i].setHasAccessDate(timesDefined.get(i)); - if (files[i].getHasAccessDate()) { - files[i].setAccessDate(header.getLong()); - } - } - break; - } - case NID.kMTime: { - final BitSet timesDefined = readAllOrBits(header, files.length); - final int external = getUnsignedByte(header); - if (external != 0) { - throw new IOException("Unimplemented"); - } - for (int i = 0; i < files.length; i++) { - files[i].setHasLastModifiedDate(timesDefined.get(i)); - if (files[i].getHasLastModifiedDate()) { - files[i].setLastModifiedDate(header.getLong()); - } - } - break; - } - case NID.kWinAttributes: { - final BitSet attributesDefined = readAllOrBits(header, files.length); - final int external = getUnsignedByte(header); - if (external != 0) { - throw new IOException("Unimplemented"); - } - for (int i = 0; i < files.length; i++) { - files[i].setHasWindowsAttributes(attributesDefined.get(i)); - if (files[i].getHasWindowsAttributes()) { - files[i].setWindowsAttributes(header.getInt()); - } - } - break; - } - case NID.kStartPos: { - throw new IOException("kStartPos is unsupported, please report"); - } - case NID.kDummy: { - // 7z 9.20 asserts the content is all zeros and ignores the property - // Compress up to 1.8.1 would throw an exception, now we ignore it (see COMPRESS-287 - - if (skipBytesFully(header, size) < size) { - throw new IOException("Incomplete kDummy property"); - } - break; - } - - default: { - // Compress up to 1.8.1 would throw an exception, now we ignore it (see COMPRESS-287 - if (skipBytesFully(header, size) < size) { - throw new IOException("Incomplete property of type " + propertyType); - } - break; - } - } - } - int nonEmptyFileCounter = 0; - int emptyFileCounter = 0; - for (int i = 0; i < files.length; i++) { - files[i].setHasStream(isEmptyStream == null || !isEmptyStream.get(i)); - if (files[i].hasStream()) { - files[i].setDirectory(false); - files[i].setAntiItem(false); - files[i].setHasCrc(archive.subStreamsInfo.hasCrc.get(nonEmptyFileCounter)); - files[i].setCrcValue(archive.subStreamsInfo.crcs[nonEmptyFileCounter]); - files[i].setSize(archive.subStreamsInfo.unpackSizes[nonEmptyFileCounter]); - ++nonEmptyFileCounter; - } else { - files[i].setDirectory(isEmptyFile == null || !isEmptyFile.get(emptyFileCounter)); - files[i].setAntiItem(isAnti != null && isAnti.get(emptyFileCounter)); - files[i].setHasCrc(false); - files[i].setSize(0); - ++emptyFileCounter; - } - } - archive.files = files; - calculateStreamMap(archive); - } - - private void calculateStreamMap(final Archive archive) throws IOException { - final StreamMap streamMap = new StreamMap(); - - int nextFolderPackStreamIndex = 0; - final int numFolders = archive.folders != null ? archive.folders.length : 0; - streamMap.folderFirstPackStreamIndex = new int[numFolders]; - for (int i = 0; i < numFolders; i++) { - streamMap.folderFirstPackStreamIndex[i] = nextFolderPackStreamIndex; - nextFolderPackStreamIndex += archive.folders[i].packedStreams.length; - } - - long nextPackStreamOffset = 0; - final int numPackSizes = archive.packSizes != null ? archive.packSizes.length : 0; - streamMap.packStreamOffsets = new long[numPackSizes]; - for (int i = 0; i < numPackSizes; i++) { - streamMap.packStreamOffsets[i] = nextPackStreamOffset; - nextPackStreamOffset += archive.packSizes[i]; - } - - streamMap.folderFirstFileIndex = new int[numFolders]; - streamMap.fileFolderIndex = new int[archive.files.length]; - int nextFolderIndex = 0; - int nextFolderUnpackStreamIndex = 0; - for (int i = 0; i < archive.files.length; i++) { - if (!archive.files[i].hasStream() && nextFolderUnpackStreamIndex == 0) { - streamMap.fileFolderIndex[i] = -1; - continue; - } - if (nextFolderUnpackStreamIndex == 0) { - for (; nextFolderIndex < archive.folders.length; ++nextFolderIndex) { - streamMap.folderFirstFileIndex[nextFolderIndex] = i; - if (archive.folders[nextFolderIndex].numUnpackSubStreams > 0) { - break; - } - } - if (nextFolderIndex >= archive.folders.length) { - throw new IOException("Too few folders in archive"); - } - } - streamMap.fileFolderIndex[i] = nextFolderIndex; - if (!archive.files[i].hasStream()) { - continue; - } - ++nextFolderUnpackStreamIndex; - if (nextFolderUnpackStreamIndex >= archive.folders[nextFolderIndex].numUnpackSubStreams) { - ++nextFolderIndex; - nextFolderUnpackStreamIndex = 0; - } - } - - archive.streamMap = streamMap; - } - - private void buildDecodingStream() throws IOException { - final int folderIndex = archive.streamMap.fileFolderIndex[currentEntryIndex]; - if (folderIndex < 0) { - deferredBlockStreams.clear(); - // TODO: previously it'd return an empty stream? - // new BoundedInputStream(new ByteArrayInputStream(new byte[0]), 0); - return; - } - final SevenZArchiveEntry file = archive.files[currentEntryIndex]; - if (currentFolderIndex == folderIndex) { - // (COMPRESS-320). - // The current entry is within the same (potentially opened) folder. The - // previous stream has to be fully decoded before we can start reading - // but don't do it eagerly -- if the user skips over the entire folder nothing - // is effectively decompressed. - - file.setContentMethods(archive.files[currentEntryIndex - 1].getContentMethods()); - } else { - // We're opening a new folder. Discard any queued streams/ folder stream. - currentFolderIndex = folderIndex; - deferredBlockStreams.clear(); - if (currentFolderInputStream != null) { - currentFolderInputStream.close(); - currentFolderInputStream = null; - } - - final Folder folder = archive.folders[folderIndex]; - final int firstPackStreamIndex = archive.streamMap.folderFirstPackStreamIndex[folderIndex]; - final long folderOffset = SIGNATURE_HEADER_SIZE + archive.packPos + - archive.streamMap.packStreamOffsets[firstPackStreamIndex]; - currentFolderInputStream = buildDecoderStack(folder, folderOffset, firstPackStreamIndex, file); - } - - InputStream fileStream = new BoundedInputStream(currentFolderInputStream, file.getSize()); - if (file.getHasCrc()) { - fileStream = new CRC32VerifyingInputStream(fileStream, file.getSize(), file.getCrcValue()); - } - - deferredBlockStreams.add(fileStream); - } - - private InputStream buildDecoderStack(final Folder folder, final long folderOffset, - final int firstPackStreamIndex, final SevenZArchiveEntry entry) throws IOException { - channel.position(folderOffset); - InputStream inputStreamStack = new FilterInputStream(new BufferedInputStream( - new BoundedSeekableByteChannelInputStream(channel, - archive.packSizes[firstPackStreamIndex]))) { - @Override - public int read() throws IOException { - final int r = in.read(); - if (r >= 0) { - count(1); - } - return r; - } - @Override - public int read(final byte[] b) throws IOException { - return read(b, 0, b.length); - } - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - final int r = in.read(b, off, len); - if (r >= 0) { - count(r); - } - return r; - } - private void count(int c) { - compressedBytesReadFromCurrentEntry += c; - } - }; - final LinkedList methods = new LinkedList<>(); - for (final Coder coder : folder.getOrderedCoders()) { - if (coder.numInStreams != 1 || coder.numOutStreams != 1) { - throw new IOException("Multi input/output stream coders are not yet supported"); - } - final SevenZMethod method = SevenZMethod.byId(coder.decompressionMethodId); - inputStreamStack = Coders.addDecoder(fileName, inputStreamStack, - folder.getUnpackSizeForCoder(coder), coder, password); - methods.addFirst(new SevenZMethodConfiguration(method, - Coders.findByMethod(method).getOptionsFromCoder(coder, inputStreamStack))); - } - entry.setContentMethods(methods); - if (folder.hasCrc) { - return new CRC32VerifyingInputStream(inputStreamStack, - folder.getUnpackSize(), folder.crc); - } - return inputStreamStack; - } - - /** - * Reads a byte of data. - * - * @return the byte read, or -1 if end of input is reached - * @throws IOException - * if an I/O error has occurred - */ - public int read() throws IOException { - int b = getCurrentStream().read(); - if (b >= 0) { - uncompressedBytesReadFromCurrentEntry++; - } - return b; - } - - private InputStream getCurrentStream() throws IOException { - if (archive.files[currentEntryIndex].getSize() == 0) { - return new ByteArrayInputStream(new byte[0]); - } - if (deferredBlockStreams.isEmpty()) { - throw new IllegalStateException("No current 7z entry (call getNextEntry() first)."); - } - - while (deferredBlockStreams.size() > 1) { - // In solid compression mode we need to decompress all leading folder' - // streams to get access to an entry. We defer this until really needed - // so that entire blocks can be skipped without wasting time for decompression. - try (final InputStream stream = deferredBlockStreams.remove(0)) { - IOUtils.skip(stream, Long.MAX_VALUE); - } - compressedBytesReadFromCurrentEntry = 0; - } - - return deferredBlockStreams.get(0); - } - - /** - * Reads data into an array of bytes. - * - * @param b the array to write data to - * @return the number of bytes read, or -1 if end of input is reached - * @throws IOException - * if an I/O error has occurred - */ - public int read(final byte[] b) throws IOException { - return read(b, 0, b.length); - } - - /** - * Reads data into an array of bytes. - * - * @param b the array to write data to - * @param off offset into the buffer to start filling at - * @param len of bytes to read - * @return the number of bytes read, or -1 if end of input is reached - * @throws IOException - * if an I/O error has occurred - */ - public int read(final byte[] b, final int off, final int len) throws IOException { - int cnt = getCurrentStream().read(b, off, len); - if (cnt > 0) { - uncompressedBytesReadFromCurrentEntry += cnt; - } - return cnt; - } - - /** - * Provides statistics for bytes read from the current entry. - * - * @return statistics for bytes read from the current entry - * @since 1.17 - */ - public InputStreamStatistics getStatisticsForCurrentEntry() { - return new InputStreamStatistics() { - @Override - public long getCompressedCount() { - return compressedBytesReadFromCurrentEntry; - } - @Override - public long getUncompressedCount() { - return uncompressedBytesReadFromCurrentEntry; - } - }; - } - - private static long readUint64(final ByteBuffer in) throws IOException { - // long rather than int as it might get shifted beyond the range of an int - final long firstByte = getUnsignedByte(in); - int mask = 0x80; - long value = 0; - for (int i = 0; i < 8; i++) { - if ((firstByte & mask) == 0) { - return value | ((firstByte & (mask - 1)) << (8 * i)); - } - final long nextByte = getUnsignedByte(in); - value |= nextByte << (8 * i); - mask >>>= 1; - } - return value; - } - - private static int getUnsignedByte(ByteBuffer buf) { - return buf.get() & 0xff; - } - - /** - * Checks if the signature matches what is expected for a 7z file. - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this is the signature of a 7z archive. - * @since 1.8 - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < sevenZSignature.length) { - return false; - } - - for (int i = 0; i < sevenZSignature.length; i++) { - if (signature[i] != sevenZSignature[i]) { - return false; - } - } - return true; - } - - private static long skipBytesFully(final ByteBuffer input, long bytesToSkip) throws IOException { - if (bytesToSkip < 1) { - return 0; - } - int current = input.position(); - int maxSkip = input.remaining(); - if (maxSkip < bytesToSkip) { - bytesToSkip = maxSkip; - } - input.position(current + (int) bytesToSkip); - return bytesToSkip; - } - - private void readFully(ByteBuffer buf) throws IOException { - buf.rewind(); - IOUtils.readFully(channel, buf); - buf.flip(); - } - - @Override - public String toString() { - return archive.toString(); - } - - private static final CharsetEncoder PASSWORD_ENCODER = StandardCharsets.UTF_16LE.newEncoder(); - - private static byte[] utf16Decode(char[] chars) throws IOException { - if (chars == null) { - return null; - } - ByteBuffer encoded = PASSWORD_ENCODER.encode(CharBuffer.wrap(chars)); - if (encoded.hasArray()) { - return encoded.array(); - } - byte[] e = new byte[encoded.remaining()]; - encoded.get(e); - return e; - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/SevenZMethod.java b/src/org/apache/commons/compress/archivers/sevenz/SevenZMethod.java deleted file mode 100644 index 3c446cc2c1e..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/SevenZMethod.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.util.Arrays; - -/** - * The (partially) supported compression/encryption methods used in 7z archives. - * - *

All methods with a _FILTER suffix are used as preprocessors with - * the goal of creating a better compression ratio with the compressor - * that comes next in the chain of methods. 7z will in general only - * allow them to be used together with a "real" compression method but - * Commons Compress doesn't enforce this.

- * - *

The BCJ_ filters work on executable files for the given platform - * and convert relative addresses to absolute addresses in CALL - * instructions. This means they are only useful when applied to - * executables of the chosen platform.

- */ -public enum SevenZMethod { - /** no compression at all */ - COPY(new byte[] { (byte)0x00 }), - /** LZMA - only supported when reading */ - LZMA(new byte[] { (byte)0x03, (byte)0x01, (byte)0x01 }), - /** LZMA2 */ - LZMA2(new byte[] { (byte)0x21 }), - /** Deflate */ - DEFLATE(new byte[] { (byte)0x04, (byte)0x01, (byte)0x08 }), - /** - * Deflate64 - * @since 1.16 - */ - DEFLATE64(new byte[] { (byte)0x04, (byte)0x01, (byte)0x09 }), - /** BZIP2 */ - BZIP2(new byte[] { (byte)0x04, (byte)0x02, (byte)0x02 }), - /** - * AES encryption with a key length of 256 bit using SHA256 for - * hashes - only supported when reading - */ - AES256SHA256(new byte[] { (byte)0x06, (byte)0xf1, (byte)0x07, (byte)0x01 }), - /** - * BCJ x86 platform version 1. - * @since 1.8 - */ - BCJ_X86_FILTER(new byte[] { 0x03, 0x03, 0x01, 0x03 }), - /** - * BCJ PowerPC platform. - * @since 1.8 - */ - BCJ_PPC_FILTER(new byte[] { 0x03, 0x03, 0x02, 0x05 }), - /** - * BCJ I64 platform. - * @since 1.8 - */ - BCJ_IA64_FILTER(new byte[] { 0x03, 0x03, 0x04, 0x01 }), - /** - * BCJ ARM platform. - * @since 1.8 - */ - BCJ_ARM_FILTER(new byte[] { 0x03, 0x03, 0x05, 0x01 }), - /** - * BCJ ARM Thumb platform. - * @since 1.8 - */ - BCJ_ARM_THUMB_FILTER(new byte[] { 0x03, 0x03, 0x07, 0x01 }), - /** - * BCJ Sparc platform. - * @since 1.8 - */ - BCJ_SPARC_FILTER(new byte[] { 0x03, 0x03, 0x08, 0x05 }), - /** - * Delta filter. - * @since 1.8 - */ - DELTA_FILTER(new byte[] { 0x03 }); - - private final byte[] id; - - SevenZMethod(final byte[] id) { - this.id = id; - } - - byte[] getId() { - final byte[] copy = new byte[id.length]; - System.arraycopy(id, 0, copy, 0, id.length); - return copy; - } - - static SevenZMethod byId(final byte[] id) { - for (final SevenZMethod m : SevenZMethod.class.getEnumConstants()) { - if (Arrays.equals(m.id, id)) { - return m; - } - } - return null; - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/SevenZMethodConfiguration.java b/src/org/apache/commons/compress/archivers/sevenz/SevenZMethodConfiguration.java deleted file mode 100644 index bc47ee0a638..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/SevenZMethodConfiguration.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -/** - * Combines a SevenZMethod with configuration options for the method. - * - *

The exact type and interpretation of options depends on the - * method being configured. Currently supported are:

- * - * - * - * - * - * - * - * - *
MethodOption TypeDescription
BZIP2NumberBlock Size - an number between 1 and 9
DEFLATENumberCompression Level - an number between 1 and 9
LZMA2NumberDictionary Size - a number between 4096 and 768 MiB (768 << 20)
LZMA2org.tukaani.xz.LZMA2OptionsWhole set of LZMA2 options.
DELTA_FILTERNumberDelta Distance - a number between 1 and 256
- * - * @Immutable - * @since 1.8 - */ -public class SevenZMethodConfiguration { - private final SevenZMethod method; - private final Object options; - - /** - * Doesn't configure any additional options. - * @param method the method to use - */ - public SevenZMethodConfiguration(final SevenZMethod method) { - this(method, null); - } - - /** - * Specifies and method plus configuration options. - * @param method the method to use - * @param options the options to use - * @throws IllegalArgumentException if the method doesn't understand the options specified. - */ - public SevenZMethodConfiguration(final SevenZMethod method, final Object options) { - this.method = method; - this.options = options; - if (options != null && !Coders.findByMethod(method).canAcceptOptions(options)) { - throw new IllegalArgumentException("The " + method + " method doesn't support options of type " - + options.getClass()); - } - } - - /** - * The specified method. - * @return the method - */ - public SevenZMethod getMethod() { - return method; - } - - /** - * The specified options. - * @return the options - */ - public Object getOptions() { - return options; - } - -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java b/src/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java deleted file mode 100644 index 2ed21752d4f..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/SevenZOutputFile.java +++ /dev/null @@ -1,808 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.LinkedList; -import java.util.Map; -import java.util.zip.CRC32; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.utils.CountingOutputStream; - -/** - * Writes a 7z file. - * @since 1.6 - */ -public class SevenZOutputFile implements Closeable { - private final SeekableByteChannel channel; - private final List files = new ArrayList<>(); - private int numNonEmptyStreams = 0; - private final CRC32 crc32 = new CRC32(); - private final CRC32 compressedCrc32 = new CRC32(); - private long fileBytesWritten = 0; - private boolean finished = false; - private CountingOutputStream currentOutputStream; - private CountingOutputStream[] additionalCountingStreams; - private Iterable contentMethods = - Collections.singletonList(new SevenZMethodConfiguration(SevenZMethod.LZMA2)); - private final Map additionalSizes = new HashMap<>(); - - /** - * Opens file to write a 7z archive to. - * - * @param filename the file to write to - * @throws IOException if opening the file fails - */ - public SevenZOutputFile(final File filename) throws IOException { - this(Files.newByteChannel(filename.toPath(), - EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE, - StandardOpenOption.TRUNCATE_EXISTING))); - } - - /** - * Prepares channel to write a 7z archive to. - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to write to an in-memory archive.

- * - * @param channel the channel to write to - * @throws IOException if the channel cannot be positioned properly - * @since 1.13 - */ - public SevenZOutputFile(final SeekableByteChannel channel) throws IOException { - this.channel = channel; - channel.position(SevenZFile.SIGNATURE_HEADER_SIZE); - } - - /** - * Sets the default compression method to use for entry contents - the - * default is LZMA2. - * - *

Currently only {@link SevenZMethod#COPY}, {@link - * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link - * SevenZMethod#DEFLATE} are supported.

- * - *

This is a short form for passing a single-element iterable - * to {@link #setContentMethods}.

- * @param method the default compression method - */ - public void setContentCompression(final SevenZMethod method) { - setContentMethods(Collections.singletonList(new SevenZMethodConfiguration(method))); - } - - /** - * Sets the default (compression) methods to use for entry contents - the - * default is LZMA2. - * - *

Currently only {@link SevenZMethod#COPY}, {@link - * SevenZMethod#LZMA2}, {@link SevenZMethod#BZIP2} and {@link - * SevenZMethod#DEFLATE} are supported.

- * - *

The methods will be consulted in iteration order to create - * the final output.

- * - * @since 1.8 - * @param methods the default (compression) methods - */ - public void setContentMethods(final Iterable methods) { - this.contentMethods = reverse(methods); - } - - /** - * Closes the archive, calling {@link #finish} if necessary. - * - * @throws IOException on error - */ - @Override - public void close() throws IOException { - if (!finished) { - finish(); - } - channel.close(); - } - - /** - * Create an archive entry using the inputFile and entryName provided. - * - * @param inputFile file to create an entry from - * @param entryName the name to use - * @return the ArchiveEntry set up with details from the file - * - * @throws IOException on error - */ - public SevenZArchiveEntry createArchiveEntry(final File inputFile, - final String entryName) throws IOException { - final SevenZArchiveEntry entry = new SevenZArchiveEntry(); - entry.setDirectory(inputFile.isDirectory()); - entry.setName(entryName); - entry.setLastModifiedDate(new Date(inputFile.lastModified())); - return entry; - } - - /** - * Records an archive entry to add. - * - * The caller must then write the content to the archive and call - * {@link #closeArchiveEntry()} to complete the process. - * - * @param archiveEntry describes the entry - * @throws IOException on error - */ - public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException { - final SevenZArchiveEntry entry = (SevenZArchiveEntry) archiveEntry; - files.add(entry); - } - - /** - * Closes the archive entry. - * @throws IOException on error - */ - public void closeArchiveEntry() throws IOException { - if (currentOutputStream != null) { - currentOutputStream.flush(); - currentOutputStream.close(); - } - - final SevenZArchiveEntry entry = files.get(files.size() - 1); - if (fileBytesWritten > 0) { // this implies currentOutputStream != null - entry.setHasStream(true); - ++numNonEmptyStreams; - entry.setSize(currentOutputStream.getBytesWritten()); //NOSONAR - entry.setCompressedSize(fileBytesWritten); - entry.setCrcValue(crc32.getValue()); - entry.setCompressedCrcValue(compressedCrc32.getValue()); - entry.setHasCrc(true); - if (additionalCountingStreams != null) { - final long[] sizes = new long[additionalCountingStreams.length]; - for (int i = 0; i < additionalCountingStreams.length; i++) { - sizes[i] = additionalCountingStreams[i].getBytesWritten(); - } - additionalSizes.put(entry, sizes); - } - } else { - entry.setHasStream(false); - entry.setSize(0); - entry.setCompressedSize(0); - entry.setHasCrc(false); - } - currentOutputStream = null; - additionalCountingStreams = null; - crc32.reset(); - compressedCrc32.reset(); - fileBytesWritten = 0; - } - - /** - * Writes a byte to the current archive entry. - * @param b The byte to be written. - * @throws IOException on error - */ - public void write(final int b) throws IOException { - getCurrentOutputStream().write(b); - } - - /** - * Writes a byte array to the current archive entry. - * @param b The byte array to be written. - * @throws IOException on error - */ - public void write(final byte[] b) throws IOException { - write(b, 0, b.length); - } - - /** - * Writes part of a byte array to the current archive entry. - * @param b The byte array to be written. - * @param off offset into the array to start writing from - * @param len number of bytes to write - * @throws IOException on error - */ - public void write(final byte[] b, final int off, final int len) throws IOException { - if (len > 0) { - getCurrentOutputStream().write(b, off, len); - } - } - - /** - * Finishes the addition of entries to this archive, without closing it. - * - * @throws IOException if archive is already closed. - */ - public void finish() throws IOException { - if (finished) { - throw new IOException("This archive has already been finished"); - } - finished = true; - - final long headerPosition = channel.position(); - - final ByteArrayOutputStream headerBaos = new ByteArrayOutputStream(); - final DataOutputStream header = new DataOutputStream(headerBaos); - - writeHeader(header); - header.flush(); - final byte[] headerBytes = headerBaos.toByteArray(); - channel.write(ByteBuffer.wrap(headerBytes)); - - final CRC32 crc32 = new CRC32(); - crc32.update(headerBytes); - - ByteBuffer bb = ByteBuffer.allocate(SevenZFile.sevenZSignature.length - + 2 /* version */ - + 4 /* start header CRC */ - + 8 /* next header position */ - + 8 /* next header length */ - + 4 /* next header CRC */) - .order(ByteOrder.LITTLE_ENDIAN); - // signature header - channel.position(0); - bb.put(SevenZFile.sevenZSignature); - // version - bb.put((byte) 0).put((byte) 2); - - // placeholder for start header CRC - bb.putInt(0); - - // start header - bb.putLong(headerPosition - SevenZFile.SIGNATURE_HEADER_SIZE) - .putLong(0xffffFFFFL & headerBytes.length) - .putInt((int) crc32.getValue()); - crc32.reset(); - crc32.update(bb.array(), SevenZFile.sevenZSignature.length + 6, 20); - bb.putInt(SevenZFile.sevenZSignature.length + 2, (int) crc32.getValue()); - bb.flip(); - channel.write(bb); - } - - /* - * Creation of output stream is deferred until data is actually - * written as some codecs might write header information even for - * empty streams and directories otherwise. - */ - private OutputStream getCurrentOutputStream() throws IOException { - if (currentOutputStream == null) { - currentOutputStream = setupFileOutputStream(); - } - return currentOutputStream; - } - - private CountingOutputStream setupFileOutputStream() throws IOException { - if (files.isEmpty()) { - throw new IllegalStateException("No current 7z entry"); - } - - OutputStream out = new OutputStreamWrapper(); - final ArrayList moreStreams = new ArrayList<>(); - boolean first = true; - for (final SevenZMethodConfiguration m : getContentMethods(files.get(files.size() - 1))) { - if (!first) { - final CountingOutputStream cos = new CountingOutputStream(out); - moreStreams.add(cos); - out = cos; - } - out = Coders.addEncoder(out, m.getMethod(), m.getOptions()); - first = false; - } - if (!moreStreams.isEmpty()) { - additionalCountingStreams = moreStreams.toArray(new CountingOutputStream[moreStreams.size()]); - } - return new CountingOutputStream(out) { - @Override - public void write(final int b) throws IOException { - super.write(b); - crc32.update(b); - } - - @Override - public void write(final byte[] b) throws IOException { - super.write(b); - crc32.update(b); - } - - @Override - public void write(final byte[] b, final int off, final int len) - throws IOException { - super.write(b, off, len); - crc32.update(b, off, len); - } - }; - } - - private Iterable getContentMethods(final SevenZArchiveEntry entry) { - final Iterable ms = entry.getContentMethods(); - return ms == null ? contentMethods : ms; - } - - private void writeHeader(final DataOutput header) throws IOException { - header.write(NID.kHeader); - - header.write(NID.kMainStreamsInfo); - writeStreamsInfo(header); - writeFilesInfo(header); - header.write(NID.kEnd); - } - - private void writeStreamsInfo(final DataOutput header) throws IOException { - if (numNonEmptyStreams > 0) { - writePackInfo(header); - writeUnpackInfo(header); - } - - writeSubStreamsInfo(header); - - header.write(NID.kEnd); - } - - private void writePackInfo(final DataOutput header) throws IOException { - header.write(NID.kPackInfo); - - writeUint64(header, 0); - writeUint64(header, 0xffffFFFFL & numNonEmptyStreams); - - header.write(NID.kSize); - for (final SevenZArchiveEntry entry : files) { - if (entry.hasStream()) { - writeUint64(header, entry.getCompressedSize()); - } - } - - header.write(NID.kCRC); - header.write(1); // "allAreDefined" == true - for (final SevenZArchiveEntry entry : files) { - if (entry.hasStream()) { - header.writeInt(Integer.reverseBytes((int) entry.getCompressedCrcValue())); - } - } - - header.write(NID.kEnd); - } - - private void writeUnpackInfo(final DataOutput header) throws IOException { - header.write(NID.kUnpackInfo); - - header.write(NID.kFolder); - writeUint64(header, numNonEmptyStreams); - header.write(0); - for (final SevenZArchiveEntry entry : files) { - if (entry.hasStream()) { - writeFolder(header, entry); - } - } - - header.write(NID.kCodersUnpackSize); - for (final SevenZArchiveEntry entry : files) { - if (entry.hasStream()) { - final long[] moreSizes = additionalSizes.get(entry); - if (moreSizes != null) { - for (final long s : moreSizes) { - writeUint64(header, s); - } - } - writeUint64(header, entry.getSize()); - } - } - - header.write(NID.kCRC); - header.write(1); // "allAreDefined" == true - for (final SevenZArchiveEntry entry : files) { - if (entry.hasStream()) { - header.writeInt(Integer.reverseBytes((int) entry.getCrcValue())); - } - } - - header.write(NID.kEnd); - } - - private void writeFolder(final DataOutput header, final SevenZArchiveEntry entry) throws IOException { - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - int numCoders = 0; - for (final SevenZMethodConfiguration m : getContentMethods(entry)) { - numCoders++; - writeSingleCodec(m, bos); - } - - writeUint64(header, numCoders); - header.write(bos.toByteArray()); - for (long i = 0; i < numCoders - 1; i++) { - writeUint64(header, i + 1); - writeUint64(header, i); - } - } - - private void writeSingleCodec(final SevenZMethodConfiguration m, final OutputStream bos) throws IOException { - final byte[] id = m.getMethod().getId(); - final byte[] properties = Coders.findByMethod(m.getMethod()) - .getOptionsAsProperties(m.getOptions()); - - int codecFlags = id.length; - if (properties.length > 0) { - codecFlags |= 0x20; - } - bos.write(codecFlags); - bos.write(id); - - if (properties.length > 0) { - bos.write(properties.length); - bos.write(properties); - } - } - - private void writeSubStreamsInfo(final DataOutput header) throws IOException { - header.write(NID.kSubStreamsInfo); -// -// header.write(NID.kCRC); -// header.write(1); -// for (final SevenZArchiveEntry entry : files) { -// if (entry.getHasCrc()) { -// header.writeInt(Integer.reverseBytes(entry.getCrc())); -// } -// } -// - header.write(NID.kEnd); - } - - private void writeFilesInfo(final DataOutput header) throws IOException { - header.write(NID.kFilesInfo); - - writeUint64(header, files.size()); - - writeFileEmptyStreams(header); - writeFileEmptyFiles(header); - writeFileAntiItems(header); - writeFileNames(header); - writeFileCTimes(header); - writeFileATimes(header); - writeFileMTimes(header); - writeFileWindowsAttributes(header); - header.write(NID.kEnd); - } - - private void writeFileEmptyStreams(final DataOutput header) throws IOException { - boolean hasEmptyStreams = false; - for (final SevenZArchiveEntry entry : files) { - if (!entry.hasStream()) { - hasEmptyStreams = true; - break; - } - } - if (hasEmptyStreams) { - header.write(NID.kEmptyStream); - final BitSet emptyStreams = new BitSet(files.size()); - for (int i = 0; i < files.size(); i++) { - emptyStreams.set(i, !files.get(i).hasStream()); - } - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - writeBits(out, emptyStreams, files.size()); - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - } - - private void writeFileEmptyFiles(final DataOutput header) throws IOException { - boolean hasEmptyFiles = false; - int emptyStreamCounter = 0; - final BitSet emptyFiles = new BitSet(0); - for (final SevenZArchiveEntry file1 : files) { - if (!file1.hasStream()) { - final boolean isDir = file1.isDirectory(); - emptyFiles.set(emptyStreamCounter++, !isDir); - hasEmptyFiles |= !isDir; - } - } - if (hasEmptyFiles) { - header.write(NID.kEmptyFile); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - writeBits(out, emptyFiles, emptyStreamCounter); - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - } - - private void writeFileAntiItems(final DataOutput header) throws IOException { - boolean hasAntiItems = false; - final BitSet antiItems = new BitSet(0); - int antiItemCounter = 0; - for (final SevenZArchiveEntry file1 : files) { - if (!file1.hasStream()) { - final boolean isAnti = file1.isAntiItem(); - antiItems.set(antiItemCounter++, isAnti); - hasAntiItems |= isAnti; - } - } - if (hasAntiItems) { - header.write(NID.kAnti); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - writeBits(out, antiItems, antiItemCounter); - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - } - - private void writeFileNames(final DataOutput header) throws IOException { - header.write(NID.kName); - - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - out.write(0); - for (final SevenZArchiveEntry entry : files) { - out.write(entry.getName().getBytes("UTF-16LE")); - out.writeShort(0); - } - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - - private void writeFileCTimes(final DataOutput header) throws IOException { - int numCreationDates = 0; - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasCreationDate()) { - ++numCreationDates; - } - } - if (numCreationDates > 0) { - header.write(NID.kCTime); - - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - if (numCreationDates != files.size()) { - out.write(0); - final BitSet cTimes = new BitSet(files.size()); - for (int i = 0; i < files.size(); i++) { - cTimes.set(i, files.get(i).getHasCreationDate()); - } - writeBits(out, cTimes, files.size()); - } else { - out.write(1); // "allAreDefined" == true - } - out.write(0); - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasCreationDate()) { - out.writeLong(Long.reverseBytes( - SevenZArchiveEntry.javaTimeToNtfsTime(entry.getCreationDate()))); - } - } - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - } - - private void writeFileATimes(final DataOutput header) throws IOException { - int numAccessDates = 0; - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasAccessDate()) { - ++numAccessDates; - } - } - if (numAccessDates > 0) { - header.write(NID.kATime); - - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - if (numAccessDates != files.size()) { - out.write(0); - final BitSet aTimes = new BitSet(files.size()); - for (int i = 0; i < files.size(); i++) { - aTimes.set(i, files.get(i).getHasAccessDate()); - } - writeBits(out, aTimes, files.size()); - } else { - out.write(1); // "allAreDefined" == true - } - out.write(0); - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasAccessDate()) { - out.writeLong(Long.reverseBytes( - SevenZArchiveEntry.javaTimeToNtfsTime(entry.getAccessDate()))); - } - } - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - } - - private void writeFileMTimes(final DataOutput header) throws IOException { - int numLastModifiedDates = 0; - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasLastModifiedDate()) { - ++numLastModifiedDates; - } - } - if (numLastModifiedDates > 0) { - header.write(NID.kMTime); - - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - if (numLastModifiedDates != files.size()) { - out.write(0); - final BitSet mTimes = new BitSet(files.size()); - for (int i = 0; i < files.size(); i++) { - mTimes.set(i, files.get(i).getHasLastModifiedDate()); - } - writeBits(out, mTimes, files.size()); - } else { - out.write(1); // "allAreDefined" == true - } - out.write(0); - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasLastModifiedDate()) { - out.writeLong(Long.reverseBytes( - SevenZArchiveEntry.javaTimeToNtfsTime(entry.getLastModifiedDate()))); - } - } - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - } - - private void writeFileWindowsAttributes(final DataOutput header) throws IOException { - int numWindowsAttributes = 0; - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasWindowsAttributes()) { - ++numWindowsAttributes; - } - } - if (numWindowsAttributes > 0) { - header.write(NID.kWinAttributes); - - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream out = new DataOutputStream(baos); - if (numWindowsAttributes != files.size()) { - out.write(0); - final BitSet attributes = new BitSet(files.size()); - for (int i = 0; i < files.size(); i++) { - attributes.set(i, files.get(i).getHasWindowsAttributes()); - } - writeBits(out, attributes, files.size()); - } else { - out.write(1); // "allAreDefined" == true - } - out.write(0); - for (final SevenZArchiveEntry entry : files) { - if (entry.getHasWindowsAttributes()) { - out.writeInt(Integer.reverseBytes(entry.getWindowsAttributes())); - } - } - out.flush(); - final byte[] contents = baos.toByteArray(); - writeUint64(header, contents.length); - header.write(contents); - } - } - - private void writeUint64(final DataOutput header, long value) throws IOException { - int firstByte = 0; - int mask = 0x80; - int i; - for (i = 0; i < 8; i++) { - if (value < ((1L << ( 7 * (i + 1))))) { - firstByte |= (value >>> (8 * i)); - break; - } - firstByte |= mask; - mask >>>= 1; - } - header.write(firstByte); - for (; i > 0; i--) { - header.write((int) (0xff & value)); - value >>>= 8; - } - } - - private void writeBits(final DataOutput header, final BitSet bits, final int length) throws IOException { - int cache = 0; - int shift = 7; - for (int i = 0; i < length; i++) { - cache |= ((bits.get(i) ? 1 : 0) << shift); - if (--shift < 0) { - header.write(cache); - shift = 7; - cache = 0; - } - } - if (shift != 7) { - header.write(cache); - } - } - - private static Iterable reverse(final Iterable i) { - final LinkedList l = new LinkedList<>(); - for (final T t : i) { - l.addFirst(t); - } - return l; - } - - private class OutputStreamWrapper extends OutputStream { - private static final int BUF_SIZE = 8192; - private final ByteBuffer buffer = ByteBuffer.allocate(BUF_SIZE); - @Override - public void write(final int b) throws IOException { - buffer.clear(); - buffer.put((byte) b).flip(); - channel.write(buffer); - compressedCrc32.update(b); - fileBytesWritten++; - } - - @Override - public void write(final byte[] b) throws IOException { - OutputStreamWrapper.this.write(b, 0, b.length); - } - - @Override - public void write(final byte[] b, final int off, final int len) - throws IOException { - if (len > BUF_SIZE) { - channel.write(ByteBuffer.wrap(b, off, len)); - } else { - buffer.clear(); - buffer.put(b, off, len).flip(); - channel.write(buffer); - } - compressedCrc32.update(b, off, len); - fileBytesWritten += len; - } - - @Override - public void flush() throws IOException { - // no reason to flush the channel - } - - @Override - public void close() throws IOException { - // the file will be closed by the containing class's close method - } - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/StartHeader.java b/src/org/apache/commons/compress/archivers/sevenz/StartHeader.java deleted file mode 100644 index a33aca70fa8..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/StartHeader.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -class StartHeader { - long nextHeaderOffset; - long nextHeaderSize; - long nextHeaderCrc; -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/StreamMap.java b/src/org/apache/commons/compress/archivers/sevenz/StreamMap.java deleted file mode 100644 index 9a10e1e847e..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/StreamMap.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -/// Map between folders, files and streams. -class StreamMap { - /// The first Archive.packStream index of each folder. - int[] folderFirstPackStreamIndex; - /// Offset to beginning of this pack stream's data, relative to the beginning of the first pack stream. - long[] packStreamOffsets; - /// Index of first file for each folder. - int[] folderFirstFileIndex; - /// Index of folder for each file. - int[] fileFolderIndex; - - @Override - public String toString() { - return "StreamMap with indices of " + folderFirstPackStreamIndex.length - + " folders, offsets of " + packStreamOffsets.length + " packed streams," - + " first files of " + folderFirstFileIndex.length + " folders and" - + " folder indices for " + fileFolderIndex.length + " files"; - } -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/SubStreamsInfo.java b/src/org/apache/commons/compress/archivers/sevenz/SubStreamsInfo.java deleted file mode 100644 index 95fabc635d3..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/SubStreamsInfo.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.sevenz; - -import java.util.BitSet; - -/// Properties for non-empty files. -class SubStreamsInfo { - /// Unpacked size of each unpacked stream. - long[] unpackSizes; - /// Whether CRC is present for each unpacked stream. - BitSet hasCrc; - /// CRCs of unpacked streams, if present. - long[] crcs; -} diff --git a/src/org/apache/commons/compress/archivers/sevenz/package.html b/src/org/apache/commons/compress/archivers/sevenz/package.html deleted file mode 100644 index 975703b3850..00000000000 --- a/src/org/apache/commons/compress/archivers/sevenz/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides classes for reading and writing archives using - the 7z format.

- - diff --git a/src/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java b/src/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java deleted file mode 100644 index ac98f0afa2f..00000000000 --- a/src/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java +++ /dev/null @@ -1,1440 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.tar; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.utils.ArchiveUtils; - -/** - * This class represents an entry in a Tar archive. It consists - * of the entry's header, as well as the entry's File. Entries - * can be instantiated in one of three ways, depending on how - * they are to be used. - *

- * TarEntries that are created from the header bytes read from - * an archive are instantiated with the TarEntry( byte[] ) - * constructor. These entries will be used when extracting from - * or listing the contents of an archive. These entries have their - * header filled in using the header bytes. They also set the File - * to null, since they reference an archive entry not a file. - *

- * TarEntries that are created from Files that are to be written - * into an archive are instantiated with the TarEntry( File ) - * constructor. These entries have their header filled in using - * the File's information. They also keep a reference to the File - * for convenience when writing entries. - *

- * Finally, TarEntries can be constructed from nothing but a name. - * This allows the programmer to construct the entry by hand, for - * instance when only an InputStream is available for writing to - * the archive, and the header information is constructed from - * other information. In this case the header fields are set to - * defaults and the File is set to null. - * - *

- * The C structure for a Tar Entry's header is: - *

- * struct header {
- * char name[100];     // TarConstants.NAMELEN    - offset   0
- * char mode[8];       // TarConstants.MODELEN    - offset 100
- * char uid[8];        // TarConstants.UIDLEN     - offset 108
- * char gid[8];        // TarConstants.GIDLEN     - offset 116
- * char size[12];      // TarConstants.SIZELEN    - offset 124
- * char mtime[12];     // TarConstants.MODTIMELEN - offset 136
- * char chksum[8];     // TarConstants.CHKSUMLEN  - offset 148
- * char linkflag[1];   //                         - offset 156
- * char linkname[100]; // TarConstants.NAMELEN    - offset 157
- * The following fields are only present in new-style POSIX tar archives:
- * char magic[6];      // TarConstants.MAGICLEN   - offset 257
- * char version[2];    // TarConstants.VERSIONLEN - offset 263
- * char uname[32];     // TarConstants.UNAMELEN   - offset 265
- * char gname[32];     // TarConstants.GNAMELEN   - offset 297
- * char devmajor[8];   // TarConstants.DEVLEN     - offset 329
- * char devminor[8];   // TarConstants.DEVLEN     - offset 337
- * char prefix[155];   // TarConstants.PREFIXLEN  - offset 345
- * // Used if "name" field is not long enough to hold the path
- * char pad[12];       // NULs                    - offset 500
- * } header;
- * All unused bytes are set to null.
- * New-style GNU tar files are slightly different from the above.
- * For values of size larger than 077777777777L (11 7s)
- * or uid and gid larger than 07777777L (7 7s)
- * the sign bit of the first byte is set, and the rest of the
- * field is the binary representation of the number.
- * See TarUtils.parseOctalOrBinary.
- * 
- * - *

- * The C structure for a old GNU Tar Entry's header is: - *

- * struct oldgnu_header {
- * char unused_pad1[345]; // TarConstants.PAD1LEN_GNU       - offset 0
- * char atime[12];        // TarConstants.ATIMELEN_GNU      - offset 345
- * char ctime[12];        // TarConstants.CTIMELEN_GNU      - offset 357
- * char offset[12];       // TarConstants.OFFSETLEN_GNU     - offset 369
- * char longnames[4];     // TarConstants.LONGNAMESLEN_GNU  - offset 381
- * char unused_pad2;      // TarConstants.PAD2LEN_GNU       - offset 385
- * struct sparse sp[4];   // TarConstants.SPARSELEN_GNU     - offset 386
- * char isextended;       // TarConstants.ISEXTENDEDLEN_GNU - offset 482
- * char realsize[12];     // TarConstants.REALSIZELEN_GNU   - offset 483
- * char unused_pad[17];   // TarConstants.PAD3LEN_GNU       - offset 495
- * };
- * 
- * Whereas, "struct sparse" is: - *
- * struct sparse {
- * char offset[12];   // offset 0
- * char numbytes[12]; // offset 12
- * };
- * 
- * - *

- * The C structure for a xstar (Jörg Schilling star) Tar Entry's header is: - *

- * struct star_header {
- *  char name[100];		// offset   0
- *  char mode[8];		// offset 100
- *  char uid[8];		// offset 108
- *  char gid[8];		// offset 116
- *  char size[12];		// offset 124
- *  char mtime[12];		// offset 136
- *  char chksum[8];		// offset 148
- *  char typeflag;		// offset 156
- *  char linkname[100];		// offset 157
- *  char magic[6];		// offset 257
- *  char version[2];		// offset 263
- *  char uname[32];		// offset 265
- *  char gname[32];		// offset 297
- *  char devmajor[8];		// offset 329
- *  char devminor[8];		// offset 337
- *  char prefix[131];		// offset 345
- *  char atime[12];             // offset 476
- *  char ctime[12];             // offset 488
- *  char mfill[8];              // offset 500
- *  char xmagic[4];             // offset 508  "tar"
- * };
- * 
- *

which is identical to new-style POSIX up to the first 130 bytes of the prefix.

- * - * @NotThreadSafe - */ - -public class TarArchiveEntry implements ArchiveEntry, TarConstants { - private static final TarArchiveEntry[] EMPTY_TAR_ARCHIVE_ENTRIES = new TarArchiveEntry[0]; - - /** The entry's name. */ - private String name = ""; - - /** Whether to allow leading slashes or drive names inside the name */ - private final boolean preserveAbsolutePath; - - /** The entry's permission mode. */ - private int mode; - - /** The entry's user id. */ - private long userId = 0; - - /** The entry's group id. */ - private long groupId = 0; - - /** The entry's size. */ - private long size = 0; - - /** The entry's modification time. */ - private long modTime; - - /** If the header checksum is reasonably correct. */ - private boolean checkSumOK; - - /** The entry's link flag. */ - private byte linkFlag; - - /** The entry's link name. */ - private String linkName = ""; - - /** The entry's magic tag. */ - private String magic = MAGIC_POSIX; - /** The version of the format */ - private String version = VERSION_POSIX; - - /** The entry's user name. */ - private String userName; - - /** The entry's group name. */ - private String groupName = ""; - - /** The entry's major device number. */ - private int devMajor = 0; - - /** The entry's minor device number. */ - private int devMinor = 0; - - /** If an extension sparse header follows. */ - private boolean isExtended; - - /** The entry's real size in case of a sparse file. */ - private long realSize; - - /** is this entry a GNU sparse entry using one of the PAX formats? */ - private boolean paxGNUSparse; - - /** is this entry a star sparse entry using the PAX header? */ - private boolean starSparse; - - /** The entry's file reference */ - private final File file; - - /** Extra, user supplied pax headers */ - private final Map extraPaxHeaders = new HashMap<>(); - - /** Maximum length of a user's name in the tar file */ - public static final int MAX_NAMELEN = 31; - - /** Default permissions bits for directories */ - public static final int DEFAULT_DIR_MODE = 040755; - - /** Default permissions bits for files */ - public static final int DEFAULT_FILE_MODE = 0100644; - - /** Convert millis to seconds */ - public static final int MILLIS_PER_SECOND = 1000; - - - /** - * Construct an empty entry and prepares the header values. - */ - private TarArchiveEntry(boolean preserveAbsolutePath) { - String user = System.getProperty("user.name", ""); - - if (user.length() > MAX_NAMELEN) { - user = user.substring(0, MAX_NAMELEN); - } - - this.userName = user; - this.file = null; - this.preserveAbsolutePath = preserveAbsolutePath; - } - - /** - * Construct an entry with only a name. This allows the programmer - * to construct the entry's header "by hand". File is set to null. - * - *

The entry's name will be the value of the {@code name} - * argument with all file separators replaced by forward slashes - * and leading slashes as well as Windows drive letters stripped.

- * - * @param name the entry name - */ - public TarArchiveEntry(final String name) { - this(name, false); - } - - /** - * Construct an entry with only a name. This allows the programmer - * to construct the entry's header "by hand". File is set to null. - * - *

The entry's name will be the value of the {@code name} - * argument with all file separators replaced by forward slashes. - * Leading slashes and Windows drive letters are stripped if - * {@code preserveAbsolutePath} is {@code false}.

- * - * @param name the entry name - * @param preserveAbsolutePath whether to allow leading slashes - * or drive letters in the name. - * - * @since 1.1 - */ - public TarArchiveEntry(String name, final boolean preserveAbsolutePath) { - this(preserveAbsolutePath); - - name = normalizeFileName(name, preserveAbsolutePath); - final boolean isDir = name.endsWith("/"); - - this.name = name; - this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE; - this.linkFlag = isDir ? LF_DIR : LF_NORMAL; - this.modTime = new Date().getTime() / MILLIS_PER_SECOND; - this.userName = ""; - } - - /** - * Construct an entry with a name and a link flag. - * - *

The entry's name will be the value of the {@code name} - * argument with all file separators replaced by forward slashes - * and leading slashes as well as Windows drive letters - * stripped.

- * - * @param name the entry name - * @param linkFlag the entry link flag. - */ - public TarArchiveEntry(final String name, final byte linkFlag) { - this(name, linkFlag, false); - } - - /** - * Construct an entry with a name and a link flag. - * - *

The entry's name will be the value of the {@code name} - * argument with all file separators replaced by forward slashes. - * Leading slashes and Windows drive letters are stripped if - * {@code preserveAbsolutePath} is {@code false}.

- * - * @param name the entry name - * @param linkFlag the entry link flag. - * @param preserveAbsolutePath whether to allow leading slashes - * or drive letters in the name. - * - * @since 1.5 - */ - public TarArchiveEntry(final String name, final byte linkFlag, final boolean preserveAbsolutePath) { - this(name, preserveAbsolutePath); - this.linkFlag = linkFlag; - if (linkFlag == LF_GNUTYPE_LONGNAME) { - magic = MAGIC_GNU; - version = VERSION_GNU_SPACE; - } - } - - /** - * Construct an entry for a file. File is set to file, and the - * header is constructed from information from the file. - * The name is set from the normalized file path. - * - *

The entry's name will be the value of the {@code file}'s - * path with all file separators replaced by forward slashes and - * leading slashes as well as Windows drive letters stripped. The - * name will end in a slash if the {@code file} represents a - * directory.

- * - * @param file The file that the entry represents. - */ - public TarArchiveEntry(final File file) { - this(file, file.getPath()); - } - - /** - * Construct an entry for a file. File is set to file, and the - * header is constructed from information from the file. - * - *

The entry's name will be the value of the {@code fileName} - * argument with all file separators replaced by forward slashes - * and leading slashes as well as Windows drive letters stripped. - * The name will end in a slash if the {@code file} represents a - * directory.

- * - * @param file The file that the entry represents. - * @param fileName the name to be used for the entry. - */ - public TarArchiveEntry(final File file, final String fileName) { - final String normalizedName = normalizeFileName(fileName, false); - this.file = file; - - if (file.isDirectory()) { - this.mode = DEFAULT_DIR_MODE; - this.linkFlag = LF_DIR; - - final int nameLength = normalizedName.length(); - if (nameLength == 0 || normalizedName.charAt(nameLength - 1) != '/') { - this.name = normalizedName + "/"; - } else { - this.name = normalizedName; - } - } else { - this.mode = DEFAULT_FILE_MODE; - this.linkFlag = LF_NORMAL; - this.size = file.length(); - this.name = normalizedName; - } - - this.modTime = file.lastModified() / MILLIS_PER_SECOND; - this.userName = ""; - preserveAbsolutePath = false; - } - - /** - * Construct an entry from an archive's header bytes. File is set - * to null. - * - * @param headerBuf The header bytes from a tar archive entry. - * @throws IllegalArgumentException if any of the numeric fields have an invalid format - */ - public TarArchiveEntry(final byte[] headerBuf) { - this(false); - parseTarHeader(headerBuf); - } - - /** - * Construct an entry from an archive's header bytes. File is set - * to null. - * - * @param headerBuf The header bytes from a tar archive entry. - * @param encoding encoding to use for file names - * @since 1.4 - * @throws IllegalArgumentException if any of the numeric fields have an invalid format - * @throws IOException on error - */ - public TarArchiveEntry(final byte[] headerBuf, final ZipEncoding encoding) - throws IOException { - this(false); - parseTarHeader(headerBuf, encoding); - } - - /** - * Determine if the two entries are equal. Equality is determined - * by the header names being equal. - * - * @param it Entry to be checked for equality. - * @return True if the entries are equal. - */ - public boolean equals(final TarArchiveEntry it) { - return it != null && getName().equals(it.getName()); - } - - /** - * Determine if the two entries are equal. Equality is determined - * by the header names being equal. - * - * @param it Entry to be checked for equality. - * @return True if the entries are equal. - */ - @Override - public boolean equals(final Object it) { - if (it == null || getClass() != it.getClass()) { - return false; - } - return equals((TarArchiveEntry) it); - } - - /** - * Hashcodes are based on entry names. - * - * @return the entry hashcode - */ - @Override - public int hashCode() { - return getName().hashCode(); - } - - /** - * Determine if the given entry is a descendant of this entry. - * Descendancy is determined by the name of the descendant - * starting with this entry's name. - * - * @param desc Entry to be checked as a descendent of this. - * @return True if entry is a descendant of this. - */ - public boolean isDescendent(final TarArchiveEntry desc) { - return desc.getName().startsWith(getName()); - } - - /** - * Get this entry's name. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return This entry's name. - */ - @Override - public String getName() { - return name; - } - - /** - * Set this entry's name. - * - * @param name This entry's new name. - */ - public void setName(final String name) { - this.name = normalizeFileName(name, this.preserveAbsolutePath); - } - - /** - * Set the mode for this entry - * - * @param mode the mode for this entry - */ - public void setMode(final int mode) { - this.mode = mode; - } - - /** - * Get this entry's link name. - * - * @return This entry's link name. - */ - public String getLinkName() { - return linkName; - } - - /** - * Set this entry's link name. - * - * @param link the link name to use. - * - * @since 1.1 - */ - public void setLinkName(final String link) { - this.linkName = link; - } - - /** - * Get this entry's user id. - * - * @return This entry's user id. - * @deprecated use #getLongUserId instead as user ids can be - * bigger than {@link Integer#MAX_VALUE} - */ - @Deprecated - public int getUserId() { - return (int) (userId & 0xffffffff); - } - - /** - * Set this entry's user id. - * - * @param userId This entry's new user id. - */ - public void setUserId(final int userId) { - setUserId((long) userId); - } - - /** - * Get this entry's user id. - * - * @return This entry's user id. - * @since 1.10 - */ - public long getLongUserId() { - return userId; - } - - /** - * Set this entry's user id. - * - * @param userId This entry's new user id. - * @since 1.10 - */ - public void setUserId(final long userId) { - this.userId = userId; - } - - /** - * Get this entry's group id. - * - * @return This entry's group id. - * @deprecated use #getLongGroupId instead as group ids can be - * bigger than {@link Integer#MAX_VALUE} - */ - @Deprecated - public int getGroupId() { - return (int) (groupId & 0xffffffff); - } - - /** - * Set this entry's group id. - * - * @param groupId This entry's new group id. - */ - public void setGroupId(final int groupId) { - setGroupId((long) groupId); - } - - /** - * Get this entry's group id. - * - * @since 1.10 - * @return This entry's group id. - */ - public long getLongGroupId() { - return groupId; - } - - /** - * Set this entry's group id. - * - * @since 1.10 - * @param groupId This entry's new group id. - */ - public void setGroupId(final long groupId) { - this.groupId = groupId; - } - - /** - * Get this entry's user name. - * - * @return This entry's user name. - */ - public String getUserName() { - return userName; - } - - /** - * Set this entry's user name. - * - * @param userName This entry's new user name. - */ - public void setUserName(final String userName) { - this.userName = userName; - } - - /** - * Get this entry's group name. - * - * @return This entry's group name. - */ - public String getGroupName() { - return groupName; - } - - /** - * Set this entry's group name. - * - * @param groupName This entry's new group name. - */ - public void setGroupName(final String groupName) { - this.groupName = groupName; - } - - /** - * Convenience method to set this entry's group and user ids. - * - * @param userId This entry's new user id. - * @param groupId This entry's new group id. - */ - public void setIds(final int userId, final int groupId) { - setUserId(userId); - setGroupId(groupId); - } - - /** - * Convenience method to set this entry's group and user names. - * - * @param userName This entry's new user name. - * @param groupName This entry's new group name. - */ - public void setNames(final String userName, final String groupName) { - setUserName(userName); - setGroupName(groupName); - } - - /** - * Set this entry's modification time. The parameter passed - * to this method is in "Java time". - * - * @param time This entry's new modification time. - */ - public void setModTime(final long time) { - modTime = time / MILLIS_PER_SECOND; - } - - /** - * Set this entry's modification time. - * - * @param time This entry's new modification time. - */ - public void setModTime(final Date time) { - modTime = time.getTime() / MILLIS_PER_SECOND; - } - - /** - * Set this entry's modification time. - * - * @return time This entry's new modification time. - */ - public Date getModTime() { - return new Date(modTime * MILLIS_PER_SECOND); - } - - @Override - public Date getLastModifiedDate() { - return getModTime(); - } - - /** - * Get this entry's checksum status. - * - * @return if the header checksum is reasonably correct - * @see TarUtils#verifyCheckSum(byte[]) - * @since 1.5 - */ - public boolean isCheckSumOK() { - return checkSumOK; - } - - /** - * Get this entry's file. - * - *

This method is only useful for entries created from a {@code - * File} but not for entries read from an archive.

- * - * @return This entry's file. - */ - public File getFile() { - return file; - } - - /** - * Get this entry's mode. - * - * @return This entry's mode. - */ - public int getMode() { - return mode; - } - - /** - * Get this entry's file size. - * - * @return This entry's file size. - */ - @Override - public long getSize() { - return size; - } - - /** - * Set this entry's file size. - * - * @param size This entry's new file size. - * @throws IllegalArgumentException if the size is < 0. - */ - public void setSize(final long size) { - if (size < 0){ - throw new IllegalArgumentException("Size is out of range: "+size); - } - this.size = size; - } - - /** - * Get this entry's major device number. - * - * @return This entry's major device number. - * @since 1.4 - */ - public int getDevMajor() { - return devMajor; - } - - /** - * Set this entry's major device number. - * - * @param devNo This entry's major device number. - * @throws IllegalArgumentException if the devNo is < 0. - * @since 1.4 - */ - public void setDevMajor(final int devNo) { - if (devNo < 0){ - throw new IllegalArgumentException("Major device number is out of " - + "range: " + devNo); - } - this.devMajor = devNo; - } - - /** - * Get this entry's minor device number. - * - * @return This entry's minor device number. - * @since 1.4 - */ - public int getDevMinor() { - return devMinor; - } - - /** - * Set this entry's minor device number. - * - * @param devNo This entry's minor device number. - * @throws IllegalArgumentException if the devNo is < 0. - * @since 1.4 - */ - public void setDevMinor(final int devNo) { - if (devNo < 0){ - throw new IllegalArgumentException("Minor device number is out of " - + "range: " + devNo); - } - this.devMinor = devNo; - } - - /** - * Indicates in case of an oldgnu sparse file if an extension - * sparse header follows. - * - * @return true if an extension oldgnu sparse header follows. - */ - public boolean isExtended() { - return isExtended; - } - - /** - * Get this entry's real file size in case of a sparse file. - * - * @return This entry's real file size. - */ - public long getRealSize() { - return realSize; - } - - /** - * Indicate if this entry is a GNU sparse block. - * - * @return true if this is a sparse extension provided by GNU tar - */ - public boolean isGNUSparse() { - return isOldGNUSparse() || isPaxGNUSparse(); - } - - /** - * Indicate if this entry is a GNU or star sparse block using the - * oldgnu format. - * - * @return true if this is a sparse extension provided by GNU tar or star - * @since 1.11 - */ - public boolean isOldGNUSparse() { - return linkFlag == LF_GNUTYPE_SPARSE; - } - - /** - * Indicate if this entry is a GNU sparse block using one of the - * PAX formats. - * - * @return true if this is a sparse extension provided by GNU tar - * @since 1.11 - */ - public boolean isPaxGNUSparse() { - return paxGNUSparse; - } - - /** - * Indicate if this entry is a star sparse block using PAX headers. - * - * @return true if this is a sparse extension provided by star - * @since 1.11 - */ - public boolean isStarSparse() { - return starSparse; - } - - /** - * Indicate if this entry is a GNU long linkname block - * - * @return true if this is a long name extension provided by GNU tar - */ - public boolean isGNULongLinkEntry() { - return linkFlag == LF_GNUTYPE_LONGLINK; - } - - /** - * Indicate if this entry is a GNU long name block - * - * @return true if this is a long name extension provided by GNU tar - */ - public boolean isGNULongNameEntry() { - return linkFlag == LF_GNUTYPE_LONGNAME; - } - - /** - * Check if this is a Pax header. - * - * @return {@code true} if this is a Pax header. - * - * @since 1.1 - * - */ - public boolean isPaxHeader() { - return linkFlag == LF_PAX_EXTENDED_HEADER_LC - || linkFlag == LF_PAX_EXTENDED_HEADER_UC; - } - - /** - * Check if this is a Pax header. - * - * @return {@code true} if this is a Pax header. - * - * @since 1.1 - */ - public boolean isGlobalPaxHeader() { - return linkFlag == LF_PAX_GLOBAL_EXTENDED_HEADER; - } - - /** - * Return whether or not this entry represents a directory. - * - * @return True if this entry is a directory. - */ - @Override - public boolean isDirectory() { - if (file != null) { - return file.isDirectory(); - } - - if (linkFlag == LF_DIR) { - return true; - } - - return !isPaxHeader() && !isGlobalPaxHeader() && getName().endsWith("/"); - } - - /** - * Check if this is a "normal file" - * - * @since 1.2 - * @return whether this is a "normal file" - */ - public boolean isFile() { - if (file != null) { - return file.isFile(); - } - if (linkFlag == LF_OLDNORM || linkFlag == LF_NORMAL) { - return true; - } - return !getName().endsWith("/"); - } - - /** - * Check if this is a symbolic link entry. - * - * @since 1.2 - * @return whether this is a symbolic link - */ - public boolean isSymbolicLink() { - return linkFlag == LF_SYMLINK; - } - - /** - * Check if this is a link entry. - * - * @since 1.2 - * @return whether this is a link entry - */ - public boolean isLink() { - return linkFlag == LF_LINK; - } - - /** - * Check if this is a character device entry. - * - * @since 1.2 - * @return whether this is a character device - */ - public boolean isCharacterDevice() { - return linkFlag == LF_CHR; - } - - /** - * Check if this is a block device entry. - * - * @since 1.2 - * @return whether this is a block device - */ - public boolean isBlockDevice() { - return linkFlag == LF_BLK; - } - - /** - * Check if this is a FIFO (pipe) entry. - * - * @since 1.2 - * @return whether this is a FIFO entry - */ - public boolean isFIFO() { - return linkFlag == LF_FIFO; - } - - /** - * Check whether this is a sparse entry. - * - * @return whether this is a sparse entry - * @since 1.11 - */ - public boolean isSparse() { - return isGNUSparse() || isStarSparse(); - } - - /** - * get extra PAX Headers - * @return read-only map containing any extra PAX Headers - * @since 1.15 - */ - public Map getExtraPaxHeaders() { - return Collections.unmodifiableMap(extraPaxHeaders); - } - - /** - * clear all extra PAX headers. - * @since 1.15 - */ - public void clearExtraPaxHeaders() { - extraPaxHeaders.clear(); - } - - /** - * add a PAX header to this entry. If the header corresponds to an existing field in the entry, - * that field will be set; otherwise the header will be added to the extraPaxHeaders Map - * @param name The full name of the header to set. - * @param value value of header. - * @since 1.15 - */ - public void addPaxHeader(String name,String value) { - processPaxHeader(name,value); - } - - /** - * get named extra PAX header - * @param name The full name of an extended PAX header to retrieve - * @return The value of the header, if any. - * @since 1.15 - */ - public String getExtraPaxHeader(String name) { - return extraPaxHeaders.get(name); - } - - /** - * Update the entry using a map of pax headers. - * @param headers - * @since 1.15 - */ - void updateEntryFromPaxHeaders(Map headers) { - for (final Map.Entry ent : headers.entrySet()) { - final String key = ent.getKey(); - final String val = ent.getValue(); - processPaxHeader(key, val, headers); - } - } - - /** - * process one pax header, using the entries extraPaxHeaders map as source for extra headers - * used when handling entries for sparse files. - * @param key - * @param val - * @since 1.15 - */ - private void processPaxHeader(String key, String val) { - processPaxHeader(key,val,extraPaxHeaders); - } - - /** - * Process one pax header, using the supplied map as source for extra headers to be used when handling - * entries for sparse files - * - * @param key the header name. - * @param val the header value. - * @param headers map of headers used for dealing with sparse file. - * @since 1.15 - */ - private void processPaxHeader(String key, String val, Map headers) { - /* - * The following headers are defined for Pax. - * atime, ctime, charset: cannot use these without changing TarArchiveEntry fields - * mtime - * comment - * gid, gname - * linkpath - * size - * uid,uname - * SCHILY.devminor, SCHILY.devmajor: don't have setters/getters for those - * - * GNU sparse files use additional members, we use - * GNU.sparse.size to detect the 0.0 and 0.1 versions and - * GNU.sparse.realsize for 1.0. - * - * star files use additional members of which we use - * SCHILY.filetype in order to detect star sparse files. - * - * If called from addExtraPaxHeader, these additional headers must be already present . - */ - switch (key) { - case "path": - setName(val); - break; - case "linkpath": - setLinkName(val); - break; - case "gid": - setGroupId(Long.parseLong(val)); - break; - case "gname": - setGroupName(val); - break; - case "uid": - setUserId(Long.parseLong(val)); - break; - case "uname": - setUserName(val); - break; - case "size": - setSize(Long.parseLong(val)); - break; - case "mtime": - setModTime((long) (Double.parseDouble(val) * 1000)); - break; - case "SCHILY.devminor": - setDevMinor(Integer.parseInt(val)); - break; - case "SCHILY.devmajor": - setDevMajor(Integer.parseInt(val)); - break; - case "GNU.sparse.size": - fillGNUSparse0xData(headers); - break; - case "GNU.sparse.realsize": - fillGNUSparse1xData(headers); - break; - case "SCHILY.filetype": - if ("sparse".equals(val)) { - fillStarSparseData(headers); - } - break; - default: - extraPaxHeaders.put(key,val); - } - } - - - - /** - * If this entry represents a file, and the file is a directory, return - * an array of TarEntries for this entry's children. - * - *

This method is only useful for entries created from a {@code - * File} but not for entries read from an archive.

- * - * @return An array of TarEntry's for this entry's children. - */ - public TarArchiveEntry[] getDirectoryEntries() { - if (file == null || !file.isDirectory()) { - return EMPTY_TAR_ARCHIVE_ENTRIES; - } - - final String[] list = file.list(); - if (list == null) { - return EMPTY_TAR_ARCHIVE_ENTRIES; - } - final TarArchiveEntry[] result = new TarArchiveEntry[list.length]; - - for (int i = 0; i < result.length; ++i) { - result[i] = new TarArchiveEntry(new File(file, list[i])); - } - - return result; - } - - /** - * Write an entry's header information to a header buffer. - * - *

This method does not use the star/GNU tar/BSD tar extensions.

- * - * @param outbuf The tar entry header buffer to fill in. - */ - public void writeEntryHeader(final byte[] outbuf) { - try { - writeEntryHeader(outbuf, TarUtils.DEFAULT_ENCODING, false); - } catch (final IOException ex) { - try { - writeEntryHeader(outbuf, TarUtils.FALLBACK_ENCODING, false); - } catch (final IOException ex2) { - // impossible - throw new RuntimeException(ex2); //NOSONAR - } - } - } - - /** - * Write an entry's header information to a header buffer. - * - * @param outbuf The tar entry header buffer to fill in. - * @param encoding encoding to use when writing the file name. - * @param starMode whether to use the star/GNU tar/BSD tar - * extension for numeric fields if their value doesn't fit in the - * maximum size of standard tar archives - * @since 1.4 - * @throws IOException on error - */ - public void writeEntryHeader(final byte[] outbuf, final ZipEncoding encoding, - final boolean starMode) throws IOException { - int offset = 0; - - offset = TarUtils.formatNameBytes(name, outbuf, offset, NAMELEN, - encoding); - offset = writeEntryHeaderField(mode, outbuf, offset, MODELEN, starMode); - offset = writeEntryHeaderField(userId, outbuf, offset, UIDLEN, - starMode); - offset = writeEntryHeaderField(groupId, outbuf, offset, GIDLEN, - starMode); - offset = writeEntryHeaderField(size, outbuf, offset, SIZELEN, starMode); - offset = writeEntryHeaderField(modTime, outbuf, offset, MODTIMELEN, - starMode); - - final int csOffset = offset; - - for (int c = 0; c < CHKSUMLEN; ++c) { - outbuf[offset++] = (byte) ' '; - } - - outbuf[offset++] = linkFlag; - offset = TarUtils.formatNameBytes(linkName, outbuf, offset, NAMELEN, - encoding); - offset = TarUtils.formatNameBytes(magic, outbuf, offset, MAGICLEN); - offset = TarUtils.formatNameBytes(version, outbuf, offset, VERSIONLEN); - offset = TarUtils.formatNameBytes(userName, outbuf, offset, UNAMELEN, - encoding); - offset = TarUtils.formatNameBytes(groupName, outbuf, offset, GNAMELEN, - encoding); - offset = writeEntryHeaderField(devMajor, outbuf, offset, DEVLEN, - starMode); - offset = writeEntryHeaderField(devMinor, outbuf, offset, DEVLEN, - starMode); - - while (offset < outbuf.length) { - outbuf[offset++] = 0; - } - - final long chk = TarUtils.computeCheckSum(outbuf); - - TarUtils.formatCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN); - } - - private int writeEntryHeaderField(final long value, final byte[] outbuf, final int offset, - final int length, final boolean starMode) { - if (!starMode && (value < 0 - || value >= 1L << 3 * (length - 1))) { - // value doesn't fit into field when written as octal - // number, will be written to PAX header or causes an - // error - return TarUtils.formatLongOctalBytes(0, outbuf, offset, length); - } - return TarUtils.formatLongOctalOrBinaryBytes(value, outbuf, offset, - length); - } - - /** - * Parse an entry's header information from a header buffer. - * - * @param header The tar entry header buffer to get information from. - * @throws IllegalArgumentException if any of the numeric fields have an invalid format - */ - public void parseTarHeader(final byte[] header) { - try { - parseTarHeader(header, TarUtils.DEFAULT_ENCODING); - } catch (final IOException ex) { - try { - parseTarHeader(header, TarUtils.DEFAULT_ENCODING, true); - } catch (final IOException ex2) { - // not really possible - throw new RuntimeException(ex2); //NOSONAR - } - } - } - - /** - * Parse an entry's header information from a header buffer. - * - * @param header The tar entry header buffer to get information from. - * @param encoding encoding to use for file names - * @since 1.4 - * @throws IllegalArgumentException if any of the numeric fields - * have an invalid format - * @throws IOException on error - */ - public void parseTarHeader(final byte[] header, final ZipEncoding encoding) - throws IOException { - parseTarHeader(header, encoding, false); - } - - private void parseTarHeader(final byte[] header, final ZipEncoding encoding, - final boolean oldStyle) - throws IOException { - int offset = 0; - - name = oldStyle ? TarUtils.parseName(header, offset, NAMELEN) - : TarUtils.parseName(header, offset, NAMELEN, encoding); - offset += NAMELEN; - mode = (int) TarUtils.parseOctalOrBinary(header, offset, MODELEN); - offset += MODELEN; - userId = (int) TarUtils.parseOctalOrBinary(header, offset, UIDLEN); - offset += UIDLEN; - groupId = (int) TarUtils.parseOctalOrBinary(header, offset, GIDLEN); - offset += GIDLEN; - size = TarUtils.parseOctalOrBinary(header, offset, SIZELEN); - offset += SIZELEN; - modTime = TarUtils.parseOctalOrBinary(header, offset, MODTIMELEN); - offset += MODTIMELEN; - checkSumOK = TarUtils.verifyCheckSum(header); - offset += CHKSUMLEN; - linkFlag = header[offset++]; - linkName = oldStyle ? TarUtils.parseName(header, offset, NAMELEN) - : TarUtils.parseName(header, offset, NAMELEN, encoding); - offset += NAMELEN; - magic = TarUtils.parseName(header, offset, MAGICLEN); - offset += MAGICLEN; - version = TarUtils.parseName(header, offset, VERSIONLEN); - offset += VERSIONLEN; - userName = oldStyle ? TarUtils.parseName(header, offset, UNAMELEN) - : TarUtils.parseName(header, offset, UNAMELEN, encoding); - offset += UNAMELEN; - groupName = oldStyle ? TarUtils.parseName(header, offset, GNAMELEN) - : TarUtils.parseName(header, offset, GNAMELEN, encoding); - offset += GNAMELEN; - if (linkFlag == LF_CHR || linkFlag == LF_BLK) { - devMajor = (int) TarUtils.parseOctalOrBinary(header, offset, DEVLEN); - offset += DEVLEN; - devMinor = (int) TarUtils.parseOctalOrBinary(header, offset, DEVLEN); - offset += DEVLEN; - } else { - offset += 2 * DEVLEN; - } - - final int type = evaluateType(header); - switch (type) { - case FORMAT_OLDGNU: { - offset += ATIMELEN_GNU; - offset += CTIMELEN_GNU; - offset += OFFSETLEN_GNU; - offset += LONGNAMESLEN_GNU; - offset += PAD2LEN_GNU; - offset += SPARSELEN_GNU; - isExtended = TarUtils.parseBoolean(header, offset); - offset += ISEXTENDEDLEN_GNU; - realSize = TarUtils.parseOctal(header, offset, REALSIZELEN_GNU); - offset += REALSIZELEN_GNU; // NOSONAR - assignment as documentation - break; - } - case FORMAT_XSTAR: { - final String xstarPrefix = oldStyle - ? TarUtils.parseName(header, offset, PREFIXLEN_XSTAR) - : TarUtils.parseName(header, offset, PREFIXLEN_XSTAR, encoding); - if (xstarPrefix.length() > 0) { - name = xstarPrefix + "/" + name; - } - break; - } - case FORMAT_POSIX: - default: { - final String prefix = oldStyle - ? TarUtils.parseName(header, offset, PREFIXLEN) - : TarUtils.parseName(header, offset, PREFIXLEN, encoding); - // SunOS tar -E does not add / to directory names, so fix - // up to be consistent - if (isDirectory() && !name.endsWith("/")){ - name = name + "/"; - } - if (prefix.length() > 0){ - name = prefix + "/" + name; - } - } - } - } - - /** - * Strips Windows' drive letter as well as any leading slashes, - * turns path separators into forward slahes. - */ - private static String normalizeFileName(String fileName, - final boolean preserveAbsolutePath) { - if (!preserveAbsolutePath) { - final String osname = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); - - if (osname != null) { - - // Strip off drive letters! - // REVIEW Would a better check be "(File.separator == '\')"? - - if (osname.startsWith("windows")) { - if (fileName.length() > 2) { - final char ch1 = fileName.charAt(0); - final char ch2 = fileName.charAt(1); - - if (ch2 == ':' - && (ch1 >= 'a' && ch1 <= 'z' - || ch1 >= 'A' && ch1 <= 'Z')) { - fileName = fileName.substring(2); - } - } - } else if (osname.contains("netware")) { - final int colon = fileName.indexOf(':'); - if (colon != -1) { - fileName = fileName.substring(colon + 1); - } - } - } - } - - fileName = fileName.replace(File.separatorChar, '/'); - - // No absolute pathnames - // Windows (and Posix?) paths can start with "\\NetworkDrive\", - // so we loop on starting /'s. - while (!preserveAbsolutePath && fileName.startsWith("/")) { - fileName = fileName.substring(1); - } - return fileName; - } - - /** - * Evaluate an entry's header format from a header buffer. - * - * @param header The tar entry header buffer to evaluate the format for. - * @return format type - */ - private int evaluateType(final byte[] header) { - if (ArchiveUtils.matchAsciiBuffer(MAGIC_GNU, header, MAGIC_OFFSET, MAGICLEN)) { - return FORMAT_OLDGNU; - } - if (ArchiveUtils.matchAsciiBuffer(MAGIC_POSIX, header, MAGIC_OFFSET, MAGICLEN)) { - if (ArchiveUtils.matchAsciiBuffer(MAGIC_XSTAR, header, XSTAR_MAGIC_OFFSET, - XSTAR_MAGIC_LEN)) { - return FORMAT_XSTAR; - } - return FORMAT_POSIX; - } - return 0; - } - - void fillGNUSparse0xData(final Map headers) { - paxGNUSparse = true; - realSize = Integer.parseInt(headers.get("GNU.sparse.size")); - if (headers.containsKey("GNU.sparse.name")) { - // version 0.1 - name = headers.get("GNU.sparse.name"); - } - } - - void fillGNUSparse1xData(final Map headers) { - paxGNUSparse = true; - realSize = Integer.parseInt(headers.get("GNU.sparse.realsize")); - name = headers.get("GNU.sparse.name"); - } - - void fillStarSparseData(final Map headers) { - starSparse = true; - if (headers.containsKey("SCHILY.realsize")) { - realSize = Long.parseLong(headers.get("SCHILY.realsize")); - } - } -} - diff --git a/src/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java b/src/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java deleted file mode 100644 index daaf729f264..00000000000 --- a/src/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* - * This package is based on the work done by Timothy Gerard Endres - * (time@ice.com) to whom the Ant project is very grateful for his great code. - */ - -package org.apache.commons.compress.archivers.tar; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; -import org.apache.commons.compress.utils.ArchiveUtils; -import org.apache.commons.compress.utils.CharsetNames; -import org.apache.commons.compress.utils.IOUtils; - -/** - * The TarInputStream reads a UNIX tar archive as an InputStream. - * methods are provided to position at each successive entry in - * the archive, and the read each entry as a normal input stream - * using read(). - * @NotThreadSafe - */ -public class TarArchiveInputStream extends ArchiveInputStream { - - private static final int SMALL_BUFFER_SIZE = 256; - - private final byte[] smallBuf = new byte[SMALL_BUFFER_SIZE]; - - /** The size the TAR header */ - private final int recordSize; - - /** The size of a block */ - private final int blockSize; - - /** True if file has hit EOF */ - private boolean hasHitEOF; - - /** Size of the current entry */ - private long entrySize; - - /** How far into the entry the stream is at */ - private long entryOffset; - - /** An input stream to read from */ - private final InputStream is; - - /** The meta-data about the current entry */ - private TarArchiveEntry currEntry; - - /** The encoding of the file */ - private final ZipEncoding zipEncoding; - - // the provided encoding (for unit tests) - final String encoding; - - // the global PAX header - private Map globalPaxHeaders = new HashMap<>(); - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - */ - public TarArchiveInputStream(final InputStream is) { - this(is, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE); - } - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - * @param encoding name of the encoding to use for file names - * @since 1.4 - */ - public TarArchiveInputStream(final InputStream is, final String encoding) { - this(is, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE, - encoding); - } - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - * @param blockSize the block size to use - */ - public TarArchiveInputStream(final InputStream is, final int blockSize) { - this(is, blockSize, TarConstants.DEFAULT_RCDSIZE); - } - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - * @param blockSize the block size to use - * @param encoding name of the encoding to use for file names - * @since 1.4 - */ - public TarArchiveInputStream(final InputStream is, final int blockSize, - final String encoding) { - this(is, blockSize, TarConstants.DEFAULT_RCDSIZE, encoding); - } - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - * @param blockSize the block size to use - * @param recordSize the record size to use - */ - public TarArchiveInputStream(final InputStream is, final int blockSize, final int recordSize) { - this(is, blockSize, recordSize, null); - } - - /** - * Constructor for TarInputStream. - * @param is the input stream to use - * @param blockSize the block size to use - * @param recordSize the record size to use - * @param encoding name of the encoding to use for file names - * @since 1.4 - */ - public TarArchiveInputStream(final InputStream is, final int blockSize, final int recordSize, - final String encoding) { - this.is = is; - this.hasHitEOF = false; - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - this.recordSize = recordSize; - this.blockSize = blockSize; - } - - /** - * Closes this stream. Calls the TarBuffer's close() method. - * @throws IOException on error - */ - @Override - public void close() throws IOException { - is.close(); - } - - /** - * Get the record size being used by this stream's buffer. - * - * @return The TarBuffer record size. - */ - public int getRecordSize() { - return recordSize; - } - - /** - * Get the available data that can be read from the current - * entry in the archive. This does not indicate how much data - * is left in the entire archive, only in the current entry. - * This value is determined from the entry's size header field - * and the amount of data already read from the current entry. - * Integer.MAX_VALUE is returned in case more than Integer.MAX_VALUE - * bytes are left in the current entry in the archive. - * - * @return The number of available bytes for the current entry. - * @throws IOException for signature - */ - @Override - public int available() throws IOException { - if (isDirectory()) { - return 0; - } - if (entrySize - entryOffset > Integer.MAX_VALUE) { - return Integer.MAX_VALUE; - } - return (int) (entrySize - entryOffset); - } - - - /** - * Skips over and discards n bytes of data from this input - * stream. The skip method may, for a variety of reasons, end - * up skipping over some smaller number of bytes, possibly 0. - * This may result from any of a number of conditions; reaching end of file - * or end of entry before n bytes have been skipped; are only - * two possibilities. The actual number of bytes skipped is returned. If - * n is negative, no bytes are skipped. - * - * - * @param n - * the number of bytes to be skipped. - * @return the actual number of bytes skipped. - * @throws IOException - * if some other I/O error occurs. - */ - @Override - public long skip(final long n) throws IOException { - if (n <= 0 || isDirectory()) { - return 0; - } - - final long available = entrySize - entryOffset; - final long skipped = IOUtils.skip(is, Math.min(n, available)); - count(skipped); - entryOffset += skipped; - return skipped; - } - - /** - * Since we do not support marking just yet, we return false. - * - * @return False. - */ - @Override - public boolean markSupported() { - return false; - } - - /** - * Since we do not support marking just yet, we do nothing. - * - * @param markLimit The limit to mark. - */ - @Override - public void mark(final int markLimit) { - } - - /** - * Since we do not support marking just yet, we do nothing. - */ - @Override - public synchronized void reset() { - } - - /** - * Get the next entry in this tar archive. This will skip - * over any remaining data in the current entry, if there - * is one, and place the input stream at the header of the - * next entry, and read the header and instantiate a new - * TarEntry from the header bytes and return that entry. - * If there are no more entries in the archive, null will - * be returned to indicate that the end of the archive has - * been reached. - * - * @return The next TarEntry in the archive, or null. - * @throws IOException on error - */ - public TarArchiveEntry getNextTarEntry() throws IOException { - if (isAtEOF()) { - return null; - } - - if (currEntry != null) { - /* Skip will only go to the end of the current entry */ - IOUtils.skip(this, Long.MAX_VALUE); - - /* skip to the end of the last record */ - skipRecordPadding(); - } - - final byte[] headerBuf = getRecord(); - - if (headerBuf == null) { - /* hit EOF */ - currEntry = null; - return null; - } - - try { - currEntry = new TarArchiveEntry(headerBuf, zipEncoding); - } catch (final IllegalArgumentException e) { - throw new IOException("Error detected parsing the header", e); - } - - entryOffset = 0; - entrySize = currEntry.getSize(); - - if (currEntry.isGNULongLinkEntry()) { - final byte[] longLinkData = getLongNameData(); - if (longLinkData == null) { - // Bugzilla: 40334 - // Malformed tar file - long link entry name not followed by - // entry - return null; - } - currEntry.setLinkName(zipEncoding.decode(longLinkData)); - } - - if (currEntry.isGNULongNameEntry()) { - final byte[] longNameData = getLongNameData(); - if (longNameData == null) { - // Bugzilla: 40334 - // Malformed tar file - long entry name not followed by - // entry - return null; - } - currEntry.setName(zipEncoding.decode(longNameData)); - } - - if (currEntry.isGlobalPaxHeader()){ // Process Global Pax headers - readGlobalPaxHeaders(); - } - - if (currEntry.isPaxHeader()){ // Process Pax headers - paxHeaders(); - } else if (!globalPaxHeaders.isEmpty()) { - applyPaxHeadersToCurrentEntry(globalPaxHeaders); - } - - if (currEntry.isOldGNUSparse()){ // Process sparse files - readOldGNUSparse(); - } - - // If the size of the next element in the archive has changed - // due to a new size being reported in the posix header - // information, we update entrySize here so that it contains - // the correct value. - entrySize = currEntry.getSize(); - - return currEntry; - } - - /** - * The last record block should be written at the full size, so skip any - * additional space used to fill a record after an entry - */ - private void skipRecordPadding() throws IOException { - if (!isDirectory() && this.entrySize > 0 && this.entrySize % this.recordSize != 0) { - final long numRecords = (this.entrySize / this.recordSize) + 1; - final long padding = (numRecords * this.recordSize) - this.entrySize; - final long skipped = IOUtils.skip(is, padding); - count(skipped); - } - } - - /** - * Get the next entry in this tar archive as longname data. - * - * @return The next entry in the archive as longname data, or null. - * @throws IOException on error - */ - protected byte[] getLongNameData() throws IOException { - // read in the name - final ByteArrayOutputStream longName = new ByteArrayOutputStream(); - int length = 0; - while ((length = read(smallBuf)) >= 0) { - longName.write(smallBuf, 0, length); - } - getNextEntry(); - if (currEntry == null) { - // Bugzilla: 40334 - // Malformed tar file - long entry name not followed by entry - return null; - } - byte[] longNameData = longName.toByteArray(); - // remove trailing null terminator(s) - length = longNameData.length; - while (length > 0 && longNameData[length - 1] == 0) { - --length; - } - if (length != longNameData.length) { - final byte[] l = new byte[length]; - System.arraycopy(longNameData, 0, l, 0, length); - longNameData = l; - } - return longNameData; - } - - /** - * Get the next record in this tar archive. This will skip - * over any remaining data in the current entry, if there - * is one, and place the input stream at the header of the - * next entry. - * - *

If there are no more entries in the archive, null will be - * returned to indicate that the end of the archive has been - * reached. At the same time the {@code hasHitEOF} marker will be - * set to true.

- * - * @return The next header in the archive, or null. - * @throws IOException on error - */ - private byte[] getRecord() throws IOException { - byte[] headerBuf = readRecord(); - setAtEOF(isEOFRecord(headerBuf)); - if (isAtEOF() && headerBuf != null) { - tryToConsumeSecondEOFRecord(); - consumeRemainderOfLastBlock(); - headerBuf = null; - } - return headerBuf; - } - - /** - * Determine if an archive record indicate End of Archive. End of - * archive is indicated by a record that consists entirely of null bytes. - * - * @param record The record data to check. - * @return true if the record data is an End of Archive - */ - protected boolean isEOFRecord(final byte[] record) { - return record == null || ArchiveUtils.isArrayZero(record, recordSize); - } - - /** - * Read a record from the input stream and return the data. - * - * @return The record data or null if EOF has been hit. - * @throws IOException on error - */ - protected byte[] readRecord() throws IOException { - - final byte[] record = new byte[recordSize]; - - final int readNow = IOUtils.readFully(is, record); - count(readNow); - if (readNow != recordSize) { - return null; - } - - return record; - } - - private void readGlobalPaxHeaders() throws IOException { - globalPaxHeaders = parsePaxHeaders(this); - getNextEntry(); // Get the actual file entry - } - - private void paxHeaders() throws IOException{ - final Map headers = parsePaxHeaders(this); - getNextEntry(); // Get the actual file entry - applyPaxHeadersToCurrentEntry(headers); - } - - // NOTE, using a Map here makes it impossible to ever support GNU - // sparse files using the PAX Format 0.0, see - // https://www.gnu.org/software/tar/manual/html_section/tar_92.html#SEC188 - Map parsePaxHeaders(final InputStream i) - throws IOException { - final Map headers = new HashMap<>(globalPaxHeaders); - // Format is "length keyword=value\n"; - while(true){ // get length - int ch; - int len = 0; - int read = 0; - while((ch = i.read()) != -1) { - read++; - if (ch == '\n') { // blank line in header - break; - } else if (ch == ' '){ // End of length string - // Get keyword - final ByteArrayOutputStream coll = new ByteArrayOutputStream(); - while((ch = i.read()) != -1) { - read++; - if (ch == '='){ // end of keyword - final String keyword = coll.toString(CharsetNames.UTF_8); - // Get rest of entry - final int restLen = len - read; - if (restLen == 1) { // only NL - headers.remove(keyword); - } else { - final byte[] rest = new byte[restLen]; - final int got = IOUtils.readFully(i, rest); - if (got != restLen) { - throw new IOException("Failed to read " - + "Paxheader. Expected " - + restLen - + " bytes, read " - + got); - } - // Drop trailing NL - final String value = new String(rest, 0, - restLen - 1, CharsetNames.UTF_8); - headers.put(keyword, value); - } - break; - } - coll.write((byte) ch); - } - break; // Processed single header - } - len *= 10; - len += ch - '0'; - } - if (ch == -1){ // EOF - break; - } - } - return headers; - } - - private void applyPaxHeadersToCurrentEntry(final Map headers) { - currEntry.updateEntryFromPaxHeaders(headers); - - } - - /** - * Adds the sparse chunks from the current entry to the sparse chunks, - * including any additional sparse entries following the current entry. - * - * @throws IOException on error - * - * @todo Sparse files get not yet really processed. - */ - private void readOldGNUSparse() throws IOException { - /* we do not really process sparse files yet - sparses = new ArrayList(); - sparses.addAll(currEntry.getSparses()); - */ - if (currEntry.isExtended()) { - TarArchiveSparseEntry entry; - do { - final byte[] headerBuf = getRecord(); - if (headerBuf == null) { - currEntry = null; - break; - } - entry = new TarArchiveSparseEntry(headerBuf); - /* we do not really process sparse files yet - sparses.addAll(entry.getSparses()); - */ - } while (entry.isExtended()); - } - } - - private boolean isDirectory() { - return currEntry != null && currEntry.isDirectory(); - } - - /** - * Returns the next Archive Entry in this Stream. - * - * @return the next entry, - * or {@code null} if there are no more entries - * @throws IOException if the next entry could not be read - */ - @Override - public ArchiveEntry getNextEntry() throws IOException { - return getNextTarEntry(); - } - - /** - * Tries to read the next record rewinding the stream if it is not a EOF record. - * - *

This is meant to protect against cases where a tar - * implementation has written only one EOF record when two are - * expected. Actually this won't help since a non-conforming - * implementation likely won't fill full blocks consisting of - by - * default - ten records either so we probably have already read - * beyond the archive anyway.

- */ - private void tryToConsumeSecondEOFRecord() throws IOException { - boolean shouldReset = true; - final boolean marked = is.markSupported(); - if (marked) { - is.mark(recordSize); - } - try { - shouldReset = !isEOFRecord(readRecord()); - } finally { - if (shouldReset && marked) { - pushedBackBytes(recordSize); - is.reset(); - } - } - } - - /** - * Reads bytes from the current tar archive entry. - * - * This method is aware of the boundaries of the current - * entry in the archive and will deal with them as if they - * were this stream's start and EOF. - * - * @param buf The buffer into which to place bytes read. - * @param offset The offset at which to place bytes read. - * @param numToRead The number of bytes to read. - * @return The number of bytes read, or -1 at EOF. - * @throws IOException on error - */ - @Override - public int read(final byte[] buf, final int offset, int numToRead) throws IOException { - int totalRead = 0; - - if (isAtEOF() || isDirectory() || entryOffset >= entrySize) { - return -1; - } - - if (currEntry == null) { - throw new IllegalStateException("No current tar entry"); - } - - numToRead = Math.min(numToRead, available()); - - totalRead = is.read(buf, offset, numToRead); - - if (totalRead == -1) { - if (numToRead > 0) { - throw new IOException("Truncated TAR archive"); - } - setAtEOF(true); - } else { - count(totalRead); - entryOffset += totalRead; - } - - return totalRead; - } - - /** - * Whether this class is able to read the given entry. - * - *

May return false if the current entry is a sparse file.

- */ - @Override - public boolean canReadEntryData(final ArchiveEntry ae) { - if (ae instanceof TarArchiveEntry) { - final TarArchiveEntry te = (TarArchiveEntry) ae; - return !te.isSparse(); - } - return false; - } - - /** - * Get the current TAR Archive Entry that this input stream is processing - * - * @return The current Archive Entry - */ - public TarArchiveEntry getCurrentEntry() { - return currEntry; - } - - protected final void setCurrentEntry(final TarArchiveEntry e) { - currEntry = e; - } - - protected final boolean isAtEOF() { - return hasHitEOF; - } - - protected final void setAtEOF(final boolean b) { - hasHitEOF = b; - } - - /** - * This method is invoked once the end of the archive is hit, it - * tries to consume the remaining bytes under the assumption that - * the tool creating this archive has padded the last block. - */ - private void consumeRemainderOfLastBlock() throws IOException { - final long bytesReadOfLastBlock = getBytesRead() % blockSize; - if (bytesReadOfLastBlock > 0) { - final long skipped = IOUtils.skip(is, blockSize - bytesReadOfLastBlock); - count(skipped); - } - } - - /** - * Checks if the signature matches what is expected for a tar file. - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is a tar archive stream, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < TarConstants.VERSION_OFFSET+TarConstants.VERSIONLEN) { - return false; - } - - if (ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_POSIX, - signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN) - && - ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_POSIX, - signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN) - ){ - return true; - } - if (ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_GNU, - signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN) - && - ( - ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_GNU_SPACE, - signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN) - || - ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_GNU_ZERO, - signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN) - ) - ){ - return true; - } - // COMPRESS-107 - recognise Ant tar files - return ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_ANT, - signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN) - && - ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_ANT, - signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN); - } - -} diff --git a/src/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java b/src/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java deleted file mode 100644 index 382f06fe185..00000000000 --- a/src/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.tar; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; -import org.apache.commons.compress.utils.CharsetNames; -import org.apache.commons.compress.utils.CountingOutputStream; -import org.apache.commons.compress.utils.FixedLengthBlockOutputStream; - -/** - * The TarOutputStream writes a UNIX tar archive as an OutputStream. Methods are provided to put - * entries, and then write their contents by writing to this stream using write(). - * - *

tar archives consist of a sequence of records of 512 bytes each - * that are grouped into blocks. Prior to Apache Commons Compress 1.14 - * it has been possible to configure a record size different from 512 - * bytes and arbitrary block sizes. Starting with Compress 1.15 512 is - * the only valid option for the record size and the block size must - * be a multiple of 512. Also the default block size changed from - * 10240 bytes prior to Compress 1.15 to 512 bytes with Compress - * 1.15.

- * - * @NotThreadSafe - */ -public class TarArchiveOutputStream extends ArchiveOutputStream { - - /** - * Fail if a long file name is required in the archive. - */ - public static final int LONGFILE_ERROR = 0; - - /** - * Long paths will be truncated in the archive. - */ - public static final int LONGFILE_TRUNCATE = 1; - - /** - * GNU tar extensions are used to store long file names in the archive. - */ - public static final int LONGFILE_GNU = 2; - - /** - * POSIX/PAX extensions are used to store long file names in the archive. - */ - public static final int LONGFILE_POSIX = 3; - - /** - * Fail if a big number (e.g. size > 8GiB) is required in the archive. - */ - public static final int BIGNUMBER_ERROR = 0; - - /** - * star/GNU tar/BSD tar extensions are used to store big number in the archive. - */ - public static final int BIGNUMBER_STAR = 1; - - /** - * POSIX/PAX extensions are used to store big numbers in the archive. - */ - public static final int BIGNUMBER_POSIX = 2; - private static final int RECORD_SIZE = 512; - - private long currSize; - private String currName; - private long currBytes; - private final byte[] recordBuf; - private int longFileMode = LONGFILE_ERROR; - private int bigNumberMode = BIGNUMBER_ERROR; - private int recordsWritten; - private final int recordsPerBlock; - - private boolean closed = false; - - /** - * Indicates if putArchiveEntry has been called without closeArchiveEntry - */ - private boolean haveUnclosedEntry = false; - - /** - * indicates if this archive is finished - */ - private boolean finished = false; - - private final FixedLengthBlockOutputStream out; - private final CountingOutputStream countingOut; - - private final ZipEncoding zipEncoding; - - // the provided encoding (for unit tests) - final String encoding; - - private boolean addPaxHeadersForNonAsciiNames = false; - private static final ZipEncoding ASCII = - ZipEncodingHelper.getZipEncoding("ASCII"); - - private static final int BLOCK_SIZE_UNSPECIFIED = -511; - - /** - * Constructor for TarArchiveOutputStream. - * - *

Uses a block size of 512 bytes.

- * - * @param os the output stream to use - */ - public TarArchiveOutputStream(final OutputStream os) { - this(os, BLOCK_SIZE_UNSPECIFIED); - } - - /** - * Constructor for TarArchiveOutputStream. - * - *

Uses a block size of 512 bytes.

- * - * @param os the output stream to use - * @param encoding name of the encoding to use for file names - * @since 1.4 - */ - public TarArchiveOutputStream(final OutputStream os, final String encoding) { - this(os, BLOCK_SIZE_UNSPECIFIED, encoding); - } - - /** - * Constructor for TarArchiveOutputStream. - * - * @param os the output stream to use - * @param blockSize the block size to use. Must be a multiple of 512 bytes. - */ - public TarArchiveOutputStream(final OutputStream os, final int blockSize) { - this(os, blockSize, null); - } - - - /** - * Constructor for TarArchiveOutputStream. - * - * @param os the output stream to use - * @param blockSize the block size to use - * @param recordSize the record size to use. Must be 512 bytes. - * @deprecated recordSize must always be 512 bytes. An IllegalArgumentException will be thrown - * if any other value is used - */ - @Deprecated - public TarArchiveOutputStream(final OutputStream os, final int blockSize, - final int recordSize) { - this(os, blockSize, recordSize, null); - } - - /** - * Constructor for TarArchiveOutputStream. - * - * @param os the output stream to use - * @param blockSize the block size to use . Must be a multiple of 512 bytes. - * @param recordSize the record size to use. Must be 512 bytes. - * @param encoding name of the encoding to use for file names - * @since 1.4 - * @deprecated recordSize must always be 512 bytes. An IllegalArgumentException will be thrown - * if any other value is used. - */ - @Deprecated - public TarArchiveOutputStream(final OutputStream os, final int blockSize, - final int recordSize, final String encoding) { - this(os, blockSize, encoding); - if (recordSize != RECORD_SIZE) { - throw new IllegalArgumentException( - "Tar record size must always be 512 bytes. Attempt to set size of " + recordSize); - } - - } - - /** - * Constructor for TarArchiveOutputStream. - * - * @param os the output stream to use - * @param blockSize the block size to use. Must be a multiple of 512 bytes. - * @param encoding name of the encoding to use for file names - * @since 1.4 - */ - public TarArchiveOutputStream(final OutputStream os, final int blockSize, - final String encoding) { - int realBlockSize; - if (BLOCK_SIZE_UNSPECIFIED == blockSize) { - realBlockSize = RECORD_SIZE; - } else { - realBlockSize = blockSize; - } - - if (realBlockSize <=0 || realBlockSize % RECORD_SIZE != 0) { - throw new IllegalArgumentException("Block size must be a multiple of 512 bytes. Attempt to use set size of " + blockSize); - } - out = new FixedLengthBlockOutputStream(countingOut = new CountingOutputStream(os), - RECORD_SIZE); - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - - this.recordBuf = new byte[RECORD_SIZE]; - this.recordsPerBlock = realBlockSize / RECORD_SIZE; - } - - /** - * Set the long file mode. This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1) or - * LONGFILE_GNU(2). This specifies the treatment of long file names (names >= - * TarConstants.NAMELEN). Default is LONGFILE_ERROR. - * - * @param longFileMode the mode to use - */ - public void setLongFileMode(final int longFileMode) { - this.longFileMode = longFileMode; - } - - /** - * Set the big number mode. This can be BIGNUMBER_ERROR(0), BIGNUMBER_POSIX(1) or - * BIGNUMBER_STAR(2). This specifies the treatment of big files (sizes > - * TarConstants.MAXSIZE) and other numeric values to big to fit into a traditional tar header. - * Default is BIGNUMBER_ERROR. - * - * @param bigNumberMode the mode to use - * @since 1.4 - */ - public void setBigNumberMode(final int bigNumberMode) { - this.bigNumberMode = bigNumberMode; - } - - /** - * Whether to add a PAX extension header for non-ASCII file names. - * - * @param b whether to add a PAX extension header for non-ASCII file names. - * @since 1.4 - */ - public void setAddPaxHeadersForNonAsciiNames(final boolean b) { - addPaxHeadersForNonAsciiNames = b; - } - - @Deprecated - @Override - public int getCount() { - return (int) getBytesWritten(); - } - - @Override - public long getBytesWritten() { - return countingOut.getBytesWritten(); - } - - /** - * Ends the TAR archive without closing the underlying OutputStream. - * - * An archive consists of a series of file entries terminated by an - * end-of-archive entry, which consists of two 512 blocks of zero bytes. - * POSIX.1 requires two EOF records, like some other implementations. - * - * @throws IOException on error - */ - @Override - public void finish() throws IOException { - if (finished) { - throw new IOException("This archive has already been finished"); - } - - if (haveUnclosedEntry) { - throw new IOException("This archive contains unclosed entries."); - } - writeEOFRecord(); - writeEOFRecord(); - padAsNeeded(); - out.flush(); - finished = true; - } - - /** - * Closes the underlying OutputStream. - * - * @throws IOException on error - */ - @Override - public void close() throws IOException { - if (!finished) { - finish(); - } - - if (!closed) { - out.close(); - closed = true; - } - } - - /** - * Get the record size being used by this stream's TarBuffer. - * - * @return The TarBuffer record size. - * @deprecated - */ - @Deprecated - public int getRecordSize() { - return RECORD_SIZE; - } - - /** - * Put an entry on the output stream. This writes the entry's header record and positions the - * output stream for writing the contents of the entry. Once this method is called, the stream - * is ready for calls to write() to write the entry's contents. Once the contents are written, - * closeArchiveEntry() MUST be called to ensure that all buffered data is completely - * written to the output stream. - * - * @param archiveEntry The TarEntry to be written to the archive. - * @throws IOException on error - * @throws ClassCastException if archiveEntry is not an instance of TarArchiveEntry - */ - @Override - public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException { - if (finished) { - throw new IOException("Stream has already been finished"); - } - final TarArchiveEntry entry = (TarArchiveEntry) archiveEntry; - if (entry.isGlobalPaxHeader()) { - final byte[] data = encodeExtendedPaxHeadersContents(entry.getExtraPaxHeaders()); - entry.setSize(data.length); - entry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR); - writeRecord(recordBuf); - currSize= entry.getSize(); - currBytes = 0; - this.haveUnclosedEntry = true; - write(data); - closeArchiveEntry(); - } else { - final Map paxHeaders = new HashMap<>(); - final String entryName = entry.getName(); - final boolean paxHeaderContainsPath = handleLongName(entry, entryName, paxHeaders, "path", - TarConstants.LF_GNUTYPE_LONGNAME, "file name"); - - final String linkName = entry.getLinkName(); - final boolean paxHeaderContainsLinkPath = linkName != null && linkName.length() > 0 - && handleLongName(entry, linkName, paxHeaders, "linkpath", - TarConstants.LF_GNUTYPE_LONGLINK, "link name"); - - if (bigNumberMode == BIGNUMBER_POSIX) { - addPaxHeadersForBigNumbers(paxHeaders, entry); - } else if (bigNumberMode != BIGNUMBER_STAR) { - failForBigNumbers(entry); - } - - if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsPath - && !ASCII.canEncode(entryName)) { - paxHeaders.put("path", entryName); - } - - if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsLinkPath - && (entry.isLink() || entry.isSymbolicLink()) - && !ASCII.canEncode(linkName)) { - paxHeaders.put("linkpath", linkName); - } - paxHeaders.putAll(entry.getExtraPaxHeaders()); - - if (paxHeaders.size() > 0) { - writePaxHeaders(entry, entryName, paxHeaders); - } - - entry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR); - writeRecord(recordBuf); - - currBytes = 0; - - if (entry.isDirectory()) { - currSize = 0; - } else { - currSize = entry.getSize(); - } - currName = entryName; - haveUnclosedEntry = true; - } - } - - /** - * Close an entry. This method MUST be called for all file entries that contain data. The reason - * is that we must buffer data written to the stream in order to satisfy the buffer's record - * based writes. Thus, there may be data fragments still being assembled that must be written to - * the output stream before this entry is closed and the next entry written. - * - * @throws IOException on error - */ - @Override - public void closeArchiveEntry() throws IOException { - if (finished) { - throw new IOException("Stream has already been finished"); - } - if (!haveUnclosedEntry) { - throw new IOException("No current entry to close"); - } - out.flushBlock(); - if (currBytes < currSize) { - throw new IOException("entry '" + currName + "' closed at '" - + currBytes - + "' before the '" + currSize - + "' bytes specified in the header were written"); - } - recordsWritten += (currSize / RECORD_SIZE); - if (0 != currSize % RECORD_SIZE) { - recordsWritten++; - } - haveUnclosedEntry = false; - } - - /** - * Writes bytes to the current tar archive entry. This method is aware of the current entry and - * will throw an exception if you attempt to write bytes past the length specified for the - * current entry. - * - * @param wBuf The buffer to write to the archive. - * @param wOffset The offset in the buffer from which to get bytes. - * @param numToWrite The number of bytes to write. - * @throws IOException on error - */ - @Override - public void write(final byte[] wBuf, int wOffset, int numToWrite) throws IOException { - if (!haveUnclosedEntry) { - throw new IllegalStateException("No current tar entry"); - } - if (currBytes + numToWrite > currSize) { - throw new IOException("request to write '" + numToWrite - + "' bytes exceeds size in header of '" - + currSize + "' bytes for entry '" - + currName + "'"); - } - out.write(wBuf, wOffset, numToWrite); - currBytes += numToWrite; - } - - /** - * Writes a PAX extended header with the given map as contents. - * - * @since 1.4 - */ - void writePaxHeaders(final TarArchiveEntry entry, - final String entryName, - final Map headers) throws IOException { - String name = "./PaxHeaders.X/" + stripTo7Bits(entryName); - if (name.length() >= TarConstants.NAMELEN) { - name = name.substring(0, TarConstants.NAMELEN - 1); - } - final TarArchiveEntry pex = new TarArchiveEntry(name, - TarConstants.LF_PAX_EXTENDED_HEADER_LC); - transferModTime(entry, pex); - - final byte[] data = encodeExtendedPaxHeadersContents(headers); - pex.setSize(data.length); - putArchiveEntry(pex); - write(data); - closeArchiveEntry(); - } - - private byte[] encodeExtendedPaxHeadersContents(Map headers) - throws UnsupportedEncodingException { - final StringWriter w = new StringWriter(); - for (final Map.Entry h : headers.entrySet()) { - final String key = h.getKey(); - final String value = h.getValue(); - int len = key.length() + value.length() - + 3 /* blank, equals and newline */ - + 2 /* guess 9 < actual length < 100 */; - String line = len + " " + key + "=" + value + "\n"; - int actualLength = line.getBytes(CharsetNames.UTF_8).length; - while (len != actualLength) { - // Adjust for cases where length < 10 or > 100 - // or where UTF-8 encoding isn't a single octet - // per character. - // Must be in loop as size may go from 99 to 100 in - // first pass so we'd need a second. - len = actualLength; - line = len + " " + key + "=" + value + "\n"; - actualLength = line.getBytes(CharsetNames.UTF_8).length; - } - w.write(line); - } - return w.toString().getBytes(CharsetNames.UTF_8); - } - - private String stripTo7Bits(final String name) { - final int length = name.length(); - final StringBuilder result = new StringBuilder(length); - for (int i = 0; i < length; i++) { - final char stripped = (char) (name.charAt(i) & 0x7F); - if (shouldBeReplaced(stripped)) { - result.append("_"); - } else { - result.append(stripped); - } - } - return result.toString(); - } - - /** - * @return true if the character could lead to problems when used inside a TarArchiveEntry name - * for a PAX header. - */ - private boolean shouldBeReplaced(final char c) { - return c == 0 // would be read as Trailing null - || c == '/' // when used as last character TAE will consider the PAX header a directory - || c == '\\'; // same as '/' as slashes get "normalized" on Windows - } - - /** - * Write an EOF (end of archive) record to the tar archive. An EOF record consists of a record - * of all zeros. - */ - private void writeEOFRecord() throws IOException { - Arrays.fill(recordBuf, (byte) 0); - writeRecord(recordBuf); - } - - @Override - public void flush() throws IOException { - out.flush(); - } - - @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) - throws IOException { - if (finished) { - throw new IOException("Stream has already been finished"); - } - return new TarArchiveEntry(inputFile, entryName); - } - - /** - * Write an archive record to the archive. - * - * @param record The record data to write to the archive. - * @throws IOException on error - */ - private void writeRecord(final byte[] record) throws IOException { - if (record.length != RECORD_SIZE) { - throw new IOException("record to write has length '" - + record.length - + "' which is not the record size of '" - + RECORD_SIZE + "'"); - } - - out.write(record); - recordsWritten++; - } - - private void padAsNeeded() throws IOException { - final int start = recordsWritten % recordsPerBlock; - if (start != 0) { - for (int i = start; i < recordsPerBlock; i++) { - writeEOFRecord(); - } - } - } - - private void addPaxHeadersForBigNumbers(final Map paxHeaders, - final TarArchiveEntry entry) { - addPaxHeaderForBigNumber(paxHeaders, "size", entry.getSize(), - TarConstants.MAXSIZE); - addPaxHeaderForBigNumber(paxHeaders, "gid", entry.getLongGroupId(), - TarConstants.MAXID); - addPaxHeaderForBigNumber(paxHeaders, "mtime", - entry.getModTime().getTime() / 1000, - TarConstants.MAXSIZE); - addPaxHeaderForBigNumber(paxHeaders, "uid", entry.getLongUserId(), - TarConstants.MAXID); - // star extensions by J\u00f6rg Schilling - addPaxHeaderForBigNumber(paxHeaders, "SCHILY.devmajor", - entry.getDevMajor(), TarConstants.MAXID); - addPaxHeaderForBigNumber(paxHeaders, "SCHILY.devminor", - entry.getDevMinor(), TarConstants.MAXID); - // there is no PAX header for file mode - failForBigNumber("mode", entry.getMode(), TarConstants.MAXID); - } - - private void addPaxHeaderForBigNumber(final Map paxHeaders, - final String header, final long value, - final long maxValue) { - if (value < 0 || value > maxValue) { - paxHeaders.put(header, String.valueOf(value)); - } - } - - private void failForBigNumbers(final TarArchiveEntry entry) { - failForBigNumber("entry size", entry.getSize(), TarConstants.MAXSIZE); - failForBigNumberWithPosixMessage("group id", entry.getLongGroupId(), TarConstants.MAXID); - failForBigNumber("last modification time", - entry.getModTime().getTime() / 1000, - TarConstants.MAXSIZE); - failForBigNumber("user id", entry.getLongUserId(), TarConstants.MAXID); - failForBigNumber("mode", entry.getMode(), TarConstants.MAXID); - failForBigNumber("major device number", entry.getDevMajor(), - TarConstants.MAXID); - failForBigNumber("minor device number", entry.getDevMinor(), - TarConstants.MAXID); - } - - private void failForBigNumber(final String field, final long value, final long maxValue) { - failForBigNumber(field, value, maxValue, ""); - } - - private void failForBigNumberWithPosixMessage(final String field, final long value, - final long maxValue) { - failForBigNumber(field, value, maxValue, - " Use STAR or POSIX extensions to overcome this limit"); - } - - private void failForBigNumber(final String field, final long value, final long maxValue, - final String additionalMsg) { - if (value < 0 || value > maxValue) { - throw new RuntimeException(field + " '" + value //NOSONAR - + "' is too big ( > " - + maxValue + " )." + additionalMsg); - } - } - - /** - * Handles long file or link names according to the longFileMode setting. - * - *

I.e. if the given name is too long to be written to a plain tar header then

  • it - * creates a pax header who's name is given by the paxHeaderName parameter if longFileMode is - * POSIX
  • it creates a GNU longlink entry who's type is given by the linkType parameter - * if longFileMode is GNU
  • it throws an exception if longFileMode is ERROR
  • it - * truncates the name if longFileMode is TRUNCATE

- * - * @param entry entry the name belongs to - * @param name the name to write - * @param paxHeaders current map of pax headers - * @param paxHeaderName name of the pax header to write - * @param linkType type of the GNU entry to write - * @param fieldName the name of the field - * @return whether a pax header has been written. - */ - private boolean handleLongName(final TarArchiveEntry entry, final String name, - final Map paxHeaders, - final String paxHeaderName, final byte linkType, final String fieldName) - throws IOException { - final ByteBuffer encodedName = zipEncoding.encode(name); - final int len = encodedName.limit() - encodedName.position(); - if (len >= TarConstants.NAMELEN) { - - if (longFileMode == LONGFILE_POSIX) { - paxHeaders.put(paxHeaderName, name); - return true; - } else if (longFileMode == LONGFILE_GNU) { - // create a TarEntry for the LongLink, the contents - // of which are the link's name - final TarArchiveEntry longLinkEntry = new TarArchiveEntry(TarConstants.GNU_LONGLINK, - linkType); - - longLinkEntry.setSize(len + 1L); // +1 for NUL - transferModTime(entry, longLinkEntry); - putArchiveEntry(longLinkEntry); - write(encodedName.array(), encodedName.arrayOffset(), len); - write(0); // NUL terminator - closeArchiveEntry(); - } else if (longFileMode != LONGFILE_TRUNCATE) { - throw new RuntimeException(fieldName + " '" + name //NOSONAR - + "' is too long ( > " - + TarConstants.NAMELEN + " bytes)"); - } - } - return false; - } - - private void transferModTime(final TarArchiveEntry from, final TarArchiveEntry to) { - Date fromModTime = from.getModTime(); - final long fromModTimeSeconds = fromModTime.getTime() / 1000; - if (fromModTimeSeconds < 0 || fromModTimeSeconds > TarConstants.MAXSIZE) { - fromModTime = new Date(0); - } - to.setModTime(fromModTime); - } -} diff --git a/src/org/apache/commons/compress/archivers/tar/TarArchiveSparseEntry.java b/src/org/apache/commons/compress/archivers/tar/TarArchiveSparseEntry.java deleted file mode 100644 index a49e7180c72..00000000000 --- a/src/org/apache/commons/compress/archivers/tar/TarArchiveSparseEntry.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.tar; - -import java.io.IOException; - -/** - * This class represents a sparse entry in a Tar archive. - * - *

- * The C structure for a sparse entry is: - *

- * struct posix_header {
- * struct sparse sp[21]; // TarConstants.SPARSELEN_GNU_SPARSE     - offset 0
- * char isextended;      // TarConstants.ISEXTENDEDLEN_GNU_SPARSE - offset 504
- * };
- * 
- * Whereas, "struct sparse" is: - *
- * struct sparse {
- * char offset[12];   // offset 0
- * char numbytes[12]; // offset 12
- * };
- * 
- */ - -public class TarArchiveSparseEntry implements TarConstants { - /** If an extension sparse header follows. */ - private final boolean isExtended; - - /** - * Construct an entry from an archive's header bytes. File is set - * to null. - * - * @param headerBuf The header bytes from a tar archive entry. - * @throws IOException on unknown format - */ - public TarArchiveSparseEntry(final byte[] headerBuf) throws IOException { - int offset = 0; - offset += SPARSELEN_GNU_SPARSE; - isExtended = TarUtils.parseBoolean(headerBuf, offset); - } - - public boolean isExtended() { - return isExtended; - } -} diff --git a/src/org/apache/commons/compress/archivers/tar/TarConstants.java b/src/org/apache/commons/compress/archivers/tar/TarConstants.java deleted file mode 100644 index 751840d448f..00000000000 --- a/src/org/apache/commons/compress/archivers/tar/TarConstants.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.tar; - -/** - * This interface contains all the definitions used in the package. - * - * For tar formats (FORMAT_OLDGNU, FORMAT_POSIX, etc.) see GNU tar - * tar.h type enum archive_format - */ -// CheckStyle:InterfaceIsTypeCheck OFF (bc) -public interface TarConstants { - - /** Default record size */ - int DEFAULT_RCDSIZE = 512; - - /** Default block size */ - int DEFAULT_BLKSIZE = DEFAULT_RCDSIZE * 20; - - /** - * GNU format as per before tar 1.12. - */ - int FORMAT_OLDGNU = 2; - - /** - * Pure Posix format. - */ - int FORMAT_POSIX = 3; - - /** - * xstar format used by Jörg Schilling's star. - */ - int FORMAT_XSTAR = 4; - - /** - * The length of the name field in a header buffer. - */ - int NAMELEN = 100; - - /** - * The length of the mode field in a header buffer. - */ - int MODELEN = 8; - - /** - * The length of the user id field in a header buffer. - */ - int UIDLEN = 8; - - /** - * The length of the group id field in a header buffer. - */ - int GIDLEN = 8; - - /** - * The maximum value of gid/uid in a tar archive which can - * be expressed in octal char notation (that's 7 sevens, octal). - */ - long MAXID = 07777777L; - - /** - * The length of the checksum field in a header buffer. - */ - int CHKSUMLEN = 8; - - /** - * Offset of the checksum field within header record. - * @since 1.5 - */ - int CHKSUM_OFFSET = 148; - - /** - * The length of the size field in a header buffer. - * Includes the trailing space or NUL. - */ - int SIZELEN = 12; - - /** - * The maximum size of a file in a tar archive - * which can be expressed in octal char notation (that's 11 sevens, octal). - */ - long MAXSIZE = 077777777777L; - - /** Offset of start of magic field within header record */ - int MAGIC_OFFSET = 257; - /** - * The length of the magic field in a header buffer. - */ - int MAGICLEN = 6; - - /** Offset of start of magic field within header record */ - int VERSION_OFFSET = 263; - /** - * Previously this was regarded as part of "magic" field, but it is separate. - */ - int VERSIONLEN = 2; - - /** - * The length of the modification time field in a header buffer. - */ - int MODTIMELEN = 12; - - /** - * The length of the user name field in a header buffer. - */ - int UNAMELEN = 32; - - /** - * The length of the group name field in a header buffer. - */ - int GNAMELEN = 32; - - /** - * The length of each of the device fields (major and minor) in a header buffer. - */ - int DEVLEN = 8; - - /** - * Length of the prefix field. - * - */ - int PREFIXLEN = 155; - - /** - * The length of the access time field in an old GNU header buffer. - * - */ - int ATIMELEN_GNU = 12; - - /** - * The length of the created time field in an old GNU header buffer. - * - */ - int CTIMELEN_GNU = 12; - - /** - * The length of the multivolume start offset field in an old GNU header buffer. - * - */ - int OFFSETLEN_GNU = 12; - - /** - * The length of the long names field in an old GNU header buffer. - * - */ - int LONGNAMESLEN_GNU = 4; - - /** - * The length of the padding field in an old GNU header buffer. - * - */ - int PAD2LEN_GNU = 1; - - /** - * The sum of the length of all sparse headers in an old GNU header buffer. - * - */ - int SPARSELEN_GNU = 96; - - /** - * The length of the is extension field in an old GNU header buffer. - * - */ - int ISEXTENDEDLEN_GNU = 1; - - /** - * The length of the real size field in an old GNU header buffer. - * - */ - int REALSIZELEN_GNU = 12; - - /** - * The sum of the length of all sparse headers in a sparse header buffer. - * - */ - int SPARSELEN_GNU_SPARSE = 504; - - /** - * The length of the is extension field in a sparse header buffer. - * - */ - int ISEXTENDEDLEN_GNU_SPARSE = 1; - - /** - * LF_ constants represent the "link flag" of an entry, or more commonly, - * the "entry type". This is the "old way" of indicating a normal file. - */ - byte LF_OLDNORM = 0; - - /** - * Normal file type. - */ - byte LF_NORMAL = (byte) '0'; - - /** - * Link file type. - */ - byte LF_LINK = (byte) '1'; - - /** - * Symbolic link file type. - */ - byte LF_SYMLINK = (byte) '2'; - - /** - * Character device file type. - */ - byte LF_CHR = (byte) '3'; - - /** - * Block device file type. - */ - byte LF_BLK = (byte) '4'; - - /** - * Directory file type. - */ - byte LF_DIR = (byte) '5'; - - /** - * FIFO (pipe) file type. - */ - byte LF_FIFO = (byte) '6'; - - /** - * Contiguous file type. - */ - byte LF_CONTIG = (byte) '7'; - - /** - * Identifies the *next* file on the tape as having a long linkname. - */ - byte LF_GNUTYPE_LONGLINK = (byte) 'K'; - - /** - * Identifies the *next* file on the tape as having a long name. - */ - byte LF_GNUTYPE_LONGNAME = (byte) 'L'; - - /** - * Sparse file type. - * @since 1.1.1 - */ - byte LF_GNUTYPE_SPARSE = (byte) 'S'; - - // See "http://www.opengroup.org/onlinepubs/009695399/utilities/pax.html#tag_04_100_13_02" - - /** - * Identifies the entry as a Pax extended header. - * @since 1.1 - */ - byte LF_PAX_EXTENDED_HEADER_LC = (byte) 'x'; - - /** - * Identifies the entry as a Pax extended header (SunOS tar -E). - * - * @since 1.1 - */ - byte LF_PAX_EXTENDED_HEADER_UC = (byte) 'X'; - - /** - * Identifies the entry as a Pax global extended header. - * - * @since 1.1 - */ - byte LF_PAX_GLOBAL_EXTENDED_HEADER = (byte) 'g'; - - /** - * The magic tag representing a POSIX tar archive. - */ - String MAGIC_POSIX = "ustar\0"; - String VERSION_POSIX = "00"; - - /** - * The magic tag representing a GNU tar archive. - */ - String MAGIC_GNU = "ustar "; - // Appear to be two possible GNU versions - String VERSION_GNU_SPACE = " \0"; - String VERSION_GNU_ZERO = "0\0"; - - /** - * The magic tag representing an Ant tar archive. - * - * @since 1.1 - */ - String MAGIC_ANT = "ustar\0"; - - /** - * The "version" representing an Ant tar archive. - * - * @since 1.1 - */ - // Does not appear to have a version, however Ant does write 8 bytes, - // so assume the version is 2 nulls - String VERSION_ANT = "\0\0"; - - /** - * The name of the GNU tar entry which contains a long name. - */ - String GNU_LONGLINK = "././@LongLink"; // TODO rename as LONGLINK_GNU ? - - /** - * The magix string used in the last four bytes of the header to - * identify the xstar format. - * @since 1.11 - */ - String MAGIC_XSTAR = "tar\0"; - - /** - * Offset inside the header for the xstar magic bytes. - * @since 1.11 - */ - int XSTAR_MAGIC_OFFSET = 508; - - /** - * Length of the XSTAR magic. - * @since 1.11 - */ - int XSTAR_MAGIC_LEN = 4; - - /** - * Length of the prefix field in xstar archives. - * - * @since 1.11 - */ - int PREFIXLEN_XSTAR = 131; - - /** - * The length of the access time field in a xstar header buffer. - * - * @since 1.11 - */ - int ATIMELEN_XSTAR = 12; - - /** - * The length of the created time field in a xstar header buffer. - * - * @since 1.11 - */ - int CTIMELEN_XSTAR = 12; -} diff --git a/src/org/apache/commons/compress/archivers/tar/TarUtils.java b/src/org/apache/commons/compress/archivers/tar/TarUtils.java deleted file mode 100644 index c83bcf966ed..00000000000 --- a/src/org/apache/commons/compress/archivers/tar/TarUtils.java +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.tar; - -import static org.apache.commons.compress.archivers.tar.TarConstants.CHKSUMLEN; -import static org.apache.commons.compress.archivers.tar.TarConstants.CHKSUM_OFFSET; - -import java.io.IOException; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import org.apache.commons.compress.archivers.zip.ZipEncoding; -import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; - -/** - * This class provides static utility methods to work with byte streams. - * - * @Immutable - */ -// CheckStyle:HideUtilityClassConstructorCheck OFF (bc) -public class TarUtils { - - private static final int BYTE_MASK = 255; - - static final ZipEncoding DEFAULT_ENCODING = - ZipEncodingHelper.getZipEncoding(null); - - /** - * Encapsulates the algorithms used up to Commons Compress 1.3 as - * ZipEncoding. - */ - static final ZipEncoding FALLBACK_ENCODING = new ZipEncoding() { - @Override - public boolean canEncode(final String name) { return true; } - - @Override - public ByteBuffer encode(final String name) { - final int length = name.length(); - final byte[] buf = new byte[length]; - - // copy until end of input or output is reached. - for (int i = 0; i < length; ++i) { - buf[i] = (byte) name.charAt(i); - } - return ByteBuffer.wrap(buf); - } - - @Override - public String decode(final byte[] buffer) { - final int length = buffer.length; - final StringBuilder result = new StringBuilder(length); - - for (final byte b : buffer) { - if (b == 0) { // Trailing null - break; - } - result.append((char) (b & 0xFF)); // Allow for sign-extension - } - - return result.toString(); - } - }; - - /** Private constructor to prevent instantiation of this utility class. */ - private TarUtils(){ - } - - /** - * Parse an octal string from a buffer. - * - *

Leading spaces are ignored. - * The buffer must contain a trailing space or NUL, - * and may contain an additional trailing space or NUL.

- * - *

The input buffer is allowed to contain all NULs, - * in which case the method returns 0L - * (this allows for missing fields).

- * - *

To work-around some tar implementations that insert a - * leading NUL this method returns 0 if it detects a leading NUL - * since Commons Compress 1.4.

- * - * @param buffer The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The maximum number of bytes to parse - must be at least 2 bytes. - * @return The long value of the octal string. - * @throws IllegalArgumentException if the trailing space/NUL is missing or if a invalid byte is detected. - */ - public static long parseOctal(final byte[] buffer, final int offset, final int length) { - long result = 0; - int end = offset + length; - int start = offset; - - if (length < 2){ - throw new IllegalArgumentException("Length "+length+" must be at least 2"); - } - - if (buffer[start] == 0) { - return 0L; - } - - // Skip leading spaces - while (start < end){ - if (buffer[start] == ' '){ - start++; - } else { - break; - } - } - - // Trim all trailing NULs and spaces. - // The ustar and POSIX tar specs require a trailing NUL or - // space but some implementations use the extra digit for big - // sizes/uids/gids ... - byte trailer = buffer[end - 1]; - while (start < end && (trailer == 0 || trailer == ' ')) { - end--; - trailer = buffer[end - 1]; - } - - for ( ;start < end; start++) { - final byte currentByte = buffer[start]; - // CheckStyle:MagicNumber OFF - if (currentByte < '0' || currentByte > '7'){ - throw new IllegalArgumentException( - exceptionMessage(buffer, offset, length, start, currentByte)); - } - result = (result << 3) + (currentByte - '0'); // convert from ASCII - // CheckStyle:MagicNumber ON - } - - return result; - } - - /** - * Compute the value contained in a byte buffer. If the most - * significant bit of the first byte in the buffer is set, this - * bit is ignored and the rest of the buffer is interpreted as a - * binary number. Otherwise, the buffer is interpreted as an - * octal number as per the parseOctal function above. - * - * @param buffer The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The maximum number of bytes to parse. - * @return The long value of the octal or binary string. - * @throws IllegalArgumentException if the trailing space/NUL is - * missing or an invalid byte is detected in an octal number, or - * if a binary number would exceed the size of a signed long - * 64-bit integer. - * @since 1.4 - */ - public static long parseOctalOrBinary(final byte[] buffer, final int offset, - final int length) { - - if ((buffer[offset] & 0x80) == 0) { - return parseOctal(buffer, offset, length); - } - final boolean negative = buffer[offset] == (byte) 0xff; - if (length < 9) { - return parseBinaryLong(buffer, offset, length, negative); - } - return parseBinaryBigInteger(buffer, offset, length, negative); - } - - private static long parseBinaryLong(final byte[] buffer, final int offset, - final int length, - final boolean negative) { - if (length >= 9) { - throw new IllegalArgumentException("At offset " + offset + ", " - + length + " byte binary number" - + " exceeds maximum signed long" - + " value"); - } - long val = 0; - for (int i = 1; i < length; i++) { - val = (val << 8) + (buffer[offset + i] & 0xff); - } - if (negative) { - // 2's complement - val--; - val ^= (long) Math.pow(2.0, (length - 1) * 8.0) - 1; - } - return negative ? -val : val; - } - - private static long parseBinaryBigInteger(final byte[] buffer, - final int offset, - final int length, - final boolean negative) { - final byte[] remainder = new byte[length - 1]; - System.arraycopy(buffer, offset + 1, remainder, 0, length - 1); - BigInteger val = new BigInteger(remainder); - if (negative) { - // 2's complement - val = val.add(BigInteger.valueOf(-1)).not(); - } - if (val.bitLength() > 63) { - throw new IllegalArgumentException("At offset " + offset + ", " - + length + " byte binary number" - + " exceeds maximum signed long" - + " value"); - } - return negative ? -val.longValue() : val.longValue(); - } - - /** - * Parse a boolean byte from a buffer. - * Leading spaces and NUL are ignored. - * The buffer may contain trailing spaces or NULs. - * - * @param buffer The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @return The boolean value of the bytes. - * @throws IllegalArgumentException if an invalid byte is detected. - */ - public static boolean parseBoolean(final byte[] buffer, final int offset) { - return buffer[offset] == 1; - } - - // Helper method to generate the exception message - private static String exceptionMessage(final byte[] buffer, final int offset, - final int length, final int current, final byte currentByte) { - // default charset is good enough for an exception message, - // - // the alternative was to modify parseOctal and - // parseOctalOrBinary to receive the ZipEncoding of the - // archive (deprecating the existing public methods, of - // course) and dealing with the fact that ZipEncoding#decode - // can throw an IOException which parseOctal* doesn't declare - String string = new String(buffer, offset, length); - - string=string.replaceAll("\0", "{NUL}"); // Replace NULs to allow string to be printed - return "Invalid byte "+currentByte+" at offset "+(current-offset)+" in '"+string+"' len="+length; - } - - /** - * Parse an entry name from a buffer. - * Parsing stops when a NUL is found - * or the buffer length is reached. - * - * @param buffer The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The maximum number of bytes to parse. - * @return The entry name. - */ - public static String parseName(final byte[] buffer, final int offset, final int length) { - try { - return parseName(buffer, offset, length, DEFAULT_ENCODING); - } catch (final IOException ex) { - try { - return parseName(buffer, offset, length, FALLBACK_ENCODING); - } catch (final IOException ex2) { - // impossible - throw new RuntimeException(ex2); //NOSONAR - } - } - } - - /** - * Parse an entry name from a buffer. - * Parsing stops when a NUL is found - * or the buffer length is reached. - * - * @param buffer The buffer from which to parse. - * @param offset The offset into the buffer from which to parse. - * @param length The maximum number of bytes to parse. - * @param encoding name of the encoding to use for file names - * @since 1.4 - * @return The entry name. - * @throws IOException on error - */ - public static String parseName(final byte[] buffer, final int offset, - final int length, - final ZipEncoding encoding) - throws IOException { - - int len = 0; - for (int i = offset; len < length && buffer[i] != 0; i++) { - len++; - } - if (len > 0) { - final byte[] b = new byte[len]; - System.arraycopy(buffer, offset, b, 0, len); - return encoding.decode(b); - } - return ""; - } - - /** - * Copy a name into a buffer. - * Copies characters from the name into the buffer - * starting at the specified offset. - * If the buffer is longer than the name, the buffer - * is filled with trailing NULs. - * If the name is longer than the buffer, - * the output is truncated. - * - * @param name The header name from which to copy the characters. - * @param buf The buffer where the name is to be stored. - * @param offset The starting offset into the buffer - * @param length The maximum number of header bytes to copy. - * @return The updated offset, i.e. offset + length - */ - public static int formatNameBytes(final String name, final byte[] buf, final int offset, final int length) { - try { - return formatNameBytes(name, buf, offset, length, DEFAULT_ENCODING); - } catch (final IOException ex) { - try { - return formatNameBytes(name, buf, offset, length, - FALLBACK_ENCODING); - } catch (final IOException ex2) { - // impossible - throw new RuntimeException(ex2); //NOSONAR - } - } - } - - /** - * Copy a name into a buffer. - * Copies characters from the name into the buffer - * starting at the specified offset. - * If the buffer is longer than the name, the buffer - * is filled with trailing NULs. - * If the name is longer than the buffer, - * the output is truncated. - * - * @param name The header name from which to copy the characters. - * @param buf The buffer where the name is to be stored. - * @param offset The starting offset into the buffer - * @param length The maximum number of header bytes to copy. - * @param encoding name of the encoding to use for file names - * @since 1.4 - * @return The updated offset, i.e. offset + length - * @throws IOException on error - */ - public static int formatNameBytes(final String name, final byte[] buf, final int offset, - final int length, - final ZipEncoding encoding) - throws IOException { - int len = name.length(); - ByteBuffer b = encoding.encode(name); - while (b.limit() > length && len > 0) { - b = encoding.encode(name.substring(0, --len)); - } - final int limit = b.limit() - b.position(); - System.arraycopy(b.array(), b.arrayOffset(), buf, offset, limit); - - // Pad any remaining output bytes with NUL - for (int i = limit; i < length; ++i) { - buf[offset + i] = 0; - } - - return offset + length; - } - - /** - * Fill buffer with unsigned octal number, padded with leading zeroes. - * - * @param value number to convert to octal - treated as unsigned - * @param buffer destination buffer - * @param offset starting offset in buffer - * @param length length of buffer to fill - * @throws IllegalArgumentException if the value will not fit in the buffer - */ - public static void formatUnsignedOctalString(final long value, final byte[] buffer, - final int offset, final int length) { - int remaining = length; - remaining--; - if (value == 0) { - buffer[offset + remaining--] = (byte) '0'; - } else { - long val = value; - for (; remaining >= 0 && val != 0; --remaining) { - // CheckStyle:MagicNumber OFF - buffer[offset + remaining] = (byte) ((byte) '0' + (byte) (val & 7)); - val = val >>> 3; - // CheckStyle:MagicNumber ON - } - if (val != 0){ - throw new IllegalArgumentException - (value+"="+Long.toOctalString(value)+ " will not fit in octal number buffer of length "+length); - } - } - - for (; remaining >= 0; --remaining) { // leading zeros - buffer[offset + remaining] = (byte) '0'; - } - } - - /** - * Write an octal integer into a buffer. - * - * Uses {@link #formatUnsignedOctalString} to format - * the value as an octal string with leading zeros. - * The converted number is followed by space and NUL - * - * @param value The value to write - * @param buf The buffer to receive the output - * @param offset The starting offset into the buffer - * @param length The size of the output buffer - * @return The updated offset, i.e offset+length - * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer - */ - public static int formatOctalBytes(final long value, final byte[] buf, final int offset, final int length) { - - int idx=length-2; // For space and trailing null - formatUnsignedOctalString(value, buf, offset, idx); - - buf[offset + idx++] = (byte) ' '; // Trailing space - buf[offset + idx] = 0; // Trailing null - - return offset + length; - } - - /** - * Write an octal long integer into a buffer. - * - * Uses {@link #formatUnsignedOctalString} to format - * the value as an octal string with leading zeros. - * The converted number is followed by a space. - * - * @param value The value to write as octal - * @param buf The destinationbuffer. - * @param offset The starting offset into the buffer. - * @param length The length of the buffer - * @return The updated offset - * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer - */ - public static int formatLongOctalBytes(final long value, final byte[] buf, final int offset, final int length) { - - final int idx=length-1; // For space - - formatUnsignedOctalString(value, buf, offset, idx); - buf[offset + idx] = (byte) ' '; // Trailing space - - return offset + length; - } - - /** - * Write an long integer into a buffer as an octal string if this - * will fit, or as a binary number otherwise. - * - * Uses {@link #formatUnsignedOctalString} to format - * the value as an octal string with leading zeros. - * The converted number is followed by a space. - * - * @param value The value to write into the buffer. - * @param buf The destination buffer. - * @param offset The starting offset into the buffer. - * @param length The length of the buffer. - * @return The updated offset. - * @throws IllegalArgumentException if the value (and trailer) - * will not fit in the buffer. - * @since 1.4 - */ - public static int formatLongOctalOrBinaryBytes( - final long value, final byte[] buf, final int offset, final int length) { - - // Check whether we are dealing with UID/GID or SIZE field - final long maxAsOctalChar = length == TarConstants.UIDLEN ? TarConstants.MAXID : TarConstants.MAXSIZE; - - final boolean negative = value < 0; - if (!negative && value <= maxAsOctalChar) { // OK to store as octal chars - return formatLongOctalBytes(value, buf, offset, length); - } - - if (length < 9) { - formatLongBinary(value, buf, offset, length, negative); - } else { - formatBigIntegerBinary(value, buf, offset, length, negative); - } - - buf[offset] = (byte) (negative ? 0xff : 0x80); - return offset + length; - } - - private static void formatLongBinary(final long value, final byte[] buf, - final int offset, final int length, - final boolean negative) { - final int bits = (length - 1) * 8; - final long max = 1L << bits; - long val = Math.abs(value); // Long.MIN_VALUE stays Long.MIN_VALUE - if (val < 0 || val >= max) { - throw new IllegalArgumentException("Value " + value + - " is too large for " + length + " byte field."); - } - if (negative) { - val ^= max - 1; - val++; - val |= 0xffL << bits; - } - for (int i = offset + length - 1; i >= offset; i--) { - buf[i] = (byte) val; - val >>= 8; - } - } - - private static void formatBigIntegerBinary(final long value, final byte[] buf, - final int offset, - final int length, - final boolean negative) { - final BigInteger val = BigInteger.valueOf(value); - final byte[] b = val.toByteArray(); - final int len = b.length; - if (len > length - 1) { - throw new IllegalArgumentException("Value " + value + - " is too large for " + length + " byte field."); - } - final int off = offset + length - len; - System.arraycopy(b, 0, buf, off, len); - final byte fill = (byte) (negative ? 0xff : 0); - for (int i = offset + 1; i < off; i++) { - buf[i] = fill; - } - } - - /** - * Writes an octal value into a buffer. - * - * Uses {@link #formatUnsignedOctalString} to format - * the value as an octal string with leading zeros. - * The converted number is followed by NUL and then space. - * - * @param value The value to convert - * @param buf The destination buffer - * @param offset The starting offset into the buffer. - * @param length The size of the buffer. - * @return The updated value of offset, i.e. offset+length - * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer - */ - public static int formatCheckSumOctalBytes(final long value, final byte[] buf, final int offset, final int length) { - - int idx=length-2; // for NUL and space - formatUnsignedOctalString(value, buf, offset, idx); - - buf[offset + idx++] = 0; // Trailing null - buf[offset + idx] = (byte) ' '; // Trailing space - - return offset + length; - } - - /** - * Compute the checksum of a tar entry header. - * - * @param buf The tar entry's header buffer. - * @return The computed checksum. - */ - public static long computeCheckSum(final byte[] buf) { - long sum = 0; - - for (final byte element : buf) { - sum += BYTE_MASK & element; - } - - return sum; - } - - /** - * Wikipedia says: - *
- * The checksum is calculated by taking the sum of the unsigned byte values - * of the header block with the eight checksum bytes taken to be ascii - * spaces (decimal value 32). It is stored as a six digit octal number with - * leading zeroes followed by a NUL and then a space. Various - * implementations do not adhere to this format. For better compatibility, - * ignore leading and trailing whitespace, and get the first six digits. In - * addition, some historic tar implementations treated bytes as signed. - * Implementations typically calculate the checksum both ways, and treat it - * as good if either the signed or unsigned sum matches the included - * checksum. - *
- *

- * The return value of this method should be treated as a best-effort - * heuristic rather than an absolute and final truth. The checksum - * verification logic may well evolve over time as more special cases - * are encountered. - * - * @param header tar header - * @return whether the checksum is reasonably good - * @see COMPRESS-191 - * @since 1.5 - */ - public static boolean verifyCheckSum(final byte[] header) { - final long storedSum = parseOctal(header, CHKSUM_OFFSET, CHKSUMLEN); - long unsignedSum = 0; - long signedSum = 0; - - for (int i = 0; i < header.length; i++) { - byte b = header[i]; - if (CHKSUM_OFFSET <= i && i < CHKSUM_OFFSET + CHKSUMLEN) { - b = ' '; - } - unsignedSum += 0xff & b; - signedSum += b; - } - return storedSum == unsignedSum || storedSum == signedSum; - } - -} diff --git a/src/org/apache/commons/compress/archivers/tar/package.html b/src/org/apache/commons/compress/archivers/tar/package.html deleted file mode 100644 index 141f33b610e..00000000000 --- a/src/org/apache/commons/compress/archivers/tar/package.html +++ /dev/null @@ -1,30 +0,0 @@ - - - -

Provides stream classes for reading and writing archives using - the TAR format.

- -

There are many different format dialects that call themselves - TAR. The classes of this package can read and write archives in - the traditional pre-POSIX ustar format and support GNU - specific extensions for long filenames that GNU tar itself by - now refers to as oldgnu.

- - diff --git a/src/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java b/src/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java deleted file mode 100644 index 846c9e1e94b..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -import java.io.UnsupportedEncodingException; -import java.util.zip.CRC32; -import java.util.zip.ZipException; - -import org.apache.commons.compress.utils.CharsetNames; - -/** - * A common base class for Unicode extra information extra fields. - * @NotThreadSafe - */ -public abstract class AbstractUnicodeExtraField implements ZipExtraField { - private long nameCRC32; - private byte[] unicodeName; - private byte[] data; - - protected AbstractUnicodeExtraField() { - } - - /** - * Assemble as unicode extension from the name/comment and - * encoding of the original zip entry. - * - * @param text The file name or comment. - * @param bytes The encoded of the filename or comment in the zip - * file. - * @param off The offset of the encoded filename or comment in - * bytes. - * @param len The length of the encoded filename or commentin - * bytes. - */ - protected AbstractUnicodeExtraField(final String text, final byte[] bytes, final int off, final int len) { - final CRC32 crc32 = new CRC32(); - crc32.update(bytes, off, len); - nameCRC32 = crc32.getValue(); - - try { - unicodeName = text.getBytes(CharsetNames.UTF_8); - } catch (final UnsupportedEncodingException e) { - throw new RuntimeException("FATAL: UTF-8 encoding not supported.", e); //NOSONAR - } - } - - /** - * Assemble as unicode extension from the name/comment and - * encoding of the original zip entry. - * - * @param text The file name or comment. - * @param bytes The encoded of the filename or comment in the zip - * file. - */ - protected AbstractUnicodeExtraField(final String text, final byte[] bytes) { - this(text, bytes, 0, bytes.length); - } - - private void assembleData() { - if (unicodeName == null) { - return; - } - - data = new byte[5 + unicodeName.length]; - // version 1 - data[0] = 0x01; - System.arraycopy(ZipLong.getBytes(nameCRC32), 0, data, 1, 4); - System.arraycopy(unicodeName, 0, data, 5, unicodeName.length); - } - - /** - * @return The CRC32 checksum of the filename or comment as - * encoded in the central directory of the zip file. - */ - public long getNameCRC32() { - return nameCRC32; - } - - /** - * @param nameCRC32 The CRC32 checksum of the filename as encoded - * in the central directory of the zip file to set. - */ - public void setNameCRC32(final long nameCRC32) { - this.nameCRC32 = nameCRC32; - data = null; - } - - /** - * @return The UTF-8 encoded name. - */ - public byte[] getUnicodeName() { - byte[] b = null; - if (unicodeName != null) { - b = new byte[unicodeName.length]; - System.arraycopy(unicodeName, 0, b, 0, b.length); - } - return b; - } - - /** - * @param unicodeName The UTF-8 encoded name to set. - */ - public void setUnicodeName(final byte[] unicodeName) { - if (unicodeName != null) { - this.unicodeName = new byte[unicodeName.length]; - System.arraycopy(unicodeName, 0, this.unicodeName, 0, - unicodeName.length); - } else { - this.unicodeName = null; - } - data = null; - } - - @Override - public byte[] getCentralDirectoryData() { - if (data == null) { - this.assembleData(); - } - byte[] b = null; - if (data != null) { - b = new byte[data.length]; - System.arraycopy(data, 0, b, 0, b.length); - } - return b; - } - - @Override - public ZipShort getCentralDirectoryLength() { - if (data == null) { - assembleData(); - } - return new ZipShort(data != null ? data.length : 0); - } - - @Override - public byte[] getLocalFileDataData() { - return getCentralDirectoryData(); - } - - @Override - public ZipShort getLocalFileDataLength() { - return getCentralDirectoryLength(); - } - - @Override - public void parseFromLocalFileData(final byte[] buffer, final int offset, final int length) - throws ZipException { - - if (length < 5) { - throw new ZipException("UniCode path extra data must have at least 5 bytes."); - } - - final int version = buffer[offset]; - - if (version != 0x01) { - throw new ZipException("Unsupported version [" + version - + "] for UniCode path extra data."); - } - - nameCRC32 = ZipLong.getValue(buffer, offset + 1); - unicodeName = new byte[length - 5]; - System.arraycopy(buffer, offset + 5, unicodeName, 0, length - 5); - data = null; - } - - /** - * Doesn't do anything special since this class always uses the - * same data in central directory and local file data. - */ - @Override - public void parseFromCentralDirectoryData(final byte[] buffer, final int offset, - final int length) - throws ZipException { - parseFromLocalFileData(buffer, offset, length); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/AsiExtraField.java b/src/org/apache/commons/compress/archivers/zip/AsiExtraField.java deleted file mode 100644 index e4afa95cdb4..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/AsiExtraField.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.zip.CRC32; -import java.util.zip.ZipException; - -/** - * Adds Unix file permission and UID/GID fields as well as symbolic - * link handling. - * - *

This class uses the ASi extra field in the format:

- *
- *         Value         Size            Description
- *         -----         ----            -----------
- * (Unix3) 0x756e        Short           tag for this extra block type
- *         TSize         Short           total data size for this block
- *         CRC           Long            CRC-32 of the remaining data
- *         Mode          Short           file permissions
- *         SizDev        Long            symlink'd size OR major/minor dev num
- *         UID           Short           user ID
- *         GID           Short           group ID
- *         (var.)        variable        symbolic link filename
- * 
- *

taken from appnote.iz (Info-ZIP note, 981119) found at ftp://ftp.uu.net/pub/archiving/zip/doc/

- * - *

Short is two bytes and Long is four bytes in big endian byte and - * word order, device numbers are currently not supported.

- * @NotThreadSafe - * - *

Since the documentation this class is based upon doesn't mention - * the character encoding of the file name at all, it is assumed that - * it uses the current platform's default encoding.

- */ -public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable { - - private static final ZipShort HEADER_ID = new ZipShort(0x756E); - private static final int WORD = 4; - /** - * Standard Unix stat(2) file mode. - */ - private int mode = 0; - /** - * User ID. - */ - private int uid = 0; - /** - * Group ID. - */ - private int gid = 0; - /** - * File this entry points to, if it is a symbolic link. - * - *

empty string - if entry is not a symbolic link.

- */ - private String link = ""; - /** - * Is this an entry for a directory? - */ - private boolean dirFlag = false; - - /** - * Instance used to calculate checksums. - */ - private CRC32 crc = new CRC32(); - - /** Constructor for AsiExtraField. */ - public AsiExtraField() { - } - - /** - * The Header-ID. - * @return the value for the header id for this extrafield - */ - @Override - public ZipShort getHeaderId() { - return HEADER_ID; - } - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * @return a ZipShort for the length of the data of this extra field - */ - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(WORD // CRC - + 2 // Mode - + WORD // SizDev - + 2 // UID - + 2 // GID - + getLinkedFile().getBytes().length); - // Uses default charset - see class Javadoc - } - - /** - * Delegate to local file data. - * @return the centralDirectory length - */ - @Override - public ZipShort getCentralDirectoryLength() { - return getLocalFileDataLength(); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * @return get the data - */ - @Override - public byte[] getLocalFileDataData() { - // CRC will be added later - final byte[] data = new byte[getLocalFileDataLength().getValue() - WORD]; - System.arraycopy(ZipShort.getBytes(getMode()), 0, data, 0, 2); - - final byte[] linkArray = getLinkedFile().getBytes(); // Uses default charset - see class Javadoc - // CheckStyle:MagicNumber OFF - System.arraycopy(ZipLong.getBytes(linkArray.length), - 0, data, 2, WORD); - - System.arraycopy(ZipShort.getBytes(getUserId()), - 0, data, 6, 2); - System.arraycopy(ZipShort.getBytes(getGroupId()), - 0, data, 8, 2); - - System.arraycopy(linkArray, 0, data, 10, linkArray.length); - // CheckStyle:MagicNumber ON - - crc.reset(); - crc.update(data); - final long checksum = crc.getValue(); - - final byte[] result = new byte[data.length + WORD]; - System.arraycopy(ZipLong.getBytes(checksum), 0, result, 0, WORD); - System.arraycopy(data, 0, result, WORD, data.length); - return result; - } - - /** - * Delegate to local file data. - * @return the local file data - */ - @Override - public byte[] getCentralDirectoryData() { - return getLocalFileDataData(); - } - - /** - * Set the user id. - * @param uid the user id - */ - public void setUserId(final int uid) { - this.uid = uid; - } - - /** - * Get the user id. - * @return the user id - */ - public int getUserId() { - return uid; - } - - /** - * Set the group id. - * @param gid the group id - */ - public void setGroupId(final int gid) { - this.gid = gid; - } - - /** - * Get the group id. - * @return the group id - */ - public int getGroupId() { - return gid; - } - - /** - * Indicate that this entry is a symbolic link to the given filename. - * - * @param name Name of the file this entry links to, empty String - * if it is not a symbolic link. - */ - public void setLinkedFile(final String name) { - link = name; - mode = getMode(mode); - } - - /** - * Name of linked file - * - * @return name of the file this entry links to if it is a - * symbolic link, the empty string otherwise. - */ - public String getLinkedFile() { - return link; - } - - /** - * Is this entry a symbolic link? - * @return true if this is a symbolic link - */ - public boolean isLink() { - return getLinkedFile().length() != 0; - } - - /** - * File mode of this file. - * @param mode the file mode - */ - public void setMode(final int mode) { - this.mode = getMode(mode); - } - - /** - * File mode of this file. - * @return the file mode - */ - public int getMode() { - return mode; - } - - /** - * Indicate whether this entry is a directory. - * @param dirFlag if true, this entry is a directory - */ - public void setDirectory(final boolean dirFlag) { - this.dirFlag = dirFlag; - mode = getMode(mode); - } - - /** - * Is this entry a directory? - * @return true if this entry is a directory - */ - public boolean isDirectory() { - return dirFlag && !isLink(); - } - - /** - * Populate data from this array as if it was in local file data. - * @param data an array of bytes - * @param offset the start offset - * @param length the number of bytes in the array from offset - * @throws ZipException on error - */ - @Override - public void parseFromLocalFileData(final byte[] data, final int offset, final int length) - throws ZipException { - - final long givenChecksum = ZipLong.getValue(data, offset); - final byte[] tmp = new byte[length - WORD]; - System.arraycopy(data, offset + WORD, tmp, 0, length - WORD); - crc.reset(); - crc.update(tmp); - final long realChecksum = crc.getValue(); - if (givenChecksum != realChecksum) { - throw new ZipException("bad CRC checksum " - + Long.toHexString(givenChecksum) - + " instead of " - + Long.toHexString(realChecksum)); - } - - final int newMode = ZipShort.getValue(tmp, 0); - // CheckStyle:MagicNumber OFF - final byte[] linkArray = new byte[(int) ZipLong.getValue(tmp, 2)]; - uid = ZipShort.getValue(tmp, 6); - gid = ZipShort.getValue(tmp, 8); - - if (linkArray.length == 0) { - link = ""; - } else { - System.arraycopy(tmp, 10, linkArray, 0, linkArray.length); - link = new String(linkArray); // Uses default charset - see class Javadoc - } - // CheckStyle:MagicNumber ON - setDirectory((newMode & DIR_FLAG) != 0); - setMode(newMode); - } - - /** - * Doesn't do anything special since this class always uses the - * same data in central directory and local file data. - */ - @Override - public void parseFromCentralDirectoryData(final byte[] buffer, final int offset, - final int length) - throws ZipException { - parseFromLocalFileData(buffer, offset, length); - } - - /** - * Get the file mode for given permissions with the correct file type. - * @param mode the mode - * @return the type with the mode - */ - protected int getMode(final int mode) { - int type = FILE_FLAG; - if (isLink()) { - type = LINK_FLAG; - } else if (isDirectory()) { - type = DIR_FLAG; - } - return type | (mode & PERM_MASK); - } - - @Override - public Object clone() { - try { - final AsiExtraField cloned = (AsiExtraField) super.clone(); - cloned.crc = new CRC32(); - return cloned; - } catch (final CloneNotSupportedException cnfe) { - // impossible - throw new RuntimeException(cnfe); //NOSONAR - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/BinaryTree.java b/src/org/apache/commons/compress/archivers/zip/BinaryTree.java deleted file mode 100644 index 9b3c3775625..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/BinaryTree.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers.zip; - -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -/** - * Binary tree of positive values. - * - * @author Emmanuel Bourg - * @since 1.7 - */ -class BinaryTree { - - /** Value in the array indicating an undefined node */ - private static final int UNDEFINED = -1; - - /** Value in the array indicating a non leaf node */ - private static final int NODE = -2; - - /** - * The array representing the binary tree. The root is at index 0, - * the left children are at 2*i+1 and the right children at 2*i+2. - */ - private final int[] tree; - - public BinaryTree(final int depth) { - tree = new int[(1 << (depth + 1)) - 1]; - Arrays.fill(tree, UNDEFINED); - } - - /** - * Adds a leaf to the tree. - * - * @param node the index of the node where the path is appended - * @param path the path to the leaf (bits are parsed from the right to the left) - * @param depth the number of nodes in the path - * @param value the value of the leaf (must be positive) - */ - public void addLeaf(final int node, final int path, final int depth, final int value) { - if (depth == 0) { - // end of the path reached, add the value to the current node - if (tree[node] == UNDEFINED) { - tree[node] = value; - } else { - throw new IllegalArgumentException("Tree value at index " + node + " has already been assigned (" + tree[node] + ")"); - } - } else { - // mark the current node as a non leaf node - tree[node] = NODE; - - // move down the path recursively - final int nextChild = 2 * node + 1 + (path & 1); - addLeaf(nextChild, path >>> 1, depth - 1, value); - } - } - - /** - * Reads a value from the specified bit stream. - * - * @param stream - * @return the value decoded, or -1 if the end of the stream is reached - */ - public int read(final BitStream stream) throws IOException { - int currentIndex = 0; - - while (true) { - final int bit = stream.nextBit(); - if (bit == -1) { - return -1; - } - - final int childIndex = 2 * currentIndex + 1 + bit; - final int value = tree[childIndex]; - if (value == NODE) { - // consume the next bit - currentIndex = childIndex; - } else if (value != UNDEFINED) { - return value; - } else { - throw new IOException("The child " + bit + " of node at index " + currentIndex + " is not defined"); - } - } - } - - - /** - * Decodes the packed binary tree from the specified stream. - */ - static BinaryTree decode(final InputStream in, final int totalNumberOfValues) throws IOException { - // the first byte contains the size of the structure minus one - final int size = in.read() + 1; - if (size == 0) { - throw new IOException("Cannot read the size of the encoded tree, unexpected end of stream"); - } - - final byte[] encodedTree = new byte[size]; - new DataInputStream(in).readFully(encodedTree); - - /** The maximum bit length for a value (16 or lower) */ - int maxLength = 0; - - final int[] originalBitLengths = new int[totalNumberOfValues]; - int pos = 0; - for (final byte b : encodedTree) { - // each byte encodes the number of values (upper 4 bits) for a bit length (lower 4 bits) - final int numberOfValues = ((b & 0xF0) >> 4) + 1; - final int bitLength = (b & 0x0F) + 1; - - for (int j = 0; j < numberOfValues; j++) { - originalBitLengths[pos++] = bitLength; - } - - maxLength = Math.max(maxLength, bitLength); - } - - // sort the array of bit lengths and memorize the permutation used to restore the order of the codes - final int[] permutation = new int[originalBitLengths.length]; - for (int k = 0; k < permutation.length; k++) { - permutation[k] = k; - } - - int c = 0; - final int[] sortedBitLengths = new int[originalBitLengths.length]; - for (int k = 0; k < originalBitLengths.length; k++) { - // iterate over the values - for (int l = 0; l < originalBitLengths.length; l++) { - // look for the value in the original array - if (originalBitLengths[l] == k) { - // put the value at the current position in the sorted array... - sortedBitLengths[c] = k; - - // ...and memorize the permutation - permutation[c] = l; - - c++; - } - } - } - - // decode the values of the tree - int code = 0; - int codeIncrement = 0; - int lastBitLength = 0; - - final int[] codes = new int[totalNumberOfValues]; - - for (int i = totalNumberOfValues - 1; i >= 0; i--) { - code = code + codeIncrement; - if (sortedBitLengths[i] != lastBitLength) { - lastBitLength = sortedBitLengths[i]; - codeIncrement = 1 << (16 - lastBitLength); - } - codes[permutation[i]] = code; - } - - // build the tree - final BinaryTree tree = new BinaryTree(maxLength); - - for (int k = 0; k < codes.length; k++) { - final int bitLength = originalBitLengths[k]; - if (bitLength > 0) { - tree.addLeaf(0, Integer.reverse(codes[k] << 16), bitLength, k); - } - } - - return tree; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/BitStream.java b/src/org/apache/commons/compress/archivers/zip/BitStream.java deleted file mode 100644 index fb737b7976d..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/BitStream.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers.zip; - -import java.io.IOException; -import java.io.InputStream; -import org.apache.commons.compress.utils.BitInputStream; -import java.nio.ByteOrder; - -/** - * Iterates over the bits of an InputStream. For each byte the bits - * are read from the right to the left. - * - * @since 1.7 - */ -class BitStream extends BitInputStream { - - BitStream(final InputStream in) { - super(in, ByteOrder.LITTLE_ENDIAN); - } - - /** - * Returns the next bit. - * - * @return The next bit (0 or 1) or -1 if the end of the stream has been reached - */ - int nextBit() throws IOException { - return (int) readBits(1); - } - - /** - * Returns the integer value formed by the n next bits (up to 8 bits). - * - * @param n the number of bits read (up to 8) - * @return The value formed by the n bits, or -1 if the end of the stream has been reached - */ - long nextBits(final int n) throws IOException { - return readBits(n); - } - - int nextByte() throws IOException { - return (int) readBits(8); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/CharsetAccessor.java b/src/org/apache/commons/compress/archivers/zip/CharsetAccessor.java deleted file mode 100644 index e5342bec751..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/CharsetAccessor.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers.zip; - -import java.nio.charset.Charset; - -/** - * An interface added to allow access to the character set associated with an {@link NioZipEncoding}, - * without requiring a new method to be added to {@link ZipEncoding}. - *

- * This avoids introducing a - * potentially breaking change, or making {@link NioZipEncoding} a public class. - *

- * @since 1.15 - */ -public interface CharsetAccessor { - - /** - * Provides access to the character set associated with an object. - *

- * This allows nio oriented code to use more natural character encoding/decoding methods, - * whilst allowing existing code to continue to rely on special-case error handling for UTF-8. - *

- * @return the character set associated with this object - */ - Charset getCharset(); -} diff --git a/src/org/apache/commons/compress/archivers/zip/CircularBuffer.java b/src/org/apache/commons/compress/archivers/zip/CircularBuffer.java deleted file mode 100644 index 8502e46e5ad..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/CircularBuffer.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers.zip; - -/** - * Circular byte buffer. - * - * @author Emmanuel Bourg - * @since 1.7 - */ -class CircularBuffer { - - /** Size of the buffer */ - private final int size; - - /** The buffer */ - private final byte[] buffer; - - /** Index of the next data to be read from the buffer */ - private int readIndex; - - /** Index of the next data written in the buffer */ - private int writeIndex; - - CircularBuffer(final int size) { - this.size = size; - buffer = new byte[size]; - } - - /** - * Tells if a new byte can be read from the buffer. - */ - public boolean available() { - return readIndex != writeIndex; - } - - /** - * Writes a byte to the buffer. - */ - public void put(final int value) { - buffer[writeIndex] = (byte) value; - writeIndex = (writeIndex + 1) % size; - } - - /** - * Reads a byte from the buffer. - */ - public int get() { - if (available()) { - final int value = buffer[readIndex]; - readIndex = (readIndex + 1) % size; - return value & 0xFF; - } - return -1; - } - - /** - * Copy a previous interval in the buffer to the current position. - * - * @param distance the distance from the current write position - * @param length the number of bytes to copy - */ - public void copy(final int distance, final int length) { - final int pos1 = writeIndex - distance; - final int pos2 = pos1 + length; - for (int i = pos1; i < pos2; i++) { - buffer[writeIndex] = buffer[(i + size) % size]; - writeIndex = (writeIndex + 1) % size; - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java b/src/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java deleted file mode 100644 index 70eb3083382..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ExplodingInputStream.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.InputStreamStatistics; - -import java.io.IOException; -import java.io.InputStream; - -/** - * The implode compression method was added to PKZIP 1.01 released in 1989. - * It was then dropped from PKZIP 2.0 released in 1993 in favor of the deflate - * method. - *

- * The algorithm is described in the ZIP File Format Specification. - * - * @see ZIP File Format Specification - * - * @author Emmanuel Bourg - * @since 1.7 - */ -class ExplodingInputStream extends InputStream implements InputStreamStatistics { - - /** The underlying stream containing the compressed data */ - private final InputStream in; - - /** The stream of bits read from the input stream */ - private BitStream bits; - - /** The size of the sliding dictionary (4K or 8K) */ - private final int dictionarySize; - - /** The number of Shannon-Fano trees (2 or 3) */ - private final int numberOfTrees; - - private final int minimumMatchLength; - - /** The binary tree containing the 256 encoded literals (null when only two trees are used) */ - private BinaryTree literalTree; - - /** The binary tree containing the 64 encoded lengths */ - private BinaryTree lengthTree; - - /** The binary tree containing the 64 encoded distances */ - private BinaryTree distanceTree; - - /** Output buffer holding the decompressed data */ - private final CircularBuffer buffer = new CircularBuffer(32 * 1024); - - private long uncompressedCount = 0; - - private long treeSizes = 0; - - /** - * Create a new stream decompressing the content of the specified stream - * using the explode algorithm. - * - * @param dictionarySize the size of the sliding dictionary (4096 or 8192) - * @param numberOfTrees the number of trees (2 or 3) - * @param in the compressed data stream - */ - public ExplodingInputStream(final int dictionarySize, final int numberOfTrees, final InputStream in) { - if (dictionarySize != 4096 && dictionarySize != 8192) { - throw new IllegalArgumentException("The dictionary size must be 4096 or 8192"); - } - if (numberOfTrees != 2 && numberOfTrees != 3) { - throw new IllegalArgumentException("The number of trees must be 2 or 3"); - } - this.dictionarySize = dictionarySize; - this.numberOfTrees = numberOfTrees; - this.minimumMatchLength = numberOfTrees; - this.in = in; - } - - /** - * Reads the encoded binary trees and prepares the bit stream. - * - * @throws IOException - */ - private void init() throws IOException { - if (bits == null) { - try (CountingInputStream i = new CountingInputStream(in) { - @Override - public void close() { - // we do not want to close in - } - }) { - if (numberOfTrees == 3) { - literalTree = BinaryTree.decode(i, 256); - } - - lengthTree = BinaryTree.decode(i, 64); - distanceTree = BinaryTree.decode(i, 64); - treeSizes += i.getBytesRead(); - } - - bits = new BitStream(in); - } - } - - @Override - public int read() throws IOException { - if (!buffer.available()) { - fillBuffer(); - } - - final int ret = buffer.get(); - if (ret > -1) { - uncompressedCount++; - } - return ret; - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return bits.getBytesRead() + treeSizes; - } - - /** - * @since 1.17 - */ - @Override - public long getUncompressedCount() { - return uncompressedCount; - } - - /** - * @since 1.17 - */ - @Override - public void close() throws IOException { - in.close(); - } - - /** - * Fill the sliding dictionary with more data. - * @throws IOException - */ - private void fillBuffer() throws IOException { - init(); - - final int bit = bits.nextBit(); - if (bit == 1) { - // literal value - int literal; - if (literalTree != null) { - literal = literalTree.read(bits); - } else { - literal = bits.nextByte(); - } - - if (literal == -1) { - // end of stream reached, nothing left to decode - return; - } - - buffer.put(literal); - - } else if (bit == 0) { - // back reference - final int distanceLowSize = dictionarySize == 4096 ? 6 : 7; - final int distanceLow = (int) bits.nextBits(distanceLowSize); - final int distanceHigh = distanceTree.read(bits); - if (distanceHigh == -1 && distanceLow <= 0) { - // end of stream reached, nothing left to decode - return; - } - final int distance = distanceHigh << distanceLowSize | distanceLow; - - int length = lengthTree.read(bits); - if (length == 63) { - length += bits.nextBits(8); - } - length += minimumMatchLength; - - buffer.copy(distance + 1, length); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java b/src/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java deleted file mode 100644 index eed6cb9e3a4..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.zip.ZipException; - -/** - * ZipExtraField related methods - * @NotThreadSafe because the HashMap is not synch. - */ -// CheckStyle:HideUtilityClassConstructorCheck OFF (bc) -public class ExtraFieldUtils { - - private static final int WORD = 4; - - /** - * Static registry of known extra fields. - */ - private static final Map> implementations; - - static { - implementations = new ConcurrentHashMap<>(); - register(AsiExtraField.class); - register(X5455_ExtendedTimestamp.class); - register(X7875_NewUnix.class); - register(JarMarker.class); - register(UnicodePathExtraField.class); - register(UnicodeCommentExtraField.class); - register(Zip64ExtendedInformationExtraField.class); - register(X000A_NTFS.class); - register(X0014_X509Certificates.class); - register(X0015_CertificateIdForFile.class); - register(X0016_CertificateIdForCentralDirectory.class); - register(X0017_StrongEncryptionHeader.class); - register(X0019_EncryptionRecipientCertificateList.class); - register(ResourceAlignmentExtraField.class); - } - - /** - * Register a ZipExtraField implementation. - * - *

The given class must have a no-arg constructor and implement - * the {@link ZipExtraField ZipExtraField interface}.

- * @param c the class to register - */ - public static void register(final Class c) { - try { - final ZipExtraField ze = (ZipExtraField) c.newInstance(); - implementations.put(ze.getHeaderId(), c); - } catch (final ClassCastException cc) { - throw new RuntimeException(c + " doesn\'t implement ZipExtraField"); //NOSONAR - } catch (final InstantiationException ie) { - throw new RuntimeException(c + " is not a concrete class"); //NOSONAR - } catch (final IllegalAccessException ie) { - throw new RuntimeException(c + "\'s no-arg constructor is not public"); //NOSONAR - } - } - - /** - * Create an instance of the appropriate ExtraField, falls back to - * {@link UnrecognizedExtraField UnrecognizedExtraField}. - * @param headerId the header identifier - * @return an instance of the appropriate ExtraField - * @throws InstantiationException if unable to instantiate the class - * @throws IllegalAccessException if not allowed to instantiate the class - */ - public static ZipExtraField createExtraField(final ZipShort headerId) - throws InstantiationException, IllegalAccessException { - final Class c = implementations.get(headerId); - if (c != null) { - return (ZipExtraField) c.newInstance(); - } - final UnrecognizedExtraField u = new UnrecognizedExtraField(); - u.setHeaderId(headerId); - return u; - } - - /** - * Split the array into ExtraFields and populate them with the - * given data as local file data, throwing an exception if the - * data cannot be parsed. - * @param data an array of bytes as it appears in local file data - * @return an array of ExtraFields - * @throws ZipException on error - */ - public static ZipExtraField[] parse(final byte[] data) throws ZipException { - return parse(data, true, UnparseableExtraField.THROW); - } - - /** - * Split the array into ExtraFields and populate them with the - * given data, throwing an exception if the data cannot be parsed. - * @param data an array of bytes - * @param local whether data originates from the local file data - * or the central directory - * @return an array of ExtraFields - * @throws ZipException on error - */ - public static ZipExtraField[] parse(final byte[] data, final boolean local) - throws ZipException { - return parse(data, local, UnparseableExtraField.THROW); - } - - /** - * Split the array into ExtraFields and populate them with the - * given data. - * @param data an array of bytes - * @param local whether data originates from the local file data - * or the central directory - * @param onUnparseableData what to do if the extra field data - * cannot be parsed. - * @return an array of ExtraFields - * @throws ZipException on error - * - * @since 1.1 - */ - public static ZipExtraField[] parse(final byte[] data, final boolean local, - final UnparseableExtraField onUnparseableData) - throws ZipException { - final List v = new ArrayList<>(); - int start = 0; - LOOP: - while (start <= data.length - WORD) { - final ZipShort headerId = new ZipShort(data, start); - final int length = new ZipShort(data, start + 2).getValue(); - if (start + WORD + length > data.length) { - switch(onUnparseableData.getKey()) { - case UnparseableExtraField.THROW_KEY: - throw new ZipException("bad extra field starting at " - + start + ". Block length of " - + length + " bytes exceeds remaining" - + " data of " - + (data.length - start - WORD) - + " bytes."); - case UnparseableExtraField.READ_KEY: - final UnparseableExtraFieldData field = - new UnparseableExtraFieldData(); - if (local) { - field.parseFromLocalFileData(data, start, - data.length - start); - } else { - field.parseFromCentralDirectoryData(data, start, - data.length - start); - } - v.add(field); - //$FALL-THROUGH$ - case UnparseableExtraField.SKIP_KEY: - // since we cannot parse the data we must assume - // the extra field consumes the whole rest of the - // available data - break LOOP; - default: - throw new ZipException("unknown UnparseableExtraField key: " - + onUnparseableData.getKey()); - } - } - try { - final ZipExtraField ze = createExtraField(headerId); - try { - if (local) { - ze.parseFromLocalFileData(data, start + WORD, length); - } else { - ze.parseFromCentralDirectoryData(data, start + WORD, length); - } - } catch (ArrayIndexOutOfBoundsException aiobe) { - throw (ZipException) new ZipException("Failed to parse corrupt ZIP extra field of type " - + Integer.toHexString(headerId.getValue())).initCause(aiobe); - } - v.add(ze); - } catch (final InstantiationException | IllegalAccessException ie) { - throw (ZipException) new ZipException(ie.getMessage()).initCause(ie); - } - start += length + WORD; - } - - final ZipExtraField[] result = new ZipExtraField[v.size()]; - return v.toArray(result); - } - - /** - * Merges the local file data fields of the given ZipExtraFields. - * @param data an array of ExtraFiles - * @return an array of bytes - */ - public static byte[] mergeLocalFileDataData(final ZipExtraField[] data) { - final boolean lastIsUnparseableHolder = data.length > 0 - && data[data.length - 1] instanceof UnparseableExtraFieldData; - final int regularExtraFieldCount = - lastIsUnparseableHolder ? data.length - 1 : data.length; - - int sum = WORD * regularExtraFieldCount; - for (final ZipExtraField element : data) { - sum += element.getLocalFileDataLength().getValue(); - } - - final byte[] result = new byte[sum]; - int start = 0; - for (int i = 0; i < regularExtraFieldCount; i++) { - System.arraycopy(data[i].getHeaderId().getBytes(), - 0, result, start, 2); - System.arraycopy(data[i].getLocalFileDataLength().getBytes(), - 0, result, start + 2, 2); - start += WORD; - final byte[] local = data[i].getLocalFileDataData(); - if (local != null) { - System.arraycopy(local, 0, result, start, local.length); - start += local.length; - } - } - if (lastIsUnparseableHolder) { - final byte[] local = data[data.length - 1].getLocalFileDataData(); - if (local != null) { - System.arraycopy(local, 0, result, start, local.length); - } - } - return result; - } - - /** - * Merges the central directory fields of the given ZipExtraFields. - * @param data an array of ExtraFields - * @return an array of bytes - */ - public static byte[] mergeCentralDirectoryData(final ZipExtraField[] data) { - final boolean lastIsUnparseableHolder = data.length > 0 - && data[data.length - 1] instanceof UnparseableExtraFieldData; - final int regularExtraFieldCount = - lastIsUnparseableHolder ? data.length - 1 : data.length; - - int sum = WORD * regularExtraFieldCount; - for (final ZipExtraField element : data) { - sum += element.getCentralDirectoryLength().getValue(); - } - final byte[] result = new byte[sum]; - int start = 0; - for (int i = 0; i < regularExtraFieldCount; i++) { - System.arraycopy(data[i].getHeaderId().getBytes(), - 0, result, start, 2); - System.arraycopy(data[i].getCentralDirectoryLength().getBytes(), - 0, result, start + 2, 2); - start += WORD; - final byte[] local = data[i].getCentralDirectoryData(); - if (local != null) { - System.arraycopy(local, 0, result, start, local.length); - start += local.length; - } - } - if (lastIsUnparseableHolder) { - final byte[] local = data[data.length - 1].getCentralDirectoryData(); - if (local != null) { - System.arraycopy(local, 0, result, start, local.length); - } - } - return result; - } - - /** - * "enum" for the possible actions to take if the extra field - * cannot be parsed. - * - * @since 1.1 - */ - public static final class UnparseableExtraField { - /** - * Key for "throw an exception" action. - */ - public static final int THROW_KEY = 0; - /** - * Key for "skip" action. - */ - public static final int SKIP_KEY = 1; - /** - * Key for "read" action. - */ - public static final int READ_KEY = 2; - - /** - * Throw an exception if field cannot be parsed. - */ - public static final UnparseableExtraField THROW - = new UnparseableExtraField(THROW_KEY); - - /** - * Skip the extra field entirely and don't make its data - * available - effectively removing the extra field data. - */ - public static final UnparseableExtraField SKIP - = new UnparseableExtraField(SKIP_KEY); - - /** - * Read the extra field data into an instance of {@link - * UnparseableExtraFieldData UnparseableExtraFieldData}. - */ - public static final UnparseableExtraField READ - = new UnparseableExtraField(READ_KEY); - - private final int key; - - private UnparseableExtraField(final int k) { - key = k; - } - - /** - * Key of the action to take. - * @return the key - */ - public int getKey() { return key; } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java b/src/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java deleted file mode 100644 index dd363aa9334..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/GeneralPurposeBit.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -/** - * Parser/encoder for the "general purpose bit" field in ZIP's local - * file and central directory headers. - * - * @since 1.1 - * @NotThreadSafe - */ -public final class GeneralPurposeBit implements Cloneable { - - /** - * Indicates that the file is encrypted. - */ - private static final int ENCRYPTION_FLAG = 1 << 0; - - /** - * Indicates the size of the sliding dictionary used by the compression method 6 (imploding). - *
    - *
  • 0: 4096 bytes
  • - *
  • 1: 8192 bytes
  • - *
- */ - private static final int SLIDING_DICTIONARY_SIZE_FLAG = 1 << 1; - - /** - * Indicates the number of Shannon-Fano trees used by the compression method 6 (imploding). - *
    - *
  • 0: 2 trees (lengths, distances)
  • - *
  • 1: 3 trees (literals, lengths, distances)
  • - *
- */ - private static final int NUMBER_OF_SHANNON_FANO_TREES_FLAG = 1 << 2; - - /** - * Indicates that a data descriptor stored after the file contents - * will hold CRC and size information. - */ - private static final int DATA_DESCRIPTOR_FLAG = 1 << 3; - - /** - * Indicates strong encryption. - */ - private static final int STRONG_ENCRYPTION_FLAG = 1 << 6; - - /** - * Indicates that filenames are written in UTF-8. - * - *

The only reason this is public is that {@link - * ZipArchiveOutputStream#EFS_FLAG} was public in Apache Commons - * Compress 1.0 and we needed a substitute for it.

- */ - public static final int UFT8_NAMES_FLAG = 1 << 11; - - private boolean languageEncodingFlag = false; - private boolean dataDescriptorFlag = false; - private boolean encryptionFlag = false; - private boolean strongEncryptionFlag = false; - private int slidingDictionarySize; - private int numberOfShannonFanoTrees; - - public GeneralPurposeBit() { - } - - /** - * whether the current entry uses UTF8 for file name and comment. - * @return whether the current entry uses UTF8 for file name and comment. - */ - public boolean usesUTF8ForNames() { - return languageEncodingFlag; - } - - /** - * whether the current entry will use UTF8 for file name and comment. - * @param b whether the current entry will use UTF8 for file name and comment. - */ - public void useUTF8ForNames(final boolean b) { - languageEncodingFlag = b; - } - - /** - * whether the current entry uses the data descriptor to store CRC - * and size information. - * @return whether the current entry uses the data descriptor to store CRC - * and size information - */ - public boolean usesDataDescriptor() { - return dataDescriptorFlag; - } - - /** - * whether the current entry will use the data descriptor to store - * CRC and size information. - * @param b whether the current entry will use the data descriptor to store - * CRC and size information - */ - public void useDataDescriptor(final boolean b) { - dataDescriptorFlag = b; - } - - /** - * whether the current entry is encrypted. - * @return whether the current entry is encrypted - */ - public boolean usesEncryption() { - return encryptionFlag; - } - - /** - * whether the current entry will be encrypted. - * @param b whether the current entry will be encrypted - */ - public void useEncryption(final boolean b) { - encryptionFlag = b; - } - - /** - * whether the current entry is encrypted using strong encryption. - * @return whether the current entry is encrypted using strong encryption - */ - public boolean usesStrongEncryption() { - return encryptionFlag && strongEncryptionFlag; - } - - /** - * whether the current entry will be encrypted using strong encryption. - * @param b whether the current entry will be encrypted using strong encryption - */ - public void useStrongEncryption(final boolean b) { - strongEncryptionFlag = b; - if (b) { - useEncryption(true); - } - } - - /** - * Returns the sliding dictionary size used by the compression method 6 (imploding). - */ - int getSlidingDictionarySize() { - return slidingDictionarySize; - } - - /** - * Returns the number of trees used by the compression method 6 (imploding). - */ - int getNumberOfShannonFanoTrees() { - return numberOfShannonFanoTrees; - } - - /** - * Encodes the set bits in a form suitable for ZIP archives. - * @return the encoded general purpose bits - */ - public byte[] encode() { - final byte[] result = new byte[2]; - encode(result, 0); - return result; - } - - - /** - * Encodes the set bits in a form suitable for ZIP archives. - * - * @param buf the output buffer - * @param offset - * The offset within the output buffer of the first byte to be written. - * must be non-negative and no larger than buf.length-2 - */ - public void encode(final byte[] buf, final int offset) { - ZipShort.putShort((dataDescriptorFlag ? DATA_DESCRIPTOR_FLAG : 0) - | - (languageEncodingFlag ? UFT8_NAMES_FLAG : 0) - | - (encryptionFlag ? ENCRYPTION_FLAG : 0) - | - (strongEncryptionFlag ? STRONG_ENCRYPTION_FLAG : 0) - , buf, offset); - } - - /** - * Parses the supported flags from the given archive data. - * - * @param data local file header or a central directory entry. - * @param offset offset at which the general purpose bit starts - * @return parsed flags - */ - public static GeneralPurposeBit parse(final byte[] data, final int offset) { - final int generalPurposeFlag = ZipShort.getValue(data, offset); - final GeneralPurposeBit b = new GeneralPurposeBit(); - b.useDataDescriptor((generalPurposeFlag & DATA_DESCRIPTOR_FLAG) != 0); - b.useUTF8ForNames((generalPurposeFlag & UFT8_NAMES_FLAG) != 0); - b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG) != 0); - b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0); - b.slidingDictionarySize = (generalPurposeFlag & SLIDING_DICTIONARY_SIZE_FLAG) != 0 ? 8192 : 4096; - b.numberOfShannonFanoTrees = (generalPurposeFlag & NUMBER_OF_SHANNON_FANO_TREES_FLAG) != 0 ? 3 : 2; - return b; - } - - @Override - public int hashCode() { - return 3 * (7 * (13 * (17 * (encryptionFlag ? 1 : 0) - + (strongEncryptionFlag ? 1 : 0)) - + (languageEncodingFlag ? 1 : 0)) - + (dataDescriptorFlag ? 1 : 0)); - } - - @Override - public boolean equals(final Object o) { - if (!(o instanceof GeneralPurposeBit)) { - return false; - } - final GeneralPurposeBit g = (GeneralPurposeBit) o; - return g.encryptionFlag == encryptionFlag - && g.strongEncryptionFlag == strongEncryptionFlag - && g.languageEncodingFlag == languageEncodingFlag - && g.dataDescriptorFlag == dataDescriptorFlag; - } - - @Override - public Object clone() { - try { - return super.clone(); - } catch (final CloneNotSupportedException ex) { - // impossible - throw new RuntimeException("GeneralPurposeBit is not Cloneable?", ex); //NOSONAR - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/InflaterInputStream.java b/src/org/apache/commons/compress/archivers/zip/InflaterInputStream.java deleted file mode 100644 index 32d20e3ef7f..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/InflaterInputStream.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.utils.InputStreamStatistics; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.Inflater; - -/** - * Helper class to provide statistics - * - * @since 1.17 - */ -/* package */ class InflaterInputStream extends java.util.zip.InflaterInputStream - implements InputStreamStatistics { - private long compressedCount = 0; - private long uncompressedCount = 0; - - public InflaterInputStream(InputStream in) { - super(in); - } - - public InflaterInputStream(InputStream in, Inflater inf) { - super(in, inf); - } - - public InflaterInputStream(InputStream in, Inflater inf, int size) { - super(in, inf, size); - } - - @Override - protected void fill() throws IOException { - super.fill(); - compressedCount += inf.getRemaining(); - } - - @Override - public int read() throws IOException { - final int b = super.read(); - if (b > -1) { - uncompressedCount++; - } - return b; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - final int bytes = super.read(b, off, len); - if (bytes > -1) { - uncompressedCount += bytes; - } - return bytes; - } - - @Override - public long getCompressedCount() { - return compressedCount; - } - - @Override - public long getUncompressedCount() { - return uncompressedCount; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/InflaterInputStreamWithStatistics.java b/src/org/apache/commons/compress/archivers/zip/InflaterInputStreamWithStatistics.java deleted file mode 100644 index b10590fa6f4..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/InflaterInputStreamWithStatistics.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.utils.InputStreamStatistics; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -/** - * Helper class to provide statistics - * - * @since 1.17 - */ -/* package */ class InflaterInputStreamWithStatistics extends InflaterInputStream - implements InputStreamStatistics { - private long compressedCount = 0; - private long uncompressedCount = 0; - - public InflaterInputStreamWithStatistics(InputStream in) { - super(in); - } - - public InflaterInputStreamWithStatistics(InputStream in, Inflater inf) { - super(in, inf); - } - - public InflaterInputStreamWithStatistics(InputStream in, Inflater inf, int size) { - super(in, inf, size); - } - - @Override - protected void fill() throws IOException { - super.fill(); - compressedCount += inf.getRemaining(); - } - - @Override - public int read() throws IOException { - final int b = super.read(); - if (b > -1) { - uncompressedCount++; - } - return b; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - final int bytes = super.read(b, off, len); - if (bytes > -1) { - uncompressedCount += bytes; - } - return bytes; - } - - @Override - public long getCompressedCount() { - return compressedCount; - } - - @Override - public long getUncompressedCount() { - return uncompressedCount; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/JarMarker.java b/src/org/apache/commons/compress/archivers/zip/JarMarker.java deleted file mode 100644 index ad12f37e248..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/JarMarker.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.zip.ZipException; - -/** - * If this extra field is added as the very first extra field of the - * archive, Solaris will consider it an executable jar file. - * @Immutable - */ -public final class JarMarker implements ZipExtraField { - - private static final ZipShort ID = new ZipShort(0xCAFE); - private static final ZipShort NULL = new ZipShort(0); - private static final byte[] NO_BYTES = new byte[0]; - private static final JarMarker DEFAULT = new JarMarker(); - - /** No-arg constructor */ - public JarMarker() { - // empty - } - - /** - * Since JarMarker is stateless we can always use the same instance. - * @return the DEFAULT jarmaker. - */ - public static JarMarker getInstance() { - return DEFAULT; - } - - /** - * The Header-ID. - * @return the header id - */ - @Override - public ZipShort getHeaderId() { - return ID; - } - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * @return 0 - */ - @Override - public ZipShort getLocalFileDataLength() { - return NULL; - } - - /** - * Length of the extra field in the central directory - without - * Header-ID or length specifier. - * @return 0 - */ - @Override - public ZipShort getCentralDirectoryLength() { - return NULL; - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * @return the data - */ - @Override - public byte[] getLocalFileDataData() { - return NO_BYTES; - } - - /** - * The actual data to put central directory - without Header-ID or - * length specifier. - * @return the data - */ - @Override - public byte[] getCentralDirectoryData() { - return NO_BYTES; - } - - /** - * Populate data from this array as if it was in local file data. - * @param data an array of bytes - * @param offset the start offset - * @param length the number of bytes in the array from offset - * - * @throws ZipException on error - */ - @Override - public void parseFromLocalFileData(final byte[] data, final int offset, final int length) - throws ZipException { - if (length != 0) { - throw new ZipException("JarMarker doesn't expect any data"); - } - } - - /** - * Doesn't do anything special since this class always uses the - * same data in central directory and local file data. - */ - @Override - public void parseFromCentralDirectoryData(final byte[] buffer, final int offset, - final int length) - throws ZipException { - parseFromLocalFileData(buffer, offset, length); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/NioZipEncoding.java b/src/org/apache/commons/compress/archivers/zip/NioZipEncoding.java deleted file mode 100644 index 0a7581acf0c..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/NioZipEncoding.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers.zip; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; - -/** - * A ZipEncoding, which uses a java.nio {@link - * java.nio.charset.Charset Charset} to encode names. - *

The methods of this class are reentrant.

- * @Immutable - */ -class NioZipEncoding implements ZipEncoding, CharsetAccessor { - - private final Charset charset; - private final boolean useReplacement; - private static final char REPLACEMENT = '?'; - private static final byte[] REPLACEMENT_BYTES = { (byte) REPLACEMENT }; - private static final String REPLACEMENT_STRING = String.valueOf(REPLACEMENT); - private static final char[] HEX_CHARS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - - - /** - * Construct an NioZipEncoding using the given charset. - * @param charset The character set to use. - * @param useReplacement should invalid characters be replaced, or reported. - */ - NioZipEncoding(final Charset charset, boolean useReplacement) { - this.charset = charset; - this.useReplacement = useReplacement; - } - - @Override - public Charset getCharset() { - return charset; - } - - /** - * @see ZipEncoding#canEncode(java.lang.String) - */ - @Override - public boolean canEncode(final String name) { - final CharsetEncoder enc = newEncoder(); - - return enc.canEncode(name); - } - - /** - * @see ZipEncoding#encode(java.lang.String) - */ - @Override - public ByteBuffer encode(final String name) { - final CharsetEncoder enc = newEncoder(); - - final CharBuffer cb = CharBuffer.wrap(name); - CharBuffer tmp = null; - ByteBuffer out = ByteBuffer.allocate(estimateInitialBufferSize(enc, cb.remaining())); - - while (cb.remaining() > 0) { - final CoderResult res = enc.encode(cb, out, false); - - if (res.isUnmappable() || res.isMalformed()) { - - // write the unmappable characters in utf-16 - // pseudo-URL encoding style to ByteBuffer. - - int spaceForSurrogate = estimateIncrementalEncodingSize(enc, 6 * res.length()); - if (spaceForSurrogate > out.remaining()) { - // if the destination buffer isn't over sized, assume that the presence of one - // unmappable character makes it likely that there will be more. Find all the - // un-encoded characters and allocate space based on those estimates. - int charCount = 0; - for (int i = cb.position() ; i < cb.limit(); i++) { - charCount += !enc.canEncode(cb.get(i)) ? 6 : 1; - } - int totalExtraSpace = estimateIncrementalEncodingSize(enc, charCount); - out = ZipEncodingHelper.growBufferBy(out, totalExtraSpace - out.remaining()); - } - if (tmp == null) { - tmp = CharBuffer.allocate(6); - } - for (int i = 0; i < res.length(); ++i) { - out = encodeFully(enc, encodeSurrogate(tmp, cb.get()), out); - } - - } else if (res.isOverflow()) { - int increment = estimateIncrementalEncodingSize(enc, cb.remaining()); - out = ZipEncodingHelper.growBufferBy(out, increment); - } - } - // tell the encoder we are done - enc.encode(cb, out, true); - // may have caused underflow, but that's been ignored traditionally - - out.limit(out.position()); - out.rewind(); - return out; - } - - /** - * @see - * ZipEncoding#decode(byte[]) - */ - @Override - public String decode(final byte[] data) throws IOException { - return newDecoder() - .decode(ByteBuffer.wrap(data)).toString(); - } - - private static ByteBuffer encodeFully(CharsetEncoder enc, CharBuffer cb, ByteBuffer out) { - ByteBuffer o = out; - while (cb.hasRemaining()) { - CoderResult result = enc.encode(cb, o, false); - if (result.isOverflow()) { - int increment = estimateIncrementalEncodingSize(enc, cb.remaining()); - o = ZipEncodingHelper.growBufferBy(o, increment); - } - } - return o; - } - - private static CharBuffer encodeSurrogate(CharBuffer cb, char c) { - cb.position(0).limit(6); - cb.put('%'); - cb.put('U'); - - cb.put(HEX_CHARS[(c >> 12) & 0x0f]); - cb.put(HEX_CHARS[(c >> 8) & 0x0f]); - cb.put(HEX_CHARS[(c >> 4) & 0x0f]); - cb.put(HEX_CHARS[c & 0x0f]); - cb.flip(); - return cb; - } - - private CharsetEncoder newEncoder() { - if (useReplacement) { - return charset.newEncoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .replaceWith(REPLACEMENT_BYTES); - } else { - return charset.newEncoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - } - } - - private CharsetDecoder newDecoder() { - if (!useReplacement) { - return this.charset.newDecoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - } else { - return charset.newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .replaceWith(REPLACEMENT_STRING); - } - } - - /** - * Estimate the initial encoded size (in bytes) for a character buffer. - *

- * The estimate assumes that one character consumes uses the maximum length encoding, - * whilst the rest use an average size encoding. This accounts for any BOM for UTF-16, at - * the expense of a couple of extra bytes for UTF-8 encoded ASCII. - *

- * - * @param enc encoder to use for estimates - * @param charChount number of characters in string - * @return estimated size in bytes. - */ - private static int estimateInitialBufferSize(CharsetEncoder enc, int charChount) { - float first = enc.maxBytesPerChar(); - float rest = (charChount - 1) * enc.averageBytesPerChar(); - return (int) Math.ceil(first + rest); - } - - /** - * Estimate the size needed for remaining characters - * - * @param enc encoder to use for estimates - * @param charCount number of characters remaining - * @return estimated size in bytes. - */ - private static int estimateIncrementalEncodingSize(CharsetEncoder enc, int charCount) { - return (int) Math.ceil(charCount * enc.averageBytesPerChar()); - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/PKWareExtraHeader.java b/src/org/apache/commons/compress/archivers/zip/PKWareExtraHeader.java deleted file mode 100644 index 7177c8759b1..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/PKWareExtraHeader.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * Base class for all PKWare strong crypto extra headers. - * - *

This base class acts as a marker so you know you can ignore all - * extra fields that extend this class if you are not interested in - * the meta data of PKWare strong encryption.

- * - * Algorithm IDs - integer identifier of the encryption algorithm from - * the following range - * - *
    - *
  • 0x6601 - DES
  • - *
  • 0x6602 - RC2 (version needed to extract < 5.2)
  • - *
  • 0x6603 - 3DES 168
  • - *
  • 0x6609 - 3DES 112
  • - *
  • 0x660E - AES 128
  • - *
  • 0x660F - AES 192
  • - *
  • 0x6610 - AES 256
  • - *
  • 0x6702 - RC2 (version needed to extract >= 5.2)
  • - *
  • 0x6720 - Blowfish
  • - *
  • 0x6721 - Twofish
  • - *
  • 0x6801 - RC4
  • - *
  • 0xFFFF - Unknown algorithm
  • - *
- * - * Hash Algorithms - integer identifier of the hash algorithm from the - * following range - * - *
    - *
  • 0x0000 - none
  • - *
  • 0x0001 - CRC32
  • - *
  • 0x8003 - MD5
  • - *
  • 0x8004 - SHA1
  • - *
  • 0x8007 - RIPEMD160
  • - *
  • 0x800C - SHA256
  • - *
  • 0x800D - SHA384
  • - *
  • 0x800E - SHA512
  • - *
- * - * @since 1.11 - */ -public abstract class PKWareExtraHeader implements ZipExtraField { - - private final ZipShort headerId; - /** - * Extra field data in local file data - without Header-ID or length - * specifier. - */ - private byte[] localData; - /** - * Extra field data in central directory - without Header-ID or length - * specifier. - */ - private byte[] centralData; - - protected PKWareExtraHeader(final ZipShort headerId) { - this.headerId = headerId; - } - - /** - * Get the header id. - * - * @return the header id - */ - @Override - public ZipShort getHeaderId() { - return headerId; - } - - /** - * Set the extra field data in the local file data - without Header-ID or - * length specifier. - * - * @param data - * the field data to use - */ - public void setLocalFileDataData(final byte[] data) { - localData = ZipUtil.copy(data); - } - - /** - * Get the length of the local data. - * - * @return the length of the local data - */ - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(localData != null ? localData.length : 0); - } - - /** - * Get the local data. - * - * @return the local data - */ - @Override - public byte[] getLocalFileDataData() { - return ZipUtil.copy(localData); - } - - /** - * Set the extra field data in central directory. - * - * @param data - * the data to use - */ - public void setCentralDirectoryData(final byte[] data) { - centralData = ZipUtil.copy(data); - } - - /** - * Get the central data length. If there is no central data, get the local - * file data length. - * - * @return the central data length - */ - @Override - public ZipShort getCentralDirectoryLength() { - if (centralData != null) { - return new ZipShort(centralData.length); - } - return getLocalFileDataLength(); - } - - /** - * Get the central data. - * - * @return the central data if present, else return the local file data - */ - @Override - public byte[] getCentralDirectoryData() { - if (centralData != null) { - return ZipUtil.copy(centralData); - } - return getLocalFileDataData(); - } - - /** - * @param data - * the array of bytes. - * @param offset - * the source location in the data array. - * @param length - * the number of bytes to use in the data array. - * @see ZipExtraField#parseFromLocalFileData(byte[], int, int) - */ - @Override - public void parseFromLocalFileData(final byte[] data, final int offset, final int length) { - final byte[] tmp = new byte[length]; - System.arraycopy(data, offset, tmp, 0, length); - setLocalFileDataData(tmp); - } - - /** - * @param data - * the array of bytes. - * @param offset - * the source location in the data array. - * @param length - * the number of bytes to use in the data array. - * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int) - */ - @Override - public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) { - final byte[] tmp = new byte[length]; - System.arraycopy(data, offset, tmp, 0, length); - setCentralDirectoryData(tmp); - if (localData == null) { - setLocalFileDataData(tmp); - } - } - - /** - * Encryption algorithm. - * - * @since 1.11 - */ - public enum EncryptionAlgorithm { - DES(0x6601), - RC2pre52(0x6602), - TripleDES168(0x6603), - TripleDES192(0x6609), - AES128(0x660E), - AES192(0x660F), - AES256(0x6610), - RC2(0x6702), - RC4(0x6801), - UNKNOWN(0xFFFF); - - private final int code; - - private static final Map codeToEnum; - - static { - final Map cte = new HashMap<>(); - for (final EncryptionAlgorithm method : values()) { - cte.put(method.getCode(), method); - } - codeToEnum = Collections.unmodifiableMap(cte); - } - - /** - * private constructor for enum style class. - */ - EncryptionAlgorithm(final int code) { - this.code = code; - } - - /** - * the algorithm id. - * - * @return the PKWare AlgorithmId - */ - public int getCode() { - return code; - } - - /** - * Returns the EncryptionAlgorithm for the given code or null if the - * method is not known. - * @param code the code of the algorithm - * @return the EncryptionAlgorithm for the given code or null - * if the method is not known - */ - public static EncryptionAlgorithm getAlgorithmByCode(final int code) { - return codeToEnum.get(code); - } - } - - /** - * Hash Algorithm - * - * @since 1.11 - */ - public enum HashAlgorithm { - NONE(0), - CRC32(1), - MD5(0x8003), - SHA1(0x8004), - RIPEND160(0x8007), - SHA256(0x800C), - SHA384(0x800D), - SHA512(0x800E); - - private final int code; - - private static final Map codeToEnum; - - static { - final Map cte = new HashMap<>(); - for (final HashAlgorithm method : values()) { - cte.put(method.getCode(), method); - } - codeToEnum = Collections.unmodifiableMap(cte); - } - - /** - * private constructor for enum style class. - */ - HashAlgorithm(final int code) { - this.code = code; - } - - /** - * the hash algorithm ID. - * - * @return the PKWare hashAlg - */ - public int getCode() { - return code; - } - - /** - * Returns the HashAlgorithm for the given code or null if the method is - * not known. - * @param code the code of the algorithm - * @return the HashAlgorithm for the given code or null - * if the method is not known - */ - public static HashAlgorithm getAlgorithmByCode(final int code) { - return codeToEnum.get(code); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator.java b/src/org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator.java deleted file mode 100644 index a381d0a285e..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.parallel.FileBasedScatterGatherBackingStore; -import org.apache.commons.compress.parallel.InputStreamSupplier; -import org.apache.commons.compress.parallel.ScatterGatherBackingStore; -import org.apache.commons.compress.parallel.ScatterGatherBackingStoreSupplier; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.Deflater; - -import static java.util.Collections.synchronizedList; -import static org.apache.commons.compress.archivers.zip.ZipArchiveEntryRequest.createZipArchiveEntryRequest; - -/** - * Creates a zip in parallel by using multiple threadlocal {@link ScatterZipOutputStream} instances. - *

- * Note that this class generally makes no guarantees about the order of things written to - * the output file. Things that need to come in a specific order (manifests, directories) - * must be handled by the client of this class, usually by writing these things to the - * {@link ZipArchiveOutputStream} before calling {@link #writeTo writeTo} on this class.

- *

- * The client can supply an {@link java.util.concurrent.ExecutorService}, but for reasons of - * memory model consistency, this will be shut down by this class prior to completion. - *

- * @since 1.10 - */ -public class ParallelScatterZipCreator { - private final List streams = synchronizedList(new ArrayList()); - private final ExecutorService es; - private final ScatterGatherBackingStoreSupplier backingStoreSupplier; - private final List> futures = new ArrayList<>(); - - private final long startedAt = System.currentTimeMillis(); - private long compressionDoneAt = 0; - private long scatterDoneAt; - - private static class DefaultBackingStoreSupplier implements ScatterGatherBackingStoreSupplier { - final AtomicInteger storeNum = new AtomicInteger(0); - - @Override - public ScatterGatherBackingStore get() throws IOException { - final File tempFile = File.createTempFile("parallelscatter", "n" + storeNum.incrementAndGet()); - return new FileBasedScatterGatherBackingStore(tempFile); - } - } - - private ScatterZipOutputStream createDeferred(final ScatterGatherBackingStoreSupplier scatterGatherBackingStoreSupplier) - throws IOException { - final ScatterGatherBackingStore bs = scatterGatherBackingStoreSupplier.get(); - // lifecycle is bound to the ScatterZipOutputStream returned - final StreamCompressor sc = StreamCompressor.create(Deflater.DEFAULT_COMPRESSION, bs); //NOSONAR - return new ScatterZipOutputStream(bs, sc); - } - - private final ThreadLocal tlScatterStreams = new ThreadLocal() { - @Override - protected ScatterZipOutputStream initialValue() { - try { - final ScatterZipOutputStream scatterStream = createDeferred(backingStoreSupplier); - streams.add(scatterStream); - return scatterStream; - } catch (final IOException e) { - throw new RuntimeException(e); //NOSONAR - } - } - }; - - /** - * Create a ParallelScatterZipCreator with default threads, which is set to the number of available - * processors, as defined by {@link java.lang.Runtime#availableProcessors} - */ - public ParallelScatterZipCreator() { - this(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())); - } - - /** - * Create a ParallelScatterZipCreator - * - * @param executorService The executorService to use for parallel scheduling. For technical reasons, - * this will be shut down by this class. - */ - public ParallelScatterZipCreator(final ExecutorService executorService) { - this(executorService, new DefaultBackingStoreSupplier()); - } - - /** - * Create a ParallelScatterZipCreator - * - * @param executorService The executorService to use. For technical reasons, this will be shut down - * by this class. - * @param backingStoreSupplier The supplier of backing store which shall be used - */ - public ParallelScatterZipCreator(final ExecutorService executorService, - final ScatterGatherBackingStoreSupplier backingStoreSupplier) { - this.backingStoreSupplier = backingStoreSupplier; - es = executorService; - } - - /** - * Adds an archive entry to this archive. - *

- * This method is expected to be called from a single client thread - *

- * - * @param zipArchiveEntry The entry to add. - * @param source The source input stream supplier - */ - - public void addArchiveEntry(final ZipArchiveEntry zipArchiveEntry, final InputStreamSupplier source) { - submit(createCallable(zipArchiveEntry, source)); - } - - /** - * Adds an archive entry to this archive. - *

- * This method is expected to be called from a single client thread - *

- * - * @param zipArchiveEntryRequestSupplier Should supply the entry to be added. - * @since 1.13 - */ - public void addArchiveEntry(final ZipArchiveEntryRequestSupplier zipArchiveEntryRequestSupplier) { - submit(createCallable(zipArchiveEntryRequestSupplier)); - } - - /** - * Submit a callable for compression. - * - * @see ParallelScatterZipCreator#createCallable for details of if/when to use this. - * - * @param callable The callable to run, created by {@link #createCallable createCallable}, possibly wrapped by caller. - */ - public final void submit(final Callable callable) { - futures.add(es.submit(callable)); - } - - /** - * Create a callable that will compress the given archive entry. - * - *

This method is expected to be called from a single client thread.

- * - * Consider using {@link #addArchiveEntry addArchiveEntry}, which wraps this method and {@link #submit submit}. - * The most common use case for using {@link #createCallable createCallable} and {@link #submit submit} from a - * client is if you want to wrap the callable in something that can be prioritized by the supplied - * {@link ExecutorService}, for instance to process large or slow files first. - * Since the creation of the {@link ExecutorService} is handled by the client, all of this is up to the client. - * - * @param zipArchiveEntry The entry to add. - * @param source The source input stream supplier - * @return A callable that should subsequently passed to #submit, possibly in a wrapped/adapted from. The - * value of this callable is not used, but any exceptions happening inside the compression - * will be propagated through the callable. - */ - - public final Callable createCallable(final ZipArchiveEntry zipArchiveEntry, final InputStreamSupplier source) { - final int method = zipArchiveEntry.getMethod(); - if (method == ZipMethod.UNKNOWN_CODE) { - throw new IllegalArgumentException("Method must be set on zipArchiveEntry: " + zipArchiveEntry); - } - final ZipArchiveEntryRequest zipArchiveEntryRequest = createZipArchiveEntryRequest(zipArchiveEntry, source); - return new Callable() { - @Override - public Object call() throws Exception { - tlScatterStreams.get().addArchiveEntry(zipArchiveEntryRequest); - return null; - } - }; - } - - /** - * Create a callable that will compress archive entry supplied by {@link ZipArchiveEntryRequestSupplier}. - * - *

This method is expected to be called from a single client thread.

- * - * The same as {@link #createCallable(ZipArchiveEntry, InputStreamSupplier)}, but the archive entry - * to be added is supplied by a {@link ZipArchiveEntryRequestSupplier}. - * - * @see #createCallable(ZipArchiveEntry, InputStreamSupplier) - * - * @param zipArchiveEntryRequestSupplier Should supply the entry to be added. - * @return A callable that should subsequently passed to #submit, possibly in a wrapped/adapted from. The - * value of this callable is not used, but any exceptions happening inside the compression - * will be propagated through the callable. - * @since 1.13 - */ - public final Callable createCallable(final ZipArchiveEntryRequestSupplier zipArchiveEntryRequestSupplier) { - return new Callable() { - @Override - public Object call() throws Exception { - tlScatterStreams.get().addArchiveEntry(zipArchiveEntryRequestSupplier.get()); - return null; - } - }; - } - - /** - * Write the contents this to the target {@link ZipArchiveOutputStream}. - *

- * It may be beneficial to write things like directories and manifest files to the targetStream - * before calling this method. - *

- * - *

Calling this method will shut down the {@link ExecutorService} used by this class. If any of the {@link - * Callable}s {@link #submit}ted to this instance throws an exception, the archive can not be created properly and - * this method will throw an exception.

- * - * @param targetStream The {@link ZipArchiveOutputStream} to receive the contents of the scatter streams - * @throws IOException If writing fails - * @throws InterruptedException If we get interrupted - * @throws ExecutionException If something happens in the parallel execution - */ - public void writeTo(final ZipArchiveOutputStream targetStream) - throws IOException, InterruptedException, ExecutionException { - - // Make sure we catch any exceptions from parallel phase - try { - for (final Future future : futures) { - future.get(); - } - } finally { - es.shutdown(); - } - - es.awaitTermination(1000 * 60L, TimeUnit.SECONDS); // == Infinity. We really *must* wait for this to complete - - // It is important that all threads terminate before we go on, ensure happens-before relationship - compressionDoneAt = System.currentTimeMillis(); - - synchronized (streams) { - for (final ScatterZipOutputStream scatterStream : streams) { - scatterStream.writeTo(targetStream); - scatterStream.close(); - } - } - - scatterDoneAt = System.currentTimeMillis(); - } - - /** - * Returns a message describing the overall statistics of the compression run - * - * @return A string - */ - public ScatterStatistics getStatisticsMessage() { - return new ScatterStatistics(compressionDoneAt - startedAt, scatterDoneAt - compressionDoneAt); - } -} - diff --git a/src/org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField.java b/src/org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField.java deleted file mode 100644 index 3d0741c0467..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - - -import java.util.zip.ZipException; - -/** - * An extra field who's sole purpose is to align and pad the local file header - * so that the entry's data starts at a certain position. - * - *

The padding content of the padding is ignored and not retained - * when reading a padding field.

- * - *

This enables Commons Compress to create "aligned" archives - * similar to Android's zipalign command line tool.

- * - * @since 1.14 - * @see "https://developer.android.com/studio/command-line/zipalign.html" - * @see ZipArchiveEntry#setAlignment - */ -public class ResourceAlignmentExtraField implements ZipExtraField { - - /** - * Extra field id used for storing alignment and padding. - */ - public static final ZipShort ID = new ZipShort(0xa11e); - - public static final int BASE_SIZE = 2; - - private static final int ALLOW_METHOD_MESSAGE_CHANGE_FLAG = 0x8000; - - private short alignment; - - private boolean allowMethodChange; - - private int padding = 0; - - public ResourceAlignmentExtraField() { - } - - public ResourceAlignmentExtraField(int alignment) { - this(alignment, false); - } - - public ResourceAlignmentExtraField(int alignment, boolean allowMethodChange) { - this(alignment, allowMethodChange, 0); - } - - public ResourceAlignmentExtraField(int alignment, boolean allowMethodChange, int padding) { - if (alignment < 0 || alignment > 0x7fff) { - throw new IllegalArgumentException("Alignment must be between 0 and 0x7fff, was: " + alignment); - } - this.alignment = (short) alignment; - this.allowMethodChange = allowMethodChange; - this.padding = padding; - } - - /** - * Gets requested alignment. - * - * @return - * requested alignment. - */ - public short getAlignment() { - return alignment; - } - - /** - * Indicates whether method change is allowed when re-compressing the zip file. - * - * @return - * true if method change is allowed, false otherwise. - */ - public boolean allowMethodChange() { - return allowMethodChange; - } - - @Override - public ZipShort getHeaderId() { - return ID; - } - - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(BASE_SIZE + padding); - } - - @Override - public ZipShort getCentralDirectoryLength() { - return new ZipShort(BASE_SIZE); - } - - @Override - public byte[] getLocalFileDataData() { - byte[] content = new byte[BASE_SIZE + padding]; - ZipShort.putShort(alignment | (allowMethodChange ? ALLOW_METHOD_MESSAGE_CHANGE_FLAG : 0), - content, 0); - return content; - } - - @Override - public byte[] getCentralDirectoryData() { - return ZipShort.getBytes(alignment | (allowMethodChange ? ALLOW_METHOD_MESSAGE_CHANGE_FLAG : 0)); - } - - @Override - public void parseFromLocalFileData(byte[] buffer, int offset, int length) throws ZipException { - parseFromCentralDirectoryData(buffer, offset, length); - this.padding = length - BASE_SIZE; - } - - @Override - public void parseFromCentralDirectoryData(byte[] buffer, int offset, int length) throws ZipException { - if (length < BASE_SIZE) { - throw new ZipException("Too short content for ResourceAlignmentExtraField (0xa11e): " + length); - } - int alignmentValue = ZipShort.getValue(buffer, offset); - this.alignment = (short) (alignmentValue & (ALLOW_METHOD_MESSAGE_CHANGE_FLAG - 1)); - this.allowMethodChange = (alignmentValue & ALLOW_METHOD_MESSAGE_CHANGE_FLAG) != 0; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ScatterStatistics.java b/src/org/apache/commons/compress/archivers/zip/ScatterStatistics.java deleted file mode 100644 index 83c5bb5e917..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ScatterStatistics.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - package org.apache.commons.compress.archivers.zip; - -/** - * Provides information about a scatter compression run. - * - * @since 1.10 - */ -public class ScatterStatistics { - private final long compressionElapsed; - private final long mergingElapsed; - - ScatterStatistics(final long compressionElapsed, final long mergingElapsed) { - this.compressionElapsed = compressionElapsed; - this.mergingElapsed = mergingElapsed; - } - - /** - * The number of milliseconds elapsed in the parallel compression phase - * @return The number of milliseconds elapsed - */ - public long getCompressionElapsed() { - return compressionElapsed; - } - - /** - * The number of milliseconds elapsed in merging the results of the parallel compression, the IO phase - * @return The number of milliseconds elapsed - */ - public long getMergingElapsed() { - return mergingElapsed; - } - - @Override - public String toString() { - return "compressionElapsed=" + compressionElapsed + "ms, mergingElapsed=" + mergingElapsed + "ms"; - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/ScatterZipOutputStream.java b/src/org/apache/commons/compress/archivers/zip/ScatterZipOutputStream.java deleted file mode 100644 index 7076e2a397f..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ScatterZipOutputStream.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - - -import org.apache.commons.compress.parallel.FileBasedScatterGatherBackingStore; -import org.apache.commons.compress.parallel.ScatterGatherBackingStore; -import org.apache.commons.compress.utils.BoundedInputStream; - -import java.io.Closeable; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.zip.Deflater; - -/** - * A zip output stream that is optimized for multi-threaded scatter/gather construction of zip files. - *

- * The internal data format of the entries used by this class are entirely private to this class - * and are not part of any public api whatsoever. - *

- *

It is possible to extend this class to support different kinds of backing storage, the default - * implementation only supports file-based backing. - *

- * Thread safety: This class supports multiple threads. But the "writeTo" method must be called - * by the thread that originally created the {@link ZipArchiveEntry}. - * - * @since 1.10 - */ -public class ScatterZipOutputStream implements Closeable { - private final Queue items = new ConcurrentLinkedQueue<>(); - private final ScatterGatherBackingStore backingStore; - private final StreamCompressor streamCompressor; - - private static class CompressedEntry { - final ZipArchiveEntryRequest zipArchiveEntryRequest; - final long crc; - final long compressedSize; - final long size; - - public CompressedEntry(final ZipArchiveEntryRequest zipArchiveEntryRequest, final long crc, final long compressedSize, final long size) { - this.zipArchiveEntryRequest = zipArchiveEntryRequest; - this.crc = crc; - this.compressedSize = compressedSize; - this.size = size; - } - - /** - * Update the original {@link ZipArchiveEntry} with sizes/crc - * Do not use this methods from threads that did not create the instance itself ! - * @return the zipArchiveEntry that is basis for this request - */ - - public ZipArchiveEntry transferToArchiveEntry(){ - final ZipArchiveEntry entry = zipArchiveEntryRequest.getZipArchiveEntry(); - entry.setCompressedSize(compressedSize); - entry.setSize(size); - entry.setCrc(crc); - entry.setMethod(zipArchiveEntryRequest.getMethod()); - return entry; - } - } - - public ScatterZipOutputStream(final ScatterGatherBackingStore backingStore, - final StreamCompressor streamCompressor) { - this.backingStore = backingStore; - this.streamCompressor = streamCompressor; - } - - /** - * Add an archive entry to this scatter stream. - * - * @param zipArchiveEntryRequest The entry to write. - * @throws IOException If writing fails - */ - public void addArchiveEntry(final ZipArchiveEntryRequest zipArchiveEntryRequest) throws IOException { - try (final InputStream payloadStream = zipArchiveEntryRequest.getPayloadStream()) { - streamCompressor.deflate(payloadStream, zipArchiveEntryRequest.getMethod()); - } - items.add(new CompressedEntry(zipArchiveEntryRequest, streamCompressor.getCrc32(), - streamCompressor.getBytesWrittenForLastEntry(), streamCompressor.getBytesRead())); - } - - /** - * Write the contents of this scatter stream to a target archive. - * - * @param target The archive to receive the contents of this {@link ScatterZipOutputStream}. - * @throws IOException If writing fails - */ - public void writeTo(final ZipArchiveOutputStream target) throws IOException { - backingStore.closeForWriting(); - try (final InputStream data = backingStore.getInputStream()) { - for (final CompressedEntry compressedEntry : items) { - try (final BoundedInputStream rawStream = new BoundedInputStream(data, - compressedEntry.compressedSize)) { - target.addRawArchiveEntry(compressedEntry.transferToArchiveEntry(), rawStream); - } - } - } - } - - - /** - * Closes this stream, freeing all resources involved in the creation of this stream. - * @throws IOException If closing fails - */ - @Override - public void close() throws IOException { - backingStore.close(); - streamCompressor.close(); - } - - /** - * Create a {@link ScatterZipOutputStream} with default compression level that is backed by a file - * - * @param file The file to offload compressed data into. - * @return A ScatterZipOutputStream that is ready for use. - * @throws FileNotFoundException if the file cannot be found - */ - public static ScatterZipOutputStream fileBased(final File file) throws FileNotFoundException { - return fileBased(file, Deflater.DEFAULT_COMPRESSION); - } - - /** - * Create a {@link ScatterZipOutputStream} that is backed by a file - * - * @param file The file to offload compressed data into. - * @param compressionLevel The compression level to use, @see #Deflater - * @return A ScatterZipOutputStream that is ready for use. - * @throws FileNotFoundException if the file cannot be found - */ - public static ScatterZipOutputStream fileBased(final File file, final int compressionLevel) throws FileNotFoundException { - final ScatterGatherBackingStore bs = new FileBasedScatterGatherBackingStore(file); - // lifecycle is bound to the ScatterZipOutputStream returned - final StreamCompressor sc = StreamCompressor.create(compressionLevel, bs); //NOSONAR - return new ScatterZipOutputStream(bs, sc); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/StreamCompressor.java b/src/org/apache/commons/compress/archivers/zip/StreamCompressor.java deleted file mode 100644 index 1e8d68b64ff..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/StreamCompressor.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.parallel.ScatterGatherBackingStore; - -import java.io.Closeable; -import java.io.DataOutput; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.SeekableByteChannel; -import java.util.zip.CRC32; -import java.util.zip.Deflater; -import java.util.zip.ZipEntry; - -/** - * Encapsulates a {@link Deflater} and crc calculator, handling multiple types of output streams. - * Currently {@link java.util.zip.ZipEntry#DEFLATED} and {@link java.util.zip.ZipEntry#STORED} are the only - * supported compression methods. - * - * @since 1.10 - */ -public abstract class StreamCompressor implements Closeable { - - /* - * Apparently Deflater.setInput gets slowed down a lot on Sun JVMs - * when it gets handed a really big buffer. See - * https://issues.apache.org/bugzilla/show_bug.cgi?id=45396 - * - * Using a buffer size of 8 kB proved to be a good compromise - */ - private static final int DEFLATER_BLOCK_SIZE = 8192; - - private final Deflater def; - - private final CRC32 crc = new CRC32(); - - private long writtenToOutputStreamForLastEntry = 0; - private long sourcePayloadLength = 0; - private long totalWrittenToOutputStream = 0; - - private static final int BUFFER_SIZE = 4096; - private final byte[] outputBuffer = new byte[BUFFER_SIZE]; - private final byte[] readerBuf = new byte[BUFFER_SIZE]; - - StreamCompressor(final Deflater deflater) { - this.def = deflater; - } - - /** - * Create a stream compressor with the given compression level. - * - * @param os The stream to receive output - * @param deflater The deflater to use - * @return A stream compressor - */ - static StreamCompressor create(final OutputStream os, final Deflater deflater) { - return new OutputStreamCompressor(deflater, os); - } - - /** - * Create a stream compressor with the default compression level. - * - * @param os The stream to receive output - * @return A stream compressor - */ - static StreamCompressor create(final OutputStream os) { - return create(os, new Deflater(Deflater.DEFAULT_COMPRESSION, true)); - } - - /** - * Create a stream compressor with the given compression level. - * - * @param os The DataOutput to receive output - * @param deflater The deflater to use for the compressor - * @return A stream compressor - */ - static StreamCompressor create(final DataOutput os, final Deflater deflater) { - return new DataOutputCompressor(deflater, os); - } - - /** - * Create a stream compressor with the given compression level. - * - * @param os The SeekableByteChannel to receive output - * @param deflater The deflater to use for the compressor - * @return A stream compressor - * @since 1.13 - */ - static StreamCompressor create(final SeekableByteChannel os, final Deflater deflater) { - return new SeekableByteChannelCompressor(deflater, os); - } - - /** - * Create a stream compressor with the given compression level. - * - * @param compressionLevel The {@link Deflater} compression level - * @param bs The ScatterGatherBackingStore to receive output - * @return A stream compressor - */ - public static StreamCompressor create(final int compressionLevel, final ScatterGatherBackingStore bs) { - final Deflater deflater = new Deflater(compressionLevel, true); - return new ScatterGatherBackingStoreCompressor(deflater, bs); - } - - /** - * Create a stream compressor with the default compression level. - * - * @param bs The ScatterGatherBackingStore to receive output - * @return A stream compressor - */ - public static StreamCompressor create(final ScatterGatherBackingStore bs) { - return create(Deflater.DEFAULT_COMPRESSION, bs); - } - - /** - * The crc32 of the last deflated file - * - * @return the crc32 - */ - - public long getCrc32() { - return crc.getValue(); - } - - /** - * Return the number of bytes read from the source stream - * - * @return The number of bytes read, never negative - */ - public long getBytesRead() { - return sourcePayloadLength; - } - - /** - * The number of bytes written to the output for the last entry - * - * @return The number of bytes, never negative - */ - public long getBytesWrittenForLastEntry() { - return writtenToOutputStreamForLastEntry; - } - - /** - * The total number of bytes written to the output for all files - * - * @return The number of bytes, never negative - */ - public long getTotalBytesWritten() { - return totalWrittenToOutputStream; - } - - - /** - * Deflate the given source using the supplied compression method - * - * @param source The source to compress - * @param method The #ZipArchiveEntry compression method - * @throws IOException When failures happen - */ - - public void deflate(final InputStream source, final int method) throws IOException { - reset(); - int length; - - while ((length = source.read(readerBuf, 0, readerBuf.length)) >= 0) { - write(readerBuf, 0, length, method); - } - if (method == ZipEntry.DEFLATED) { - flushDeflater(); - } - } - - /** - * Writes bytes to ZIP entry. - * - * @param b the byte array to write - * @param offset the start position to write from - * @param length the number of bytes to write - * @param method the comrpession method to use - * @return the number of bytes written to the stream this time - * @throws IOException on error - */ - long write(final byte[] b, final int offset, final int length, final int method) throws IOException { - final long current = writtenToOutputStreamForLastEntry; - crc.update(b, offset, length); - if (method == ZipEntry.DEFLATED) { - writeDeflated(b, offset, length); - } else { - writeCounted(b, offset, length); - } - sourcePayloadLength += length; - return writtenToOutputStreamForLastEntry - current; - } - - - void reset() { - crc.reset(); - def.reset(); - sourcePayloadLength = 0; - writtenToOutputStreamForLastEntry = 0; - } - - @Override - public void close() throws IOException { - def.end(); - } - - void flushDeflater() throws IOException { - def.finish(); - while (!def.finished()) { - deflate(); - } - } - - private void writeDeflated(final byte[] b, final int offset, final int length) - throws IOException { - if (length > 0 && !def.finished()) { - if (length <= DEFLATER_BLOCK_SIZE) { - def.setInput(b, offset, length); - deflateUntilInputIsNeeded(); - } else { - final int fullblocks = length / DEFLATER_BLOCK_SIZE; - for (int i = 0; i < fullblocks; i++) { - def.setInput(b, offset + i * DEFLATER_BLOCK_SIZE, - DEFLATER_BLOCK_SIZE); - deflateUntilInputIsNeeded(); - } - final int done = fullblocks * DEFLATER_BLOCK_SIZE; - if (done < length) { - def.setInput(b, offset + done, length - done); - deflateUntilInputIsNeeded(); - } - } - } - } - - private void deflateUntilInputIsNeeded() throws IOException { - while (!def.needsInput()) { - deflate(); - } - } - - void deflate() throws IOException { - final int len = def.deflate(outputBuffer, 0, outputBuffer.length); - if (len > 0) { - writeCounted(outputBuffer, 0, len); - } - } - - public void writeCounted(final byte[] data) throws IOException { - writeCounted(data, 0, data.length); - } - - public void writeCounted(final byte[] data, final int offset, final int length) throws IOException { - writeOut(data, offset, length); - writtenToOutputStreamForLastEntry += length; - totalWrittenToOutputStream += length; - } - - protected abstract void writeOut(byte[] data, int offset, int length) throws IOException; - - private static final class ScatterGatherBackingStoreCompressor extends StreamCompressor { - private final ScatterGatherBackingStore bs; - - public ScatterGatherBackingStoreCompressor(final Deflater deflater, final ScatterGatherBackingStore bs) { - super(deflater); - this.bs = bs; - } - - @Override - protected final void writeOut(final byte[] data, final int offset, final int length) - throws IOException { - bs.writeOut(data, offset, length); - } - } - - private static final class OutputStreamCompressor extends StreamCompressor { - private final OutputStream os; - - public OutputStreamCompressor(final Deflater deflater, final OutputStream os) { - super(deflater); - this.os = os; - } - - @Override - protected final void writeOut(final byte[] data, final int offset, final int length) - throws IOException { - os.write(data, offset, length); - } - } - - private static final class DataOutputCompressor extends StreamCompressor { - private final DataOutput raf; - - public DataOutputCompressor(final Deflater deflater, final DataOutput raf) { - super(deflater); - this.raf = raf; - } - - @Override - protected final void writeOut(final byte[] data, final int offset, final int length) - throws IOException { - raf.write(data, offset, length); - } - } - - private static final class SeekableByteChannelCompressor extends StreamCompressor { - private final SeekableByteChannel channel; - - public SeekableByteChannelCompressor(final Deflater deflater, - final SeekableByteChannel channel) { - super(deflater); - this.channel = channel; - } - - @Override - protected final void writeOut(final byte[] data, final int offset, final int length) - throws IOException { - channel.write(ByteBuffer.wrap(data, offset, length)); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/UnicodeCommentExtraField.java b/src/org/apache/commons/compress/archivers/zip/UnicodeCommentExtraField.java deleted file mode 100644 index 0b0e84e26a6..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/UnicodeCommentExtraField.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -/** - * Info-ZIP Unicode Comment Extra Field (0x6375): - * - *

Stores the UTF-8 version of the file comment as stored in the - * central directory header.

- * - * @see PKWARE - * APPNOTE.TXT, section 4.6.8 - * - * @NotThreadSafe super-class is not thread-safe - */ -public class UnicodeCommentExtraField extends AbstractUnicodeExtraField { - - public static final ZipShort UCOM_ID = new ZipShort(0x6375); - - public UnicodeCommentExtraField () { - } - - /** - * Assemble as unicode comment extension from the name given as - * text as well as the encoded bytes actually written to the archive. - * - * @param text The file name - * @param bytes the bytes actually written to the archive - * @param off The offset of the encoded comment in bytes. - * @param len The length of the encoded comment or comment in - * bytes. - */ - public UnicodeCommentExtraField(final String text, final byte[] bytes, final int off, - final int len) { - super(text, bytes, off, len); - } - - /** - * Assemble as unicode comment extension from the comment given as - * text as well as the bytes actually written to the archive. - * - * @param comment The file comment - * @param bytes the bytes actually written to the archive - */ - public UnicodeCommentExtraField(final String comment, final byte[] bytes) { - super(comment, bytes); - } - - @Override - public ZipShort getHeaderId() { - return UCOM_ID; - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/UnicodePathExtraField.java b/src/org/apache/commons/compress/archivers/zip/UnicodePathExtraField.java deleted file mode 100644 index 510c5adeb75..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/UnicodePathExtraField.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -/** - * Info-ZIP Unicode Path Extra Field (0x7075): - * - *

Stores the UTF-8 version of the file name field as stored in the - * local header and central directory header.

- * - * @see PKWARE - * APPNOTE.TXT, section 4.6.9 - * - * @NotThreadSafe super-class is not thread-safe - */ -public class UnicodePathExtraField extends AbstractUnicodeExtraField { - - public static final ZipShort UPATH_ID = new ZipShort(0x7075); - - public UnicodePathExtraField () { - } - - /** - * Assemble as unicode path extension from the name given as - * text as well as the encoded bytes actually written to the archive. - * - * @param text The file name - * @param bytes the bytes actually written to the archive - * @param off The offset of the encoded filename in bytes. - * @param len The length of the encoded filename or comment in - * bytes. - */ - public UnicodePathExtraField(final String text, final byte[] bytes, final int off, final int len) { - super(text, bytes, off, len); - } - - /** - * Assemble as unicode path extension from the name given as - * text as well as the encoded bytes actually written to the archive. - * - * @param name The file name - * @param bytes the bytes actually written to the archive - */ - public UnicodePathExtraField(final String name, final byte[] bytes) { - super(name, bytes); - } - - @Override - public ZipShort getHeaderId() { - return UPATH_ID; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/UnixStat.java b/src/org/apache/commons/compress/archivers/zip/UnixStat.java deleted file mode 100644 index a1b20be3917..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/UnixStat.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * Constants from stat.h on Unix systems. - */ -// CheckStyle:InterfaceIsTypeCheck OFF - backward compatible -public interface UnixStat { - - /** - * Bits used for permissions (and sticky bit) - */ - int PERM_MASK = 07777; - /** - * Bits used to indicate the filesystem object type. - * @since 1.14 - */ - int FILE_TYPE_FLAG = 0170000; - /** - * Indicates symbolic links. - */ - int LINK_FLAG = 0120000; - /** - * Indicates plain files. - */ - int FILE_FLAG = 0100000; - /** - * Indicates directories. - */ - int DIR_FLAG = 040000; - - // ---------------------------------------------------------- - // somewhat arbitrary choices that are quite common for shared - // installations - // ----------------------------------------------------------- - - /** - * Default permissions for symbolic links. - */ - int DEFAULT_LINK_PERM = 0777; - - /** - * Default permissions for directories. - */ - int DEFAULT_DIR_PERM = 0755; - - /** - * Default permissions for plain files. - */ - int DEFAULT_FILE_PERM = 0644; -} diff --git a/src/org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData.java b/src/org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData.java deleted file mode 100644 index d7d24dfedf3..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * Wrapper for extra field data that doesn't conform to the recommended format of header-tag + size + data. - * - *

The header-id is artificial (and not listed as a known ID in APPNOTE.TXT). Since it isn't used anywhere - * except to satisfy the ZipExtraField contract it shouldn't matter anyway.

- * - * @since 1.1 - * @NotThreadSafe - */ -public final class UnparseableExtraFieldData implements ZipExtraField { - private static final ZipShort HEADER_ID = new ZipShort(0xACC1); - - private byte[] localFileData; - private byte[] centralDirectoryData; - - /** - * The Header-ID. - * - * @return a completely arbitrary value that should be ignored. - */ - @Override - public ZipShort getHeaderId() { - return HEADER_ID; - } - - /** - * Length of the complete extra field in the local file data. - * - * @return The LocalFileDataLength value - */ - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(localFileData == null ? 0 : localFileData.length); - } - - /** - * Length of the complete extra field in the central directory. - * - * @return The CentralDirectoryLength value - */ - @Override - public ZipShort getCentralDirectoryLength() { - return centralDirectoryData == null - ? getLocalFileDataLength() - : new ZipShort(centralDirectoryData.length); - } - - /** - * The actual data to put into local file data. - * - * @return The LocalFileDataData value - */ - @Override - public byte[] getLocalFileDataData() { - return ZipUtil.copy(localFileData); - } - - /** - * The actual data to put into central directory. - * - * @return The CentralDirectoryData value - */ - @Override - public byte[] getCentralDirectoryData() { - return centralDirectoryData == null - ? getLocalFileDataData() : ZipUtil.copy(centralDirectoryData); - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param buffer the buffer to read data from - * @param offset offset into buffer to read data - * @param length the length of data - */ - @Override - public void parseFromLocalFileData(final byte[] buffer, final int offset, final int length) { - localFileData = new byte[length]; - System.arraycopy(buffer, offset, localFileData, 0, length); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param buffer the buffer to read data from - * @param offset offset into buffer to read data - * @param length the length of data - */ - @Override - public void parseFromCentralDirectoryData(final byte[] buffer, final int offset, - final int length) { - centralDirectoryData = new byte[length]; - System.arraycopy(buffer, offset, centralDirectoryData, 0, length); - if (localFileData == null) { - parseFromLocalFileData(buffer, offset, length); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java b/src/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java deleted file mode 100644 index f8ea8b9736d..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/UnrecognizedExtraField.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * Simple placeholder for all those extra fields we don't want to deal - * with. - * - *

Assumes local file data and central directory entries are - * identical - unless told the opposite.

- * @NotThreadSafe - */ -public class UnrecognizedExtraField implements ZipExtraField { - - /** - * The Header-ID. - */ - private ZipShort headerId; - - /** - * Set the header id. - * @param headerId the header id to use - */ - public void setHeaderId(final ZipShort headerId) { - this.headerId = headerId; - } - - /** - * Get the header id. - * @return the header id - */ - @Override - public ZipShort getHeaderId() { - return headerId; - } - - /** - * Extra field data in local file data - without - * Header-ID or length specifier. - */ - private byte[] localData; - - /** - * Set the extra field data in the local file data - - * without Header-ID or length specifier. - * @param data the field data to use - */ - public void setLocalFileDataData(final byte[] data) { - localData = ZipUtil.copy(data); - } - - /** - * Get the length of the local data. - * @return the length of the local data - */ - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(localData != null ? localData.length : 0); - } - - /** - * Get the local data. - * @return the local data - */ - @Override - public byte[] getLocalFileDataData() { - return ZipUtil.copy(localData); - } - - /** - * Extra field data in central directory - without - * Header-ID or length specifier. - */ - private byte[] centralData; - - /** - * Set the extra field data in central directory. - * @param data the data to use - */ - public void setCentralDirectoryData(final byte[] data) { - centralData = ZipUtil.copy(data); - } - - /** - * Get the central data length. - * If there is no central data, get the local file data length. - * @return the central data length - */ - @Override - public ZipShort getCentralDirectoryLength() { - if (centralData != null) { - return new ZipShort(centralData.length); - } - return getLocalFileDataLength(); - } - - /** - * Get the central data. - * @return the central data if present, else return the local file data - */ - @Override - public byte[] getCentralDirectoryData() { - if (centralData != null) { - return ZipUtil.copy(centralData); - } - return getLocalFileDataData(); - } - - /** - * @param data the array of bytes. - * @param offset the source location in the data array. - * @param length the number of bytes to use in the data array. - * @see ZipExtraField#parseFromLocalFileData(byte[], int, int) - */ - @Override - public void parseFromLocalFileData(final byte[] data, final int offset, final int length) { - final byte[] tmp = new byte[length]; - System.arraycopy(data, offset, tmp, 0, length); - setLocalFileDataData(tmp); - } - - /** - * @param data the array of bytes. - * @param offset the source location in the data array. - * @param length the number of bytes to use in the data array. - * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int) - */ - @Override - public void parseFromCentralDirectoryData(final byte[] data, final int offset, - final int length) { - final byte[] tmp = new byte[length]; - System.arraycopy(data, offset, tmp, 0, length); - setCentralDirectoryData(tmp); - if (localData == null) { - setLocalFileDataData(tmp); - } - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java b/src/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java deleted file mode 100644 index 11c904cad89..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/UnshrinkingInputStream.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteOrder; - -import org.apache.commons.compress.compressors.lzw.LZWInputStream; - -/** - * Input stream that decompresses ZIP method 1 (unshrinking). A variation of the LZW algorithm, with some twists. - * @NotThreadSafe - * @since 1.7 - */ -class UnshrinkingInputStream extends LZWInputStream { - private static final int MAX_CODE_SIZE = 13; - private static final int MAX_TABLE_SIZE = 1 << MAX_CODE_SIZE; - private final boolean[] isUsed; - - /** - * IOException is not actually thrown! - * - * @param inputStream - * @throws IOException IOException is not actually thrown! - */ - public UnshrinkingInputStream(final InputStream inputStream) throws IOException { - super(inputStream, ByteOrder.LITTLE_ENDIAN); - setClearCode(DEFAULT_CODE_SIZE); - initializeTables(MAX_CODE_SIZE); - isUsed = new boolean[getPrefixesLength()]; - for (int i = 0; i < (1 << 8); i++) { - isUsed[i] = true; - } - setTableSize(getClearCode() + 1); - } - - @Override - protected int addEntry(final int previousCode, final byte character) throws IOException { - int tableSize = getTableSize(); - while ((tableSize < MAX_TABLE_SIZE) && isUsed[tableSize]) { - tableSize++; - } - setTableSize(tableSize); - final int idx = addEntry(previousCode, character, MAX_TABLE_SIZE); - if (idx >= 0) { - isUsed[idx] = true; - } - return idx; - } - - private void partialClear() { - final boolean[] isParent = new boolean[MAX_TABLE_SIZE]; - for (int i = 0; i < isUsed.length; i++) { - if (isUsed[i] && getPrefix(i) != UNUSED_PREFIX) { - isParent[getPrefix(i)] = true; - } - } - for (int i = getClearCode() + 1; i < isParent.length; i++) { - if (!isParent[i]) { - isUsed[i] = false; - setPrefix(i, UNUSED_PREFIX); - } - } - } - - @Override - protected int decompressNextSymbol() throws IOException { - // - // table entry table entry - // _____________ _____ - // table entry / \ / \ - // ____________/ \ \ - // / / \ / \ \ - // +---+---+---+---+---+---+---+---+---+---+ - // | . | . | . | . | . | . | . | . | . | . | - // +---+---+---+---+---+---+---+---+---+---+ - // |<--------->|<------------->|<----->|<->| - // symbol symbol symbol symbol - // - final int code = readNextCode(); - if (code < 0) { - return -1; - } else if (code == getClearCode()) { - final int subCode = readNextCode(); - if (subCode < 0) { - throw new IOException("Unexpected EOF;"); - } else if (subCode == 1) { - if (getCodeSize() < MAX_CODE_SIZE) { - incrementCodeSize(); - } else { - throw new IOException("Attempt to increase code size beyond maximum"); - } - } else if (subCode == 2) { - partialClear(); - setTableSize(getClearCode() + 1); - } else { - throw new IOException("Invalid clear code subcode " + subCode); - } - return 0; - } else { - boolean addedUnfinishedEntry = false; - int effectiveCode = code; - if (!isUsed[code]) { - effectiveCode = addRepeatOfPreviousCode(); - addedUnfinishedEntry = true; - } - return expandCodeToOutputStack(effectiveCode, addedUnfinishedEntry); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/UnsupportedZipFeatureException.java b/src/org/apache/commons/compress/archivers/zip/UnsupportedZipFeatureException.java deleted file mode 100644 index a92f9c71a00..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/UnsupportedZipFeatureException.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -import java.util.zip.ZipException; - -/** - * Exception thrown when attempting to read or write data for a zip - * entry that uses ZIP features not supported by this library. - * @since 1.1 - */ -public class UnsupportedZipFeatureException extends ZipException { - - private final Feature reason; - private transient final ZipArchiveEntry entry; - private static final long serialVersionUID = 20161219L; - - /** - * Creates an exception. - * @param reason the feature that is not supported - * @param entry the entry using the feature - */ - public UnsupportedZipFeatureException(final Feature reason, - final ZipArchiveEntry entry) { - super("unsupported feature " + reason + " used in entry " - + entry.getName()); - this.reason = reason; - this.entry = entry; - } - - /** - * Creates an exception for archives that use an unsupported - * compression algorithm. - * @param method the method that is not supported - * @param entry the entry using the feature - * @since 1.5 - */ - public UnsupportedZipFeatureException(final ZipMethod method, - final ZipArchiveEntry entry) { - super("unsupported feature method '" + method.name() - + "' used in entry " + entry.getName()); - this.reason = Feature.METHOD; - this.entry = entry; - } - - /** - * Creates an exception when the whole archive uses an unsupported - * feature. - * - * @param reason the feature that is not supported - * @since 1.5 - */ - public UnsupportedZipFeatureException(final Feature reason) { - super("unsupported feature " + reason + " used in archive."); - this.reason = reason; - this.entry = null; - } - - /** - * The unsupported feature that has been used. - * @return The unsupported feature that has been used. - */ - public Feature getFeature() { - return reason; - } - - /** - * The entry using the unsupported feature. - * @return The entry using the unsupported feature. - */ - public ZipArchiveEntry getEntry() { - return entry; - } - - /** - * ZIP Features that may or may not be supported. - * @since 1.1 - */ - public static class Feature implements java.io.Serializable { - - private static final long serialVersionUID = 4112582948775420359L; - /** - * The entry is encrypted. - */ - public static final Feature ENCRYPTION = new Feature("encryption"); - /** - * The entry used an unsupported compression method. - */ - public static final Feature METHOD = new Feature("compression method"); - /** - * The entry uses a data descriptor. - */ - public static final Feature DATA_DESCRIPTOR = new Feature("data descriptor"); - /** - * The archive uses splitting or spanning. - * @since 1.5 - */ - public static final Feature SPLITTING = new Feature("splitting"); - /** - * The archive contains entries with unknown compressed size - * for a compression method that doesn't support detection of - * the end of the compressed stream. - * @since 1.16 - */ - public static final Feature UNKNOWN_COMPRESSED_SIZE = new Feature("unknown compressed size"); - - private final String name; - - private Feature(final String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/X000A_NTFS.java b/src/org/apache/commons/compress/archivers/zip/X000A_NTFS.java deleted file mode 100644 index 2dd5c33e661..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X000A_NTFS.java +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.Date; -import java.util.zip.ZipException; - -/** - * NTFS extra field that was thought to store various attributes but - * in reality only stores timestamps. - * - *
- *    4.5.5 -NTFS Extra Field (0x000a):
- *
- *       The following is the layout of the NTFS attributes
- *       "extra" block. (Note: At this time the Mtime, Atime
- *       and Ctime values MAY be used on any WIN32 system.)
- *
- *       Note: all fields stored in Intel low-byte/high-byte order.
- *
- *         Value      Size       Description
- *         -----      ----       -----------
- * (NTFS)  0x000a     2 bytes    Tag for this "extra" block type
- *         TSize      2 bytes    Size of the total "extra" block
- *         Reserved   4 bytes    Reserved for future use
- *         Tag1       2 bytes    NTFS attribute tag value #1
- *         Size1      2 bytes    Size of attribute #1, in bytes
- *         (var)      Size1      Attribute #1 data
- *          .
- *          .
- *          .
- *          TagN       2 bytes    NTFS attribute tag value #N
- *          SizeN      2 bytes    Size of attribute #N, in bytes
- *          (var)      SizeN      Attribute #N data
- *
- *        For NTFS, values for Tag1 through TagN are as follows:
- *        (currently only one set of attributes is defined for NTFS)
- *
- *          Tag        Size       Description
- *          -----      ----       -----------
- *          0x0001     2 bytes    Tag for attribute #1
- *          Size1      2 bytes    Size of attribute #1, in bytes
- *          Mtime      8 bytes    File last modification time
- *          Atime      8 bytes    File last access time
- *          Ctime      8 bytes    File creation time
- * 
- * - * @since 1.11 - * @NotThreadSafe - */ -public class X000A_NTFS implements ZipExtraField { - private static final ZipShort HEADER_ID = new ZipShort(0x000a); - private static final ZipShort TIME_ATTR_TAG = new ZipShort(0x0001); - private static final ZipShort TIME_ATTR_SIZE = new ZipShort(3 * 8); - - private ZipEightByteInteger modifyTime = ZipEightByteInteger.ZERO; - private ZipEightByteInteger accessTime = ZipEightByteInteger.ZERO; - private ZipEightByteInteger createTime = ZipEightByteInteger.ZERO; - - /** - * The Header-ID. - * - * @return the value for the header id for this extrafield - */ - @Override - public ZipShort getHeaderId() { - return HEADER_ID; - } - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * - * @return a ZipShort for the length of the data of this extra field - */ - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(4 /* reserved */ - + 2 /* Tag#1 */ - + 2 /* Size#1 */ - + 3 * 8 /* time values */); - } - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * - *

For X5455 the central length is often smaller than the - * local length, because central cannot contain access or create - * timestamps.

- * - * @return a ZipShort for the length of the data of this extra field - */ - @Override - public ZipShort getCentralDirectoryLength() { - return getLocalFileDataLength(); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return get the data - */ - @Override - public byte[] getLocalFileDataData() { - final byte[] data = new byte[getLocalFileDataLength().getValue()]; - int pos = 4; - System.arraycopy(TIME_ATTR_TAG.getBytes(), 0, data, pos, 2); - pos += 2; - System.arraycopy(TIME_ATTR_SIZE.getBytes(), 0, data, pos, 2); - pos += 2; - System.arraycopy(modifyTime.getBytes(), 0, data, pos, 8); - pos += 8; - System.arraycopy(accessTime.getBytes(), 0, data, pos, 8); - pos += 8; - System.arraycopy(createTime.getBytes(), 0, data, pos, 8); - return data; - } - - /** - * The actual data to put into central directory data - without Header-ID - * or length specifier. - * - * @return the central directory data - */ - @Override - public byte[] getCentralDirectoryData() { - return getLocalFileDataData(); - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param data an array of bytes - * @param offset the start offset - * @param length the number of bytes in the array from offset - * @throws java.util.zip.ZipException on error - */ - @Override - public void parseFromLocalFileData( - final byte[] data, int offset, final int length - ) throws ZipException { - final int len = offset + length; - - // skip reserved - offset += 4; - - while (offset + 4 <= len) { - final ZipShort tag = new ZipShort(data, offset); - offset += 2; - if (tag.equals(TIME_ATTR_TAG)) { - readTimeAttr(data, offset, len - offset); - break; - } - final ZipShort size = new ZipShort(data, offset); - offset += 2 + size.getValue(); - } - } - - /** - * Doesn't do anything special since this class always uses the - * same parsing logic for both central directory and local file data. - */ - @Override - public void parseFromCentralDirectoryData( - final byte[] buffer, final int offset, final int length - ) throws ZipException { - reset(); - parseFromLocalFileData(buffer, offset, length); - } - - /** - * Returns the "File last modification time" of this zip entry as - * a ZipEightByteInteger object, or {@link - * ZipEightByteInteger#ZERO} if no such timestamp exists in the - * zip entry. - * - * @return File last modification time - */ - public ZipEightByteInteger getModifyTime() { return modifyTime; } - - /** - * Returns the "File last access time" of this zip entry as a - * ZipEightByteInteger object, or {@link ZipEightByteInteger#ZERO} - * if no such timestamp exists in the zip entry. - * - * @return File last access time - */ - public ZipEightByteInteger getAccessTime() { return accessTime; } - - /** - * Returns the "File creation time" of this zip entry as a - * ZipEightByteInteger object, or {@link ZipEightByteInteger#ZERO} - * if no such timestamp exists in the zip entry. - * - * @return File creation time - */ - public ZipEightByteInteger getCreateTime() { return createTime; } - - /** - * Returns the modify time as a java.util.Date - * of this zip entry, or null if no such timestamp exists in the zip entry. - * - * @return modify time as java.util.Date or null. - */ - public Date getModifyJavaTime() { - return zipToDate(modifyTime); - } - - /** - * Returns the access time as a java.util.Date - * of this zip entry, or null if no such timestamp exists in the zip entry. - * - * @return access time as java.util.Date or null. - */ - public Date getAccessJavaTime() { - return zipToDate(accessTime); - } - - /** - * Returns the create time as a a java.util.Date of this zip - * entry, or null if no such timestamp exists in the zip entry. - * - * @return create time as java.util.Date or null. - */ - public Date getCreateJavaTime() { - return zipToDate(createTime); - } - - /** - * Sets the File last modification time of this zip entry using a - * ZipEightByteInteger object. - * - * @param t ZipEightByteInteger of the modify time - */ - public void setModifyTime(final ZipEightByteInteger t) { - modifyTime = t == null ? ZipEightByteInteger.ZERO : t; - } - - /** - * Sets the File last access time of this zip entry using a - * ZipEightByteInteger object. - * - * @param t ZipEightByteInteger of the access time - */ - public void setAccessTime(final ZipEightByteInteger t) { - accessTime = t == null ? ZipEightByteInteger.ZERO : t; - } - - /** - * Sets the File creation time of this zip entry using a - * ZipEightByteInteger object. - * - * @param t ZipEightByteInteger of the create time - */ - public void setCreateTime(final ZipEightByteInteger t) { - createTime = t == null ? ZipEightByteInteger.ZERO : t; - } - - /** - * Sets the modify time as a java.util.Date of this zip entry. - * - * @param d modify time as java.util.Date - */ - public void setModifyJavaTime(final Date d) { setModifyTime(dateToZip(d)); } - - /** - * Sets the access time as a java.util.Date - * of this zip entry. - * - * @param d access time as java.util.Date - */ - public void setAccessJavaTime(final Date d) { setAccessTime(dateToZip(d)); } - - /** - *

- * Sets the create time as a java.util.Date - * of this zip entry. Supplied value is truncated to per-second - * precision (milliseconds zeroed-out). - *

- * Note: the setters for flags and timestamps are decoupled. - * Even if the timestamp is not-null, it will only be written - * out if the corresponding bit in the flags is also set. - *

- * - * @param d create time as java.util.Date - */ - public void setCreateJavaTime(final Date d) { setCreateTime(dateToZip(d)); } - - /** - * Returns a String representation of this class useful for - * debugging purposes. - * - * @return A String representation of this class useful for - * debugging purposes. - */ - @Override - public String toString() { - final StringBuilder buf = new StringBuilder(); - buf.append("0x000A Zip Extra Field:") - .append(" Modify:[").append(getModifyJavaTime()).append("] ") - .append(" Access:[").append(getAccessJavaTime()).append("] ") - .append(" Create:[").append(getCreateJavaTime()).append("] "); - return buf.toString(); - } - - @Override - public boolean equals(final Object o) { - if (o instanceof X000A_NTFS) { - final X000A_NTFS xf = (X000A_NTFS) o; - - return (modifyTime == xf.modifyTime || (modifyTime != null && modifyTime.equals(xf.modifyTime))) && - (accessTime == xf.accessTime || (accessTime != null && accessTime.equals(xf.accessTime))) && - (createTime == xf.createTime || (createTime != null && createTime.equals(xf.createTime))); - } - return false; - } - - @Override - public int hashCode() { - int hc = -123; - if (modifyTime != null) { - hc ^= modifyTime.hashCode(); - } - if (accessTime != null) { - // Since accessTime is often same as modifyTime, - // this prevents them from XOR negating each other. - hc ^= Integer.rotateLeft(accessTime.hashCode(), 11); - } - if (createTime != null) { - hc ^= Integer.rotateLeft(createTime.hashCode(), 22); - } - return hc; - } - - /** - * Reset state back to newly constructed state. Helps us make sure - * parse() calls always generate clean results. - */ - private void reset() { - this.modifyTime = ZipEightByteInteger.ZERO; - this.accessTime = ZipEightByteInteger.ZERO; - this.createTime = ZipEightByteInteger.ZERO; - } - - private void readTimeAttr(final byte[] data, int offset, final int length) { - if (length >= 2 + 3 * 8) { - final ZipShort tagValueLength = new ZipShort(data, offset); - if (TIME_ATTR_SIZE.equals(tagValueLength)) { - offset += 2; - modifyTime = new ZipEightByteInteger(data, offset); - offset += 8; - accessTime = new ZipEightByteInteger(data, offset); - offset += 8; - createTime = new ZipEightByteInteger(data, offset); - } - } - } - - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724290%28v=vs.85%29.aspx - // A file time is a 64-bit value that represents the number of - // 100-nanosecond intervals that have elapsed since 12:00 - // A.M. January 1, 1601 Coordinated Universal Time (UTC). - // this is the offset of Windows time 0 to Unix epoch in 100-nanosecond intervals - private static final long EPOCH_OFFSET = -116444736000000000L; - - private static ZipEightByteInteger dateToZip(final Date d) { - if (d == null) { return null; } - return new ZipEightByteInteger((d.getTime() * 10000L) - EPOCH_OFFSET); - } - - private static Date zipToDate(final ZipEightByteInteger z) { - if (z == null || ZipEightByteInteger.ZERO.equals(z)) { return null; } - final long l = (z.getLongValue() + EPOCH_OFFSET) / 10000L; - return new Date(l); - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java b/src/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java deleted file mode 100644 index 3be78638e37..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * PKCS#7 Store for X.509 Certificates (0x0014). - * - *

This field MUST contain information about each of the certificates files may - * be signed with. When the Central Directory Encryption feature is enabled for - * a ZIP file, this record will appear in the Archive Extra Data Record, - * otherwise it will appear in the first central directory record and will be - * ignored in any other record.

- * - *

Note: all fields stored in Intel low-byte/high-byte order.

- * - *
- *         Value     Size     Description
- *         -----     ----     -----------
- * (Store) 0x0014    2 bytes  Tag for this "extra" block type
- *         TSize     2 bytes  Size of the store data
- *         TData     TSize    Data about the store
- * 
- * - * @NotThreadSafe - * @since 1.11 - */ -public class X0014_X509Certificates extends PKWareExtraHeader { - - public X0014_X509Certificates() { - super(new ZipShort(0x0014)); - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java b/src/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java deleted file mode 100644 index 89b327b945f..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * X.509 Certificate ID and Signature for individual file (0x0015). - * - *

This field contains the information about which certificate in the PKCS#7 - * store was used to sign a particular file. It also contains the signature - * data. This field can appear multiple times, but can only appear once per - * certificate.

- * - *

Note: all fields stored in Intel low-byte/high-byte order.

- * - *
- *         Value     Size     Description
- *         -----     ----     -----------
- * (CID)   0x0015    2 bytes  Tag for this "extra" block type
- *         TSize     2 bytes  Size of data that follows
- *         RCount    4 bytes  Number of recipients. (inferred)
- *         HashAlg   2 bytes  Hash algorithm identifier. (inferred)
- *         TData     TSize    Signature Data
- * 
- * - * @NotThreadSafe - * @since 1.11 - */ -public class X0015_CertificateIdForFile extends PKWareExtraHeader { - - public X0015_CertificateIdForFile() { - super(new ZipShort(0x0015)); - } - - private int rcount; - private HashAlgorithm hashAlg; - - /** - * Get record count. - * @return the record count - */ - public int getRecordCount() { - return rcount; - } - - /** - * Get hash algorithm. - * @return the hash algorithm - */ - public HashAlgorithm getHashAlgorithm() { - return hashAlg; - } - - @Override - public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) { - super.parseFromCentralDirectoryData(data, offset, length); - this.rcount = ZipShort.getValue(data, offset); - this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2)); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java b/src/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java deleted file mode 100644 index bab1e616436..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * X.509 Certificate ID and Signature for central directory (0x0016). - * - *

This field contains the information about which certificate in the PKCS#7 - * store was used to sign the central directory structure. When the Central - * Directory Encryption feature is enabled for a ZIP file, this record will - * appear in the Archive Extra Data Record, otherwise it will appear in the - * first central directory record.

- * - *

Note: all fields stored in Intel low-byte/high-byte order.

- * - *
- *         Value     Size     Description
- *         -----     ----     -----------
- * (CDID)  0x0016    2 bytes  Tag for this "extra" block type
- *         TSize     2 bytes  Size of data that follows
- *         RCount    4 bytes  Number of recipients. (inferred)
- *         HashAlg   2 bytes  Hash algorithm identifier. (inferred)
- *         TData     TSize    Data
- * 
- * - * @NotThreadSafe - * @since 1.11 - */ -public class X0016_CertificateIdForCentralDirectory extends PKWareExtraHeader { - - public X0016_CertificateIdForCentralDirectory() { - super(new ZipShort(0x0016)); - } - - private int rcount; - private HashAlgorithm hashAlg; - - /** - * Get record count. - * @return the record count - */ - public int getRecordCount() { - return rcount; - } - - /** - * Get hash algorithm. - * @return the hash algorithm - */ - public HashAlgorithm getHashAlgorithm() { - return hashAlg; - } - - @Override - public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) { - this.rcount = ZipShort.getValue(data, offset); - this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2)); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java b/src/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java deleted file mode 100644 index acc3b22346b..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * Strong Encryption Header (0x0017). - * - *

Certificate-based encryption:

- * - *
- * Value     Size     Description
- * -----     ----     -----------
- * 0x0017    2 bytes  Tag for this "extra" block type
- * TSize     2 bytes  Size of data that follows
- * Format    2 bytes  Format definition for this record
- * AlgID     2 bytes  Encryption algorithm identifier
- * Bitlen    2 bytes  Bit length of encryption key (32-448 bits)
- * Flags     2 bytes  Processing flags
- * RCount    4 bytes  Number of recipients.
- * HashAlg   2 bytes  Hash algorithm identifier
- * HSize     2 bytes  Hash size
- * SRList    (var)    Simple list of recipients hashed public keys
- *
- * Flags -   This defines the processing flags.
- * 
- * - *
    - *
  • 0x0007 - reserved for future use - *
  • 0x000F - reserved for future use - *
  • 0x0100 - Indicates non-OAEP key wrapping was used. If this - * this field is set, the version needed to extract must - * be at least 61. This means OAEP key wrapping is not - * used when generating a Master Session Key using - * ErdData. - *
  • 0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the - * same algorithm used for encrypting the file contents. - *
  • 0x8000 - reserved for future use - *
- * - *
- * RCount - This defines the number intended recipients whose
- *          public keys were used for encryption.  This identifies
- *          the number of elements in the SRList.
- *
- *          see also: reserved1
- *
- * HashAlg - This defines the hash algorithm used to calculate
- *           the public key hash of each public key used
- *           for encryption. This field currently supports
- *           only the following value for SHA-1
- *
- *           0x8004 - SHA1
- *
- * HSize -   This defines the size of a hashed public key.
- *
- * SRList -  This is a variable length list of the hashed
- *           public keys for each intended recipient.  Each
- *           element in this list is HSize.  The total size of
- *           SRList is determined using RCount * HSize.
- * 
- * - *

Password-based Extra Field 0x0017 in central header only.

- * - *
- * Value     Size     Description
- * -----     ----     -----------
- * 0x0017    2 bytes  Tag for this "extra" block type
- * TSize     2 bytes  Size of data that follows
- * Format    2 bytes  Format definition for this record
- * AlgID     2 bytes  Encryption algorithm identifier
- * Bitlen    2 bytes  Bit length of encryption key (32-448 bits)
- * Flags     2 bytes  Processing flags
- * (more?)
- * 
- * - *

Format - the data format identifier for this record. The only value - * allowed at this time is the integer value 2.

- * - *

Password-based Extra Field 0x0017 preceding compressed file data.

- * - *
- * Value     Size     Description
- * -----     ----     -----------
- * 0x0017    2 bytes  Tag for this "extra" block type
- * IVSize    2 bytes  Size of initialization vector (IV)
- * IVData    IVSize   Initialization vector for this file
- * Size      4 bytes  Size of remaining decryption header data
- * Format    2 bytes  Format definition for this record
- * AlgID     2 bytes  Encryption algorithm identifier
- * Bitlen    2 bytes  Bit length of encryption key (32-448 bits)
- * Flags     2 bytes  Processing flags
- * ErdSize   2 bytes  Size of Encrypted Random Data
- * ErdData   ErdSize  Encrypted Random Data
- * Reserved1 4 bytes  Reserved certificate processing data
- * Reserved2 (var)    Reserved for certificate processing data
- * VSize     2 bytes  Size of password validation data
- * VData     VSize-4  Password validation data
- * VCRC32    4 bytes  Standard ZIP CRC32 of password validation data
- *
- * IVData - The size of the IV should match the algorithm block size.
- *          The IVData can be completely random data.  If the size of
- *          the randomly generated data does not match the block size
- *          it should be complemented with zero's or truncated as
- *          necessary.  If IVSize is 0,then IV = CRC32 + Uncompressed
- *          File Size (as a 64 bit little-endian, unsigned integer value).
- *
- * Format -  the data format identifier for this record.  The only
- *           value allowed at this time is the integer value 2.
- *
- * ErdData - Encrypted random data is used to store random data that
- *           is used to generate a file session key for encrypting
- *           each file.  SHA1 is used to calculate hash data used to
- *           derive keys.  File session keys are derived from a master
- *           session key generated from the user-supplied password.
- *           If the Flags field in the decryption header contains
- *           the value 0x4000, then the ErdData field must be
- *           decrypted using 3DES. If the value 0x4000 is not set,
- *           then the ErdData field must be decrypted using AlgId.
- *
- * Reserved1 - Reserved for certificate processing, if value is
- *           zero, then Reserved2 data is absent.  See the explanation
- *           under the Certificate Processing Method for details on
- *           this data structure.
- *
- * Reserved2 - If present, the size of the Reserved2 data structure
- *           is located by skipping the first 4 bytes of this field
- *           and using the next 2 bytes as the remaining size.  See
- *           the explanation under the Certificate Processing Method
- *           for details on this data structure.
- *
- * VSize - This size value will always include the 4 bytes of the
- *         VCRC32 data and will be greater than 4 bytes.
- *
- * VData - Random data for password validation.  This data is VSize
- *         in length and VSize must be a multiple of the encryption
- *         block size.  VCRC32 is a checksum value of VData.
- *         VData and VCRC32 are stored encrypted and start the
- *         stream of encrypted data for a file.
- * 
- * - *

Reserved1 - Certificate Decryption Header Reserved1 Data:

- * - *
- * Value     Size     Description
- * -----     ----     -----------
- * RCount    4 bytes  Number of recipients.
- * 
- * - *

RCount - This defines the number intended recipients whose public keys were - * used for encryption. This defines the number of elements in the REList field - * defined below.

- * - *

Reserved2 - Certificate Decryption Header Reserved2 Data Structures:

- * - *
- * Value     Size     Description
- * -----     ----     -----------
- * HashAlg   2 bytes  Hash algorithm identifier
- * HSize     2 bytes  Hash size
- * REList    (var)    List of recipient data elements
- *
- * HashAlg - This defines the hash algorithm used to calculate
- *           the public key hash of each public key used
- *           for encryption. This field currently supports
- *           only the following value for SHA-1
- *
- *               0x8004 - SHA1
- *
- * HSize -   This defines the size of a hashed public key
- *           defined in REHData.
- *
- * REList -  This is a variable length of list of recipient data.
- *           Each element in this list consists of a Recipient
- *           Element data structure as follows:
- * 
- * - *

Recipient Element (REList) Data Structure:

- * - *
- * Value     Size     Description
- * -----     ----     -----------
- * RESize    2 bytes  Size of REHData + REKData
- * REHData   HSize    Hash of recipients public key
- * REKData   (var)    Simple key blob
- *
- *
- * RESize -  This defines the size of an individual REList
- *           element.  This value is the combined size of the
- *           REHData field + REKData field.  REHData is defined by
- *           HSize.  REKData is variable and can be calculated
- *           for each REList element using RESize and HSize.
- *
- * REHData - Hashed public key for this recipient.
- *
- * REKData - Simple Key Blob.  The format of this data structure
- *           is identical to that defined in the Microsoft
- *           CryptoAPI and generated using the CryptExportKey()
- *           function.  The version of the Simple Key Blob
- *           supported at this time is 0x02 as defined by
- *           Microsoft.
- *
- *           For more details see https://msdn.microsoft.com/en-us/library/aa920051.aspx
- * 
- * - *

Flags - Processing flags needed for decryption

- * - *
    - *
  • 0x0001 - Password is required to decrypt
  • - *
  • 0x0002 - Certificates only
  • - *
  • 0x0003 - Password or certificate required to decrypt
  • - *
  • 0x0007 - reserved for future use - *
  • 0x000F - reserved for future use - *
  • 0x0100 - indicates non-OAEP key wrapping was used. If this field is set - * the version needed to extract must be at least 61. This means OAEP key - * wrapping is not used when generating a Master Session Key using ErdData. - *
  • 0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the same - * algorithm used for encrypting the file contents. - *
  • 0x8000 - reserved for future use. - *
- * - *

See the section describing the Strong Encryption Specification for - * details. Refer to the section in this document entitled - * "Incorporating PKWARE Proprietary Technology into Your Product" for more - * information.

- * - * @NotThreadSafe - * @since 1.11 - */ -public class X0017_StrongEncryptionHeader extends PKWareExtraHeader { - - public X0017_StrongEncryptionHeader() { - super(new ZipShort(0x0017)); - } - - private int format; // TODO written but not read - private EncryptionAlgorithm algId; - private int bitlen; // TODO written but not read - private int flags; // TODO written but not read - private long rcount; - private HashAlgorithm hashAlg; - private int hashSize; - - // encryption data - private byte ivData[]; - private byte erdData[]; - - // encryption key - private byte recipientKeyHash[]; - private byte keyBlob[]; - - // password verification data - private byte vData[]; - private byte vCRC32[]; - - /** - * Get record count. - * @return the record count - */ - public long getRecordCount() { - return rcount; - } - - /** - * Get hash algorithm. - * @return the hash algorithm - */ - public HashAlgorithm getHashAlgorithm() { - return hashAlg; - } - - /** - * Get encryption algorithm. - * @return the encryption algorithm - */ - public EncryptionAlgorithm getEncryptionAlgorithm() { - return algId; - } - - /** - * Parse central directory format. - * - * @param data the buffer to read data from - * @param offset offset into buffer to read data - * @param length the length of data - */ - public void parseCentralDirectoryFormat(final byte[] data, final int offset, final int length) { - this.format = ZipShort.getValue(data, offset); - this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2)); - this.bitlen = ZipShort.getValue(data, offset + 4); - this.flags = ZipShort.getValue(data, offset + 6); - this.rcount = ZipLong.getValue(data, offset + 8); - - if (rcount > 0) { - this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 12)); - this.hashSize = ZipShort.getValue(data, offset + 14); - // srlist... hashed public keys - for (long i = 0; i < this.rcount; i++) { - for (int j = 0; j < this.hashSize; j++) { - // ZipUtil.signedByteToUnsignedInt(data[offset + 16 + (i * this.hashSize) + j])); - } - } - } - } - - /** - * Parse file header format. - * - *

(Password only?)

- * - * @param data the buffer to read data from - * @param offset offset into buffer to read data - * @param length the length of data - */ - public void parseFileFormat(final byte[] data, final int offset, final int length) { - final int ivSize = ZipShort.getValue(data, offset); - this.ivData = new byte[ivSize]; - System.arraycopy(data, offset + 4, this.ivData, 0, ivSize); - - this.format = ZipShort.getValue(data, offset + ivSize + 6); - this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 8)); - this.bitlen = ZipShort.getValue(data, offset + ivSize + 10); - this.flags = ZipShort.getValue(data, offset + ivSize + 12); - - final int erdSize = ZipShort.getValue(data, offset + ivSize + 14); - this.erdData = new byte[erdSize]; - System.arraycopy(data, offset + ivSize + 16, this.erdData, 0, erdSize); - - this.rcount = ZipLong.getValue(data, offset + ivSize + 16 + erdSize); - System.out.println("rcount: " + rcount); - if (rcount == 0) { - final int vSize = ZipShort.getValue(data, offset + ivSize + 20 + erdSize); - this.vData = new byte[vSize - 4]; - this.vCRC32 = new byte[4]; - System.arraycopy(data, offset + ivSize + 22 + erdSize , this.vData, 0, vSize - 4); - System.arraycopy(data, offset + ivSize + 22 + erdSize + vSize - 4, vCRC32, 0, 4); - } else { - this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 20 + erdSize)); - this.hashSize = ZipShort.getValue(data, offset + ivSize + 22 + erdSize); - final int resize = ZipShort.getValue(data, offset + ivSize + 24 + erdSize); - this.recipientKeyHash = new byte[this.hashSize]; - this.keyBlob = new byte[resize - this.hashSize]; - System.arraycopy(data, offset + ivSize + 24 + erdSize, this.recipientKeyHash, 0, this.hashSize); - System.arraycopy(data, offset + ivSize + 24 + erdSize + this.hashSize, this.keyBlob, 0, resize - this.hashSize); - - final int vSize = ZipShort.getValue(data, offset + ivSize + 26 + erdSize + resize); - this.vData = new byte[vSize - 4]; - this.vCRC32 = new byte[4]; - System.arraycopy(data, offset + ivSize + 22 + erdSize + resize, this.vData, 0, vSize - 4); - System.arraycopy(data, offset + ivSize + 22 + erdSize + resize + vSize - 4, vCRC32, 0, 4); - } - - // validate values? - } - - @Override - public void parseFromLocalFileData(final byte[] data, final int offset, final int length) { - super.parseFromLocalFileData(data, offset, length); - parseFileFormat(data, offset, length); - } - - @Override - public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) { - super.parseFromCentralDirectoryData(data, offset, length); - parseCentralDirectoryFormat(data, offset, length); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java b/src/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java deleted file mode 100644 index 825507944f4..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -/** - * PKCS#7 Encryption Recipient Certificate List (0x0019). - * - *

This field MAY contain information about each of the certificates used in - * encryption processing and it can be used to identify who is allowed to - * decrypt encrypted files. This field should only appear in the archive extra - * data record. This field is not required and serves only to aid archive - * modifications by preserving public encryption key data. Individual security - * requirements may dictate that this data be omitted to deter information - * exposure.

- * - *

Note: all fields stored in Intel low-byte/high-byte order.

- * - *
- *          Value     Size     Description
- *          -----     ----     -----------
- * (CStore) 0x0019    2 bytes  Tag for this "extra" block type
- *          TSize     2 bytes  Size of the store data
- *          Version   2 bytes  Format version number - must 0x0001 at this time
- *          CStore    (var)    PKCS#7 data blob
- * 
- * - *

See the section describing the Strong Encryption Specification for - * details. Refer to the section in this document entitled - * "Incorporating PKWARE Proprietary Technology into Your Product" for more - * information.

- * - * @NotThreadSafe - * @since 1.11 - */ -public class X0019_EncryptionRecipientCertificateList extends PKWareExtraHeader { - - public X0019_EncryptionRecipientCertificateList() { - super(new ZipShort(0x0019)); - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java b/src/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java deleted file mode 100644 index 28590c2b2ea..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.Serializable; -import java.util.Date; -import java.util.zip.ZipException; - -/** - *

An extra field that stores additional file and directory timestamp data - * for zip entries. Each zip entry can include up to three timestamps - * (modify, access, create*). The timestamps are stored as 32 bit signed - * integers representing seconds since UNIX epoch (Jan 1st, 1970, UTC). - * This field improves on zip's default timestamp granularity, since it - * allows one to store additional timestamps, and, in addition, the timestamps - * are stored using per-second granularity (zip's default behaviour can only store - * timestamps to the nearest even second). - *

- * Unfortunately, 32 (signed) bits can only store dates up to the year 2037, - * and so this extra field will eventually be obsolete. Enjoy it while it lasts! - *

- *
    - *
  • modifyTime: - * most recent time of file/directory modification - * (or file/dir creation if the entry has not been - * modified since it was created). - *
  • - *
  • accessTime: - * most recent time file/directory was opened - * (e.g., read from disk). Many people disable - * their operating systems from updating this value - * using the NOATIME mount option to optimize disk behaviour, - * and thus it's not always reliable. In those cases - * it's always equal to modifyTime. - *
  • - *
  • *createTime: - * modern linux file systems (e.g., ext2 and newer) - * do not appear to store a value like this, and so - * it's usually omitted altogether in the zip extra - * field. Perhaps other unix systems track this. - *
- *

- * We're using the field definition given in Info-Zip's source archive: - * zip-3.0.tar.gz/proginfo/extrafld.txt - *

- *
- * Value         Size        Description
- * -----         ----        -----------
- * 0x5455        Short       tag for this extra block type ("UT")
- * TSize         Short       total data size for this block
- * Flags         Byte        info bits
- * (ModTime)     Long        time of last modification (UTC/GMT)
- * (AcTime)      Long        time of last access (UTC/GMT)
- * (CrTime)      Long        time of original creation (UTC/GMT)
- *
- * Central-header version:
- *
- * Value         Size        Description
- * -----         ----        -----------
- * 0x5455        Short       tag for this extra block type ("UT")
- * TSize         Short       total data size for this block
- * Flags         Byte        info bits (refers to local header!)
- * (ModTime)     Long        time of last modification (UTC/GMT)
- * 
- * @since 1.5 - */ -public class X5455_ExtendedTimestamp implements ZipExtraField, Cloneable, Serializable { - private static final ZipShort HEADER_ID = new ZipShort(0x5455); - private static final long serialVersionUID = 1L; - - /** - * The bit set inside the flags by when the last modification time - * is present in this extra field. - */ - public static final byte MODIFY_TIME_BIT = 1; - /** - * The bit set inside the flags by when the lasr access time is - * present in this extra field. - */ - public static final byte ACCESS_TIME_BIT = 2; - /** - * The bit set inside the flags by when the original creation time - * is present in this extra field. - */ - public static final byte CREATE_TIME_BIT = 4; - - // The 3 boolean fields (below) come from this flags byte. The remaining 5 bits - // are ignored according to the current version of the spec (December 2012). - private byte flags; - - // Note: even if bit1 and bit2 are set, the Central data will still not contain - // access/create fields: only local data ever holds those! This causes - // some of our implementation to look a little odd, with seemingly spurious - // != null and length checks. - private boolean bit0_modifyTimePresent; - private boolean bit1_accessTimePresent; - private boolean bit2_createTimePresent; - - private ZipLong modifyTime; - private ZipLong accessTime; - private ZipLong createTime; - - /** - * Constructor for X5455_ExtendedTimestamp. - */ - public X5455_ExtendedTimestamp() {} - - /** - * The Header-ID. - * - * @return the value for the header id for this extrafield - */ - @Override - public ZipShort getHeaderId() { - return HEADER_ID; - } - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * - * @return a ZipShort for the length of the data of this extra field - */ - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(1 + - (bit0_modifyTimePresent ? 4 : 0) + - (bit1_accessTimePresent && accessTime != null ? 4 : 0) + - (bit2_createTimePresent && createTime != null ? 4 : 0) - ); - } - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * - *

For X5455 the central length is often smaller than the - * local length, because central cannot contain access or create - * timestamps.

- * - * @return a ZipShort for the length of the data of this extra field - */ - @Override - public ZipShort getCentralDirectoryLength() { - return new ZipShort(1 + - (bit0_modifyTimePresent ? 4 : 0) - ); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return get the data - */ - @Override - public byte[] getLocalFileDataData() { - final byte[] data = new byte[getLocalFileDataLength().getValue()]; - int pos = 0; - data[pos++] = 0; - if (bit0_modifyTimePresent) { - data[0] |= MODIFY_TIME_BIT; - System.arraycopy(modifyTime.getBytes(), 0, data, pos, 4); - pos += 4; - } - if (bit1_accessTimePresent && accessTime != null) { - data[0] |= ACCESS_TIME_BIT; - System.arraycopy(accessTime.getBytes(), 0, data, pos, 4); - pos += 4; - } - if (bit2_createTimePresent && createTime != null) { - data[0] |= CREATE_TIME_BIT; - System.arraycopy(createTime.getBytes(), 0, data, pos, 4); - pos += 4; // NOSONAR - assignment as documentation - } - return data; - } - - /** - * The actual data to put into central directory data - without Header-ID - * or length specifier. - * - * @return the central directory data - */ - @Override - public byte[] getCentralDirectoryData() { - final byte[] centralData = new byte[getCentralDirectoryLength().getValue()]; - final byte[] localData = getLocalFileDataData(); - - // Truncate out create & access time (last 8 bytes) from - // the copy of the local data we obtained: - System.arraycopy(localData, 0, centralData, 0, centralData.length); - return centralData; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param data an array of bytes - * @param offset the start offset - * @param length the number of bytes in the array from offset - * @throws java.util.zip.ZipException on error - */ - @Override - public void parseFromLocalFileData( - final byte[] data, int offset, final int length - ) throws ZipException { - reset(); - final int len = offset + length; - setFlags(data[offset++]); - if (bit0_modifyTimePresent) { - modifyTime = new ZipLong(data, offset); - offset += 4; - } - - // Notice the extra length check in case we are parsing the shorter - // central data field (for both access and create timestamps). - if (bit1_accessTimePresent && offset + 4 <= len) { - accessTime = new ZipLong(data, offset); - offset += 4; - } - if (bit2_createTimePresent && offset + 4 <= len) { - createTime = new ZipLong(data, offset); - offset += 4; // NOSONAR - assignment as documentation - } - } - - /** - * Doesn't do anything special since this class always uses the - * same parsing logic for both central directory and local file data. - */ - @Override - public void parseFromCentralDirectoryData( - final byte[] buffer, final int offset, final int length - ) throws ZipException { - reset(); - parseFromLocalFileData(buffer, offset, length); - } - - /** - * Reset state back to newly constructed state. Helps us make sure - * parse() calls always generate clean results. - */ - private void reset() { - setFlags((byte) 0); - this.modifyTime = null; - this.accessTime = null; - this.createTime = null; - } - - /** - * Sets flags byte. The flags byte tells us which of the - * three datestamp fields are present in the data: - *
-     * bit0 - modify time
-     * bit1 - access time
-     * bit2 - create time
-     * 
- * Only first 3 bits of flags are used according to the - * latest version of the spec (December 2012). - * - * @param flags flags byte indicating which of the - * three datestamp fields are present. - */ - public void setFlags(final byte flags) { - this.flags = flags; - this.bit0_modifyTimePresent = (flags & MODIFY_TIME_BIT) == MODIFY_TIME_BIT; - this.bit1_accessTimePresent = (flags & ACCESS_TIME_BIT) == ACCESS_TIME_BIT; - this.bit2_createTimePresent = (flags & CREATE_TIME_BIT) == CREATE_TIME_BIT; - } - - /** - * Gets flags byte. The flags byte tells us which of the - * three datestamp fields are present in the data: - *
-     * bit0 - modify time
-     * bit1 - access time
-     * bit2 - create time
-     * 
- * Only first 3 bits of flags are used according to the - * latest version of the spec (December 2012). - * - * @return flags byte indicating which of the - * three datestamp fields are present. - */ - public byte getFlags() { return flags; } - - /** - * Returns whether bit0 of the flags byte is set or not, - * which should correspond to the presence or absence of - * a modify timestamp in this particular zip entry. - * - * @return true if bit0 of the flags byte is set. - */ - public boolean isBit0_modifyTimePresent() { return bit0_modifyTimePresent; } - - /** - * Returns whether bit1 of the flags byte is set or not, - * which should correspond to the presence or absence of - * a "last access" timestamp in this particular zip entry. - * - * @return true if bit1 of the flags byte is set. - */ - public boolean isBit1_accessTimePresent() { return bit1_accessTimePresent; } - - /** - * Returns whether bit2 of the flags byte is set or not, - * which should correspond to the presence or absence of - * a create timestamp in this particular zip entry. - * - * @return true if bit2 of the flags byte is set. - */ - public boolean isBit2_createTimePresent() { return bit2_createTimePresent; } - - /** - * Returns the modify time (seconds since epoch) of this zip entry - * as a ZipLong object, or null if no such timestamp exists in the - * zip entry. - * - * @return modify time (seconds since epoch) or null. - */ - public ZipLong getModifyTime() { return modifyTime; } - - /** - * Returns the access time (seconds since epoch) of this zip entry - * as a ZipLong object, or null if no such timestamp exists in the - * zip entry. - * - * @return access time (seconds since epoch) or null. - */ - public ZipLong getAccessTime() { return accessTime; } - - /** - *

- * Returns the create time (seconds since epoch) of this zip entry - * as a ZipLong object, or null if no such timestamp exists in the - * zip entry. - *

- * Note: modern linux file systems (e.g., ext2) - * do not appear to store a "create time" value, and so - * it's usually omitted altogether in the zip extra - * field. Perhaps other unix systems track this. - * - * @return create time (seconds since epoch) or null. - */ - public ZipLong getCreateTime() { return createTime; } - - /** - * Returns the modify time as a java.util.Date - * of this zip entry, or null if no such timestamp exists in the zip entry. - * The milliseconds are always zeroed out, since the underlying data - * offers only per-second precision. - * - * @return modify time as java.util.Date or null. - */ - public Date getModifyJavaTime() { - return zipLongToDate(modifyTime); - } - - /** - * Returns the access time as a java.util.Date - * of this zip entry, or null if no such timestamp exists in the zip entry. - * The milliseconds are always zeroed out, since the underlying data - * offers only per-second precision. - * - * @return access time as java.util.Date or null. - */ - public Date getAccessJavaTime() { - return zipLongToDate(accessTime); - } - - /** - *

- * Returns the create time as a a java.util.Date - * of this zip entry, or null if no such timestamp exists in the zip entry. - * The milliseconds are always zeroed out, since the underlying data - * offers only per-second precision. - *

- * Note: modern linux file systems (e.g., ext2) - * do not appear to store a "create time" value, and so - * it's usually omitted altogether in the zip extra - * field. Perhaps other unix systems track this. - * - * @return create time as java.util.Date or null. - */ - public Date getCreateJavaTime() { - return zipLongToDate(createTime); - } - - /** - *

- * Sets the modify time (seconds since epoch) of this zip entry - * using a ZipLong object. - *

- * Note: the setters for flags and timestamps are decoupled. - * Even if the timestamp is not-null, it will only be written - * out if the corresponding bit in the flags is also set. - *

- * - * @param l ZipLong of the modify time (seconds per epoch) - */ - public void setModifyTime(final ZipLong l) { - bit0_modifyTimePresent = l != null; - flags = (byte) (l != null ? (flags | MODIFY_TIME_BIT) - : (flags & ~MODIFY_TIME_BIT)); - this.modifyTime = l; - } - - /** - *

- * Sets the access time (seconds since epoch) of this zip entry - * using a ZipLong object - *

- * Note: the setters for flags and timestamps are decoupled. - * Even if the timestamp is not-null, it will only be written - * out if the corresponding bit in the flags is also set. - *

- * - * @param l ZipLong of the access time (seconds per epoch) - */ - public void setAccessTime(final ZipLong l) { - bit1_accessTimePresent = l != null; - flags = (byte) (l != null ? (flags | ACCESS_TIME_BIT) - : (flags & ~ACCESS_TIME_BIT)); - this.accessTime = l; - } - - /** - *

- * Sets the create time (seconds since epoch) of this zip entry - * using a ZipLong object - *

- * Note: the setters for flags and timestamps are decoupled. - * Even if the timestamp is not-null, it will only be written - * out if the corresponding bit in the flags is also set. - *

- * - * @param l ZipLong of the create time (seconds per epoch) - */ - public void setCreateTime(final ZipLong l) { - bit2_createTimePresent = l != null; - flags = (byte) (l != null ? (flags | CREATE_TIME_BIT) - : (flags & ~CREATE_TIME_BIT)); - this.createTime = l; - } - - /** - *

- * Sets the modify time as a java.util.Date - * of this zip entry. Supplied value is truncated to per-second - * precision (milliseconds zeroed-out). - *

- * Note: the setters for flags and timestamps are decoupled. - * Even if the timestamp is not-null, it will only be written - * out if the corresponding bit in the flags is also set. - *

- * - * @param d modify time as java.util.Date - */ - public void setModifyJavaTime(final Date d) { setModifyTime(dateToZipLong(d)); } - - /** - *

- * Sets the access time as a java.util.Date - * of this zip entry. Supplied value is truncated to per-second - * precision (milliseconds zeroed-out). - *

- * Note: the setters for flags and timestamps are decoupled. - * Even if the timestamp is not-null, it will only be written - * out if the corresponding bit in the flags is also set. - *

- * - * @param d access time as java.util.Date - */ - public void setAccessJavaTime(final Date d) { setAccessTime(dateToZipLong(d)); } - - /** - *

- * Sets the create time as a java.util.Date - * of this zip entry. Supplied value is truncated to per-second - * precision (milliseconds zeroed-out). - *

- * Note: the setters for flags and timestamps are decoupled. - * Even if the timestamp is not-null, it will only be written - * out if the corresponding bit in the flags is also set. - *

- * - * @param d create time as java.util.Date - */ - public void setCreateJavaTime(final Date d) { setCreateTime(dateToZipLong(d)); } - - /** - * Utility method converts java.util.Date (milliseconds since epoch) - * into a ZipLong (seconds since epoch). - *

- * Also makes sure the converted ZipLong is not too big to fit - * in 32 unsigned bits. - * - * @param d java.util.Date to convert to ZipLong - * @return ZipLong - */ - private static ZipLong dateToZipLong(final Date d) { - if (d == null) { return null; } - - return unixTimeToZipLong(d.getTime() / 1000); - } - - /** - * Returns a String representation of this class useful for - * debugging purposes. - * - * @return A String representation of this class useful for - * debugging purposes. - */ - @Override - public String toString() { - final StringBuilder buf = new StringBuilder(); - buf.append("0x5455 Zip Extra Field: Flags="); - buf.append(Integer.toBinaryString(ZipUtil.unsignedIntToSignedByte(flags))).append(" "); - if (bit0_modifyTimePresent && modifyTime != null) { - final Date m = getModifyJavaTime(); - buf.append(" Modify:[").append(m).append("] "); - } - if (bit1_accessTimePresent && accessTime != null) { - final Date a = getAccessJavaTime(); - buf.append(" Access:[").append(a).append("] "); - } - if (bit2_createTimePresent && createTime != null) { - final Date c = getCreateJavaTime(); - buf.append(" Create:[").append(c).append("] "); - } - return buf.toString(); - } - - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override - public boolean equals(final Object o) { - if (o instanceof X5455_ExtendedTimestamp) { - final X5455_ExtendedTimestamp xf = (X5455_ExtendedTimestamp) o; - - // The ZipLong==ZipLong clauses handle the cases where both are null. - // and only last 3 bits of flags matter. - return ((flags & 0x07) == (xf.flags & 0x07)) && - (modifyTime == xf.modifyTime || (modifyTime != null && modifyTime.equals(xf.modifyTime))) && - (accessTime == xf.accessTime || (accessTime != null && accessTime.equals(xf.accessTime))) && - (createTime == xf.createTime || (createTime != null && createTime.equals(xf.createTime))); - } - return false; - } - - @Override - public int hashCode() { - int hc = (-123 * (flags & 0x07)); // only last 3 bits of flags matter - if (modifyTime != null) { - hc ^= modifyTime.hashCode(); - } - if (accessTime != null) { - // Since accessTime is often same as modifyTime, - // this prevents them from XOR negating each other. - hc ^= Integer.rotateLeft(accessTime.hashCode(), 11); - } - if (createTime != null) { - hc ^= Integer.rotateLeft(createTime.hashCode(), 22); - } - return hc; - } - - private static Date zipLongToDate(ZipLong unixTime) { - return unixTime != null ? new Date(unixTime.getIntValue() * 1000L) : null; - } - - private static ZipLong unixTimeToZipLong(long l) { - if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { - throw new IllegalArgumentException("X5455 timestamps must fit in a signed 32 bit integer: " + l); - } - return new ZipLong(l); - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/X7875_NewUnix.java b/src/org/apache/commons/compress/archivers/zip/X7875_NewUnix.java deleted file mode 100644 index a540dba8a4f..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/X7875_NewUnix.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.Serializable; -import java.math.BigInteger; -import java.util.zip.ZipException; - -import static org.apache.commons.compress.archivers.zip.ZipUtil.reverse; -import static org.apache.commons.compress.archivers.zip.ZipUtil.signedByteToUnsignedInt; -import static org.apache.commons.compress.archivers.zip.ZipUtil.unsignedIntToSignedByte; - -/** - * An extra field that stores UNIX UID/GID data (owner & group ownership) for a given - * zip entry. We're using the field definition given in Info-Zip's source archive: - * zip-3.0.tar.gz/proginfo/extrafld.txt - * - *

- * Local-header version:
- *
- * Value         Size        Description
- * -----         ----        -----------
- * 0x7875        Short       tag for this extra block type ("ux")
- * TSize         Short       total data size for this block
- * Version       1 byte      version of this extra field, currently 1
- * UIDSize       1 byte      Size of UID field
- * UID           Variable    UID for this entry (little endian)
- * GIDSize       1 byte      Size of GID field
- * GID           Variable    GID for this entry (little endian)
- *
- * Central-header version:
- *
- * Value         Size        Description
- * -----         ----        -----------
- * 0x7855        Short       tag for this extra block type ("Ux")
- * TSize         Short       total data size for this block (0)
- * 
- * @since 1.5 - */ -public class X7875_NewUnix implements ZipExtraField, Cloneable, Serializable { - private static final ZipShort HEADER_ID = new ZipShort(0x7875); - private static final ZipShort ZERO = new ZipShort(0); - private static final BigInteger ONE_THOUSAND = BigInteger.valueOf(1000); - private static final long serialVersionUID = 1L; - - private int version = 1; // always '1' according to current info-zip spec. - - // BigInteger helps us with little-endian / big-endian conversions. - // (thanks to BigInteger.toByteArray() and a reverse() method we created). - // Also, the spec theoretically allows UID/GID up to 255 bytes long! - // - // NOTE: equals() and hashCode() currently assume these can never be null. - private BigInteger uid; - private BigInteger gid; - - /** - * Constructor for X7875_NewUnix. - */ - public X7875_NewUnix() { - reset(); - } - - /** - * The Header-ID. - * - * @return the value for the header id for this extrafield - */ - @Override - public ZipShort getHeaderId() { - return HEADER_ID; - } - - /** - * Gets the UID as a long. UID is typically a 32 bit unsigned - * value on most UNIX systems, so we return a long to avoid - * integer overflow into the negatives in case values above - * and including 2^31 are being used. - * - * @return the UID value. - */ - public long getUID() { return ZipUtil.bigToLong(uid); } - - /** - * Gets the GID as a long. GID is typically a 32 bit unsigned - * value on most UNIX systems, so we return a long to avoid - * integer overflow into the negatives in case values above - * and including 2^31 are being used. - * - * @return the GID value. - */ - public long getGID() { return ZipUtil.bigToLong(gid); } - - /** - * Sets the UID. - * - * @param l UID value to set on this extra field. - */ - public void setUID(final long l) { - this.uid = ZipUtil.longToBig(l); - } - - /** - * Sets the GID. - * - * @param l GID value to set on this extra field. - */ - public void setGID(final long l) { - this.gid = ZipUtil.longToBig(l); - } - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * - * @return a ZipShort for the length of the data of this extra field - */ - @Override - public ZipShort getLocalFileDataLength() { - byte[] b = trimLeadingZeroesForceMinLength(uid.toByteArray()); - final int uidSize = b == null ? 0 : b.length; - b = trimLeadingZeroesForceMinLength(gid.toByteArray()); - final int gidSize = b == null ? 0 : b.length; - - // The 3 comes from: version=1 + uidsize=1 + gidsize=1 - return new ZipShort(3 + uidSize + gidSize); - } - - /** - * Length of the extra field in the central directory data - without - * Header-ID or length specifier. - * - * @return a ZipShort for the length of the data of this extra field - */ - @Override - public ZipShort getCentralDirectoryLength() { - return ZERO; - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return get the data - */ - @Override - public byte[] getLocalFileDataData() { - byte[] uidBytes = uid.toByteArray(); - byte[] gidBytes = gid.toByteArray(); - - // BigInteger might prepend a leading-zero to force a positive representation - // (e.g., so that the sign-bit is set to zero). We need to remove that - // before sending the number over the wire. - uidBytes = trimLeadingZeroesForceMinLength(uidBytes); - int uidBytesLen = uidBytes != null ? uidBytes.length : 0; - gidBytes = trimLeadingZeroesForceMinLength(gidBytes); - int gidBytesLen = gidBytes != null ? gidBytes.length : 0; - - // Couldn't bring myself to just call getLocalFileDataLength() when we've - // already got the arrays right here. Yeah, yeah, I know, premature - // optimization is the root of all... - // - // The 3 comes from: version=1 + uidsize=1 + gidsize=1 - final byte[] data = new byte[3 + uidBytesLen + gidBytesLen]; - - // reverse() switches byte array from big-endian to little-endian. - if (uidBytes != null) { - reverse(uidBytes); - } - if (gidBytes != null) { - reverse(gidBytes); - } - - int pos = 0; - data[pos++] = unsignedIntToSignedByte(version); - data[pos++] = unsignedIntToSignedByte(uidBytesLen); - if (uidBytes != null) { - System.arraycopy(uidBytes, 0, data, pos, uidBytesLen); - } - pos += uidBytesLen; - data[pos++] = unsignedIntToSignedByte(gidBytesLen); - if (gidBytes != null) { - System.arraycopy(gidBytes, 0, data, pos, gidBytesLen); - } - return data; - } - - /** - * The actual data to put into central directory data - without Header-ID - * or length specifier. - * - * @return get the data - */ - @Override - public byte[] getCentralDirectoryData() { - return new byte[0]; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param data an array of bytes - * @param offset the start offset - * @param length the number of bytes in the array from offset - * @throws java.util.zip.ZipException on error - */ - @Override - public void parseFromLocalFileData( - final byte[] data, int offset, final int length - ) throws ZipException { - reset(); - this.version = signedByteToUnsignedInt(data[offset++]); - final int uidSize = signedByteToUnsignedInt(data[offset++]); - final byte[] uidBytes = new byte[uidSize]; - System.arraycopy(data, offset, uidBytes, 0, uidSize); - offset += uidSize; - this.uid = new BigInteger(1, reverse(uidBytes)); // sign-bit forced positive - - final int gidSize = signedByteToUnsignedInt(data[offset++]); - final byte[] gidBytes = new byte[gidSize]; - System.arraycopy(data, offset, gidBytes, 0, gidSize); - this.gid = new BigInteger(1, reverse(gidBytes)); // sign-bit forced positive - } - - /** - * Doesn't do anything since this class doesn't store anything - * inside the central directory. - */ - @Override - public void parseFromCentralDirectoryData( - final byte[] buffer, final int offset, final int length - ) throws ZipException { - } - - /** - * Reset state back to newly constructed state. Helps us make sure - * parse() calls always generate clean results. - */ - private void reset() { - // Typical UID/GID of the first non-root user created on a unix system. - uid = ONE_THOUSAND; - gid = ONE_THOUSAND; - } - - /** - * Returns a String representation of this class useful for - * debugging purposes. - * - * @return A String representation of this class useful for - * debugging purposes. - */ - @Override - public String toString() { - return "0x7875 Zip Extra Field: UID=" + uid + " GID=" + gid; - } - - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override - public boolean equals(final Object o) { - if (o instanceof X7875_NewUnix) { - final X7875_NewUnix xf = (X7875_NewUnix) o; - // We assume uid and gid can never be null. - return version == xf.version && uid.equals(xf.uid) && gid.equals(xf.gid); - } - return false; - } - - @Override - public int hashCode() { - int hc = -1234567 * version; - // Since most UID's and GID's are below 65,536, this is (hopefully!) - // a nice way to make sure typical UID and GID values impact the hash - // as much as possible. - hc ^= Integer.rotateLeft(uid.hashCode(), 16); - hc ^= gid.hashCode(); - return hc; - } - - /** - * Not really for external usage, but marked "package" visibility - * to help us JUnit it. Trims a byte array of leading zeroes while - * also enforcing a minimum length, and thus it really trims AND pads - * at the same time. - * - * @param array byte[] array to trim & pad. - * @return trimmed & padded byte[] array. - */ - static byte[] trimLeadingZeroesForceMinLength(final byte[] array) { - if (array == null) { - return array; - } - - int pos = 0; - for (final byte b : array) { - if (b == 0) { - pos++; - } else { - break; - } - } - - /* - - I agonized over my choice of MIN_LENGTH=1. Here's the situation: - InfoZip (the tool I am using to test interop) always sets these - to length=4. And so a UID of 0 (typically root) for example is - encoded as {4,0,0,0,0} (len=4, 32 bits of zero), when it could just - as easily be encoded as {1,0} (len=1, 8 bits of zero) according to - the spec. - - In the end I decided on MIN_LENGTH=1 for four reasons: - - 1.) We are adhering to the spec as far as I can tell, and so - a consumer that cannot parse this is broken. - - 2.) Fundamentally, zip files are about shrinking things, so - let's save a few bytes per entry while we can. - - 3.) Of all the people creating zip files using commons- - compress, how many care about UNIX UID/GID attributes - of the files they store? (e.g., I am probably thinking - way too hard about this and no one cares!) - - 4.) InfoZip's tool, even though it carefully stores every UID/GID - for every file zipped on a unix machine (by default) currently - appears unable to ever restore UID/GID. - unzip -X has no effect on my machine, even when run as root!!!! - - And thus it is decided: MIN_LENGTH=1. - - If anyone runs into interop problems from this, feel free to set - it to MIN_LENGTH=4 at some future time, and then we will behave - exactly like InfoZip (requires changes to unit tests, though). - - And I am sorry that the time you spent reading this comment is now - gone and you can never have it back. - - */ - final int MIN_LENGTH = 1; - - final byte[] trimmedArray = new byte[Math.max(MIN_LENGTH, array.length - pos)]; - final int startPos = trimmedArray.length - (array.length - pos); - System.arraycopy(array, pos, trimmedArray, startPos, trimmedArray.length - startPos); - return trimmedArray; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java b/src/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java deleted file mode 100644 index 0578e584713..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.zip.ZipException; - -import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD; -import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD; - -/** - * Holds size and other extended information for entries that use Zip64 - * features. - * - *

Currently Commons Compress doesn't support encrypting the - * central directory so the note in APPNOTE.TXT about masking doesn't - * apply.

- * - *

The implementation relies on data being read from the local file - * header and assumes that both size values are always present.

- * - * @see PKWARE - * APPNOTE.TXT, section 4.5.3 - * - * @since 1.2 - * @NotThreadSafe - */ -public class Zip64ExtendedInformationExtraField implements ZipExtraField { - - static final ZipShort HEADER_ID = new ZipShort(0x0001); - - private static final String LFH_MUST_HAVE_BOTH_SIZES_MSG = - "Zip64 extended information must contain" - + " both size values in the local file header."; - private static final byte[] EMPTY = new byte[0]; - - private ZipEightByteInteger size, compressedSize, relativeHeaderOffset; - private ZipLong diskStart; - - /** - * Stored in {@link #parseFromCentralDirectoryData - * parseFromCentralDirectoryData} so it can be reused when ZipFile - * calls {@link #reparseCentralDirectoryData - * reparseCentralDirectoryData}. - * - *

Not used for anything else

- * - * @since 1.3 - */ - private byte[] rawCentralDirectoryData; - - /** - * This constructor should only be used by the code that reads - * archives inside of Commons Compress. - */ - public Zip64ExtendedInformationExtraField() { } - - /** - * Creates an extra field based on the original and compressed size. - * - * @param size the entry's original size - * @param compressedSize the entry's compressed size - * - * @throws IllegalArgumentException if size or compressedSize is null - */ - public Zip64ExtendedInformationExtraField(final ZipEightByteInteger size, - final ZipEightByteInteger compressedSize) { - this(size, compressedSize, null, null); - } - - /** - * Creates an extra field based on all four possible values. - * - * @param size the entry's original size - * @param compressedSize the entry's compressed size - * @param relativeHeaderOffset the entry's offset - * @param diskStart the disk start - * - * @throws IllegalArgumentException if size or compressedSize is null - */ - public Zip64ExtendedInformationExtraField(final ZipEightByteInteger size, - final ZipEightByteInteger compressedSize, - final ZipEightByteInteger relativeHeaderOffset, - final ZipLong diskStart) { - this.size = size; - this.compressedSize = compressedSize; - this.relativeHeaderOffset = relativeHeaderOffset; - this.diskStart = diskStart; - } - - @Override - public ZipShort getHeaderId() { - return HEADER_ID; - } - - @Override - public ZipShort getLocalFileDataLength() { - return new ZipShort(size != null ? 2 * DWORD : 0); - } - - @Override - public ZipShort getCentralDirectoryLength() { - return new ZipShort((size != null ? DWORD : 0) - + (compressedSize != null ? DWORD : 0) - + (relativeHeaderOffset != null ? DWORD : 0) - + (diskStart != null ? WORD : 0)); - } - - @Override - public byte[] getLocalFileDataData() { - if (size != null || compressedSize != null) { - if (size == null || compressedSize == null) { - throw new IllegalArgumentException(LFH_MUST_HAVE_BOTH_SIZES_MSG); - } - final byte[] data = new byte[2 * DWORD]; - addSizes(data); - return data; - } - return EMPTY; - } - - @Override - public byte[] getCentralDirectoryData() { - final byte[] data = new byte[getCentralDirectoryLength().getValue()]; - int off = addSizes(data); - if (relativeHeaderOffset != null) { - System.arraycopy(relativeHeaderOffset.getBytes(), 0, data, off, DWORD); - off += DWORD; - } - if (diskStart != null) { - System.arraycopy(diskStart.getBytes(), 0, data, off, WORD); - off += WORD; // NOSONAR - assignment as documentation - } - return data; - } - - @Override - public void parseFromLocalFileData(final byte[] buffer, int offset, final int length) - throws ZipException { - if (length == 0) { - // no local file data at all, may happen if an archive - // only holds a ZIP64 extended information extra field - // inside the central directory but not inside the local - // file header - return; - } - if (length < 2 * DWORD) { - throw new ZipException(LFH_MUST_HAVE_BOTH_SIZES_MSG); - } - size = new ZipEightByteInteger(buffer, offset); - offset += DWORD; - compressedSize = new ZipEightByteInteger(buffer, offset); - offset += DWORD; - int remaining = length - 2 * DWORD; - if (remaining >= DWORD) { - relativeHeaderOffset = new ZipEightByteInteger(buffer, offset); - offset += DWORD; - remaining -= DWORD; - } - if (remaining >= WORD) { - diskStart = new ZipLong(buffer, offset); - offset += WORD; // NOSONAR - assignment as documentation - remaining -= WORD; // NOSONAR - assignment as documentation - } - } - - @Override - public void parseFromCentralDirectoryData(final byte[] buffer, int offset, - final int length) - throws ZipException { - // store for processing in reparseCentralDirectoryData - rawCentralDirectoryData = new byte[length]; - System.arraycopy(buffer, offset, rawCentralDirectoryData, 0, length); - - // if there is no size information in here, we are screwed and - // can only hope things will get resolved by LFH data later - // But there are some cases that can be detected - // * all data is there - // * length == 24 -> both sizes and offset - // * length % 8 == 4 -> at least we can identify the diskStart field - if (length >= 3 * DWORD + WORD) { - parseFromLocalFileData(buffer, offset, length); - } else if (length == 3 * DWORD) { - size = new ZipEightByteInteger(buffer, offset); - offset += DWORD; - compressedSize = new ZipEightByteInteger(buffer, offset); - offset += DWORD; - relativeHeaderOffset = new ZipEightByteInteger(buffer, offset); - } else if (length % DWORD == WORD) { - diskStart = new ZipLong(buffer, offset + length - WORD); - } - } - - /** - * Parses the raw bytes read from the central directory extra - * field with knowledge which fields are expected to be there. - * - *

All four fields inside the zip64 extended information extra - * field are optional and must only be present if their corresponding - * entry inside the central directory contains the correct magic - * value.

- * - * @param hasUncompressedSize flag to read from central directory - * @param hasCompressedSize flag to read from central directory - * @param hasRelativeHeaderOffset flag to read from central directory - * @param hasDiskStart flag to read from central directory - * @throws ZipException on error - */ - public void reparseCentralDirectoryData(final boolean hasUncompressedSize, - final boolean hasCompressedSize, - final boolean hasRelativeHeaderOffset, - final boolean hasDiskStart) - throws ZipException { - if (rawCentralDirectoryData != null) { - final int expectedLength = (hasUncompressedSize ? DWORD : 0) - + (hasCompressedSize ? DWORD : 0) - + (hasRelativeHeaderOffset ? DWORD : 0) - + (hasDiskStart ? WORD : 0); - if (rawCentralDirectoryData.length < expectedLength) { - throw new ZipException("central directory zip64 extended" - + " information extra field's length" - + " doesn't match central directory" - + " data. Expected length " - + expectedLength + " but is " - + rawCentralDirectoryData.length); - } - int offset = 0; - if (hasUncompressedSize) { - size = new ZipEightByteInteger(rawCentralDirectoryData, offset); - offset += DWORD; - } - if (hasCompressedSize) { - compressedSize = new ZipEightByteInteger(rawCentralDirectoryData, - offset); - offset += DWORD; - } - if (hasRelativeHeaderOffset) { - relativeHeaderOffset = - new ZipEightByteInteger(rawCentralDirectoryData, offset); - offset += DWORD; - } - if (hasDiskStart) { - diskStart = new ZipLong(rawCentralDirectoryData, offset); - offset += WORD; // NOSONAR - assignment as documentation - } - } - } - - /** - * The uncompressed size stored in this extra field. - * @return The uncompressed size stored in this extra field. - */ - public ZipEightByteInteger getSize() { - return size; - } - - /** - * The uncompressed size stored in this extra field. - * @param size The uncompressed size stored in this extra field. - */ - public void setSize(final ZipEightByteInteger size) { - this.size = size; - } - - /** - * The compressed size stored in this extra field. - * @return The compressed size stored in this extra field. - */ - public ZipEightByteInteger getCompressedSize() { - return compressedSize; - } - - /** - * The uncompressed size stored in this extra field. - * @param compressedSize The uncompressed size stored in this extra field. - */ - public void setCompressedSize(final ZipEightByteInteger compressedSize) { - this.compressedSize = compressedSize; - } - - /** - * The relative header offset stored in this extra field. - * @return The relative header offset stored in this extra field. - */ - public ZipEightByteInteger getRelativeHeaderOffset() { - return relativeHeaderOffset; - } - - /** - * The relative header offset stored in this extra field. - * @param rho The relative header offset stored in this extra field. - */ - public void setRelativeHeaderOffset(final ZipEightByteInteger rho) { - relativeHeaderOffset = rho; - } - - /** - * The disk start number stored in this extra field. - * @return The disk start number stored in this extra field. - */ - public ZipLong getDiskStartNumber() { - return diskStart; - } - - /** - * The disk start number stored in this extra field. - * @param ds The disk start number stored in this extra field. - */ - public void setDiskStartNumber(final ZipLong ds) { - diskStart = ds; - } - - private int addSizes(final byte[] data) { - int off = 0; - if (size != null) { - System.arraycopy(size.getBytes(), 0, data, 0, DWORD); - off += DWORD; - } - if (compressedSize != null) { - System.arraycopy(compressedSize.getBytes(), 0, data, off, DWORD); - off += DWORD; - } - return off; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/Zip64Mode.java b/src/org/apache/commons/compress/archivers/zip/Zip64Mode.java deleted file mode 100644 index d051e898294..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/Zip64Mode.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -/** - * The different modes {@link ZipArchiveOutputStream} can operate in. - * - * @see ZipArchiveOutputStream#setUseZip64 - * - * @since 1.3 - */ -public enum Zip64Mode { - /** - * Use Zip64 extensions for all entries, even if it is clear it is - * not required. - */ - Always, - /** - * Don't use Zip64 extensions for any entries. - * - *

This will cause a {@link Zip64RequiredException} to be - * thrown if {@link ZipArchiveOutputStream} detects it needs Zip64 - * support.

- */ - Never, - /** - * Use Zip64 extensions for all entries where they are required, - * don't use them for entries that clearly don't require them. - */ - AsNeeded -} diff --git a/src/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java b/src/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java deleted file mode 100644 index 1ec7e70b844..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -import java.util.zip.ZipException; - -/** - * Exception thrown when attempting to write data that requires Zip64 - * support to an archive and {@link ZipArchiveOutputStream#setUseZip64 - * UseZip64} has been set to {@link Zip64Mode#Never Never}. - * @since 1.3 - */ -public class Zip64RequiredException extends ZipException { - - private static final long serialVersionUID = 20110809L; - - /** - * Helper to format "entry too big" messages. - */ - static String getEntryTooBigMessage(final ZipArchiveEntry ze) { - return ze.getName() + "'s size exceeds the limit of 4GByte."; - } - - static final String ARCHIVE_TOO_BIG_MESSAGE = - "archive's size exceeds the limit of 4GByte."; - - static final String TOO_MANY_ENTRIES_MESSAGE = - "archive contains more than 65535 entries."; - - public Zip64RequiredException(final String reason) { - super(reason); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java b/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java deleted file mode 100644 index 4a09eac4f8c..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.EntryStreamOffsets; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.zip.ZipException; - -/** - * Extension that adds better handling of extra fields and provides - * access to the internal and external file attributes. - * - *

The extra data is expected to follow the recommendation of - * APPNOTE.TXT:

- *
    - *
  • the extra byte array consists of a sequence of extra fields
  • - *
  • each extra fields starts by a two byte header id followed by - * a two byte sequence holding the length of the remainder of - * data.
  • - *
- * - *

Any extra data that cannot be parsed by the rules above will be - * consumed as "unparseable" extra data and treated differently by the - * methods of this class. Versions prior to Apache Commons Compress - * 1.1 would have thrown an exception if any attempt was made to read - * or write extra data not conforming to the recommendation.

- * - * @NotThreadSafe - */ -public class ZipArchiveEntry extends java.util.zip.ZipEntry - implements ArchiveEntry, EntryStreamOffsets -{ - - public static final int PLATFORM_UNIX = 3; - public static final int PLATFORM_FAT = 0; - public static final int CRC_UNKNOWN = -1; - private static final int SHORT_MASK = 0xFFFF; - private static final int SHORT_SHIFT = 16; - private static final byte[] EMPTY = new byte[0]; - - /** - * Indicates how the name of this entry has been determined. - * @since 1.16 - */ - public enum NameSource { - /** - * The name has been read from the archive using the encoding - * of the archive specified when creating the {@link - * ZipArchiveInputStream} or {@link ZipFile} (defaults to the - * platform's default encoding). - */ - NAME, - /** - * The name has been read from the archive and the archive - * specified the EFS flag which indicates the name has been - * encoded as UTF-8. - */ - NAME_WITH_EFS_FLAG, - /** - * The name has been read from an {@link UnicodePathExtraField - * Unicode Extra Field}. - */ - UNICODE_EXTRA_FIELD - } - - /** - * Indicates how the comment of this entry has been determined. - * @since 1.16 - */ - public enum CommentSource { - /** - * The comment has been read from the archive using the encoding - * of the archive specified when creating the {@link - * ZipArchiveInputStream} or {@link ZipFile} (defaults to the - * platform's default encoding). - */ - COMMENT, - /** - * The comment has been read from an {@link UnicodeCommentExtraField - * Unicode Extra Field}. - */ - UNICODE_EXTRA_FIELD - } - - /** - * The {@link java.util.zip.ZipEntry} base class only supports - * the compression methods STORED and DEFLATED. We override the - * field so that any compression methods can be used. - *

- * The default value -1 means that the method has not been specified. - * - * @see COMPRESS-93 - */ - private int method = ZipMethod.UNKNOWN_CODE; - - /** - * The {@link java.util.zip.ZipEntry#setSize} method in the base - * class throws an IllegalArgumentException if the size is bigger - * than 2GB for Java versions < 7 and even in Java 7+ if the - * implementation in java.util.zip doesn't support Zip64 itself - * (it is an optional feature). - * - *

We need to keep our own size information for Zip64 support.

- */ - private long size = SIZE_UNKNOWN; - - private int internalAttributes = 0; - private int versionRequired; - private int versionMadeBy; - private int platform = PLATFORM_FAT; - private int rawFlag; - private long externalAttributes = 0; - private int alignment = 0; - private ZipExtraField[] extraFields; - private UnparseableExtraFieldData unparseableExtra = null; - private String name = null; - private byte[] rawName = null; - private GeneralPurposeBit gpb = new GeneralPurposeBit(); - private static final ZipExtraField[] noExtraFields = new ZipExtraField[0]; - private long localHeaderOffset = OFFSET_UNKNOWN; - private long dataOffset = OFFSET_UNKNOWN; - private boolean isStreamContiguous = false; - private NameSource nameSource = NameSource.NAME; - private CommentSource commentSource = CommentSource.COMMENT; - - - /** - * Creates a new zip entry with the specified name. - * - *

Assumes the entry represents a directory if and only if the - * name ends with a forward slash "/".

- * - * @param name the name of the entry - */ - public ZipArchiveEntry(final String name) { - super(name); - setName(name); - } - - /** - * Creates a new zip entry with fields taken from the specified zip entry. - * - *

Assumes the entry represents a directory if and only if the - * name ends with a forward slash "/".

- * - * @param entry the entry to get fields from - * @throws ZipException on error - */ - public ZipArchiveEntry(final java.util.zip.ZipEntry entry) throws ZipException { - super(entry); - setName(entry.getName()); - final byte[] extra = entry.getExtra(); - if (extra != null) { - setExtraFields(ExtraFieldUtils.parse(extra, true, - ExtraFieldUtils - .UnparseableExtraField.READ)); - } else { - // initializes extra data to an empty byte array - setExtra(); - } - setMethod(entry.getMethod()); - this.size = entry.getSize(); - } - - /** - * Creates a new zip entry with fields taken from the specified zip entry. - * - *

Assumes the entry represents a directory if and only if the - * name ends with a forward slash "/".

- * - * @param entry the entry to get fields from - * @throws ZipException on error - */ - public ZipArchiveEntry(final ZipArchiveEntry entry) throws ZipException { - this((java.util.zip.ZipEntry) entry); - setInternalAttributes(entry.getInternalAttributes()); - setExternalAttributes(entry.getExternalAttributes()); - setExtraFields(getAllExtraFieldsNoCopy()); - setPlatform(entry.getPlatform()); - final GeneralPurposeBit other = entry.getGeneralPurposeBit(); - setGeneralPurposeBit(other == null ? null : - (GeneralPurposeBit) other.clone()); - } - - /** - */ - protected ZipArchiveEntry() { - this(""); - } - - /** - * Creates a new zip entry taking some information from the given - * file and using the provided name. - * - *

The name will be adjusted to end with a forward slash "/" if - * the file is a directory. If the file is not a directory a - * potential trailing forward slash will be stripped from the - * entry name.

- * @param inputFile file to create the entry from - * @param entryName name of the entry - */ - public ZipArchiveEntry(final File inputFile, final String entryName) { - this(inputFile.isDirectory() && !entryName.endsWith("/") ? - entryName + "/" : entryName); - if (inputFile.isFile()){ - setSize(inputFile.length()); - } - setTime(inputFile.lastModified()); - // TODO are there any other fields we can set here? - } - - /** - * Overwrite clone. - * @return a cloned copy of this ZipArchiveEntry - */ - @Override - public Object clone() { - final ZipArchiveEntry e = (ZipArchiveEntry) super.clone(); - - e.setInternalAttributes(getInternalAttributes()); - e.setExternalAttributes(getExternalAttributes()); - e.setExtraFields(getAllExtraFieldsNoCopy()); - return e; - } - - /** - * Returns the compression method of this entry, or -1 if the - * compression method has not been specified. - * - * @return compression method - * - * @since 1.1 - */ - @Override - public int getMethod() { - return method; - } - - /** - * Sets the compression method of this entry. - * - * @param method compression method - * - * @since 1.1 - */ - @Override - public void setMethod(final int method) { - if (method < 0) { - throw new IllegalArgumentException( - "ZIP compression method can not be negative: " + method); - } - this.method = method; - } - - /** - * Retrieves the internal file attributes. - * - *

Note: {@link ZipArchiveInputStream} is unable to fill - * this field, you must use {@link ZipFile} if you want to read - * entries using this attribute.

- * - * @return the internal file attributes - */ - public int getInternalAttributes() { - return internalAttributes; - } - - /** - * Sets the internal file attributes. - * @param value an int value - */ - public void setInternalAttributes(final int value) { - internalAttributes = value; - } - - /** - * Retrieves the external file attributes. - * - *

Note: {@link ZipArchiveInputStream} is unable to fill - * this field, you must use {@link ZipFile} if you want to read - * entries using this attribute.

- * - * @return the external file attributes - */ - public long getExternalAttributes() { - return externalAttributes; - } - - /** - * Sets the external file attributes. - * @param value an long value - */ - public void setExternalAttributes(final long value) { - externalAttributes = value; - } - - /** - * Sets Unix permissions in a way that is understood by Info-Zip's - * unzip command. - * @param mode an int value - */ - public void setUnixMode(final int mode) { - // CheckStyle:MagicNumberCheck OFF - no point - setExternalAttributes((mode << SHORT_SHIFT) - // MS-DOS read-only attribute - | ((mode & 0200) == 0 ? 1 : 0) - // MS-DOS directory flag - | (isDirectory() ? 0x10 : 0)); - // CheckStyle:MagicNumberCheck ON - platform = PLATFORM_UNIX; - } - - /** - * Unix permission. - * @return the unix permissions - */ - public int getUnixMode() { - return platform != PLATFORM_UNIX ? 0 : - (int) ((getExternalAttributes() >> SHORT_SHIFT) & SHORT_MASK); - } - - /** - * Returns true if this entry represents a unix symlink, - * in which case the entry's content contains the target path - * for the symlink. - * - * @since 1.5 - * @return true if the entry represents a unix symlink, false otherwise. - */ - public boolean isUnixSymlink() { - return (getUnixMode() & UnixStat.FILE_TYPE_FLAG) == UnixStat.LINK_FLAG; - } - - /** - * Platform specification to put into the "version made - * by" part of the central file header. - * - * @return PLATFORM_FAT unless {@link #setUnixMode setUnixMode} - * has been called, in which case PLATFORM_UNIX will be returned. - */ - public int getPlatform() { - return platform; - } - - /** - * Set the platform (UNIX or FAT). - * @param platform an int value - 0 is FAT, 3 is UNIX - */ - protected void setPlatform(final int platform) { - this.platform = platform; - } - - /** - * Gets currently configured alignment. - * - * @return - * alignment for this entry. - * @since 1.14 - */ - protected int getAlignment() { - return this.alignment; - } - - /** - * Sets alignment for this entry. - * - * @param alignment - * requested alignment, 0 for default. - * @since 1.14 - */ - public void setAlignment(int alignment) { - if ((alignment & (alignment - 1)) != 0 || alignment > 0xffff) { - throw new IllegalArgumentException("Invalid value for alignment, must be power of two and no bigger than " - + 0xffff + " but is " + alignment); - } - this.alignment = alignment; - } - - /** - * Replaces all currently attached extra fields with the new array. - * @param fields an array of extra fields - */ - public void setExtraFields(final ZipExtraField[] fields) { - final List newFields = new ArrayList<>(); - for (final ZipExtraField field : fields) { - if (field instanceof UnparseableExtraFieldData) { - unparseableExtra = (UnparseableExtraFieldData) field; - } else { - newFields.add( field); - } - } - extraFields = newFields.toArray(new ZipExtraField[newFields.size()]); - setExtra(); - } - - /** - * Retrieves all extra fields that have been parsed successfully. - * - *

Note: The set of extra fields may be incomplete when - * {@link ZipArchiveInputStream} has been used as some extra - * fields use the central directory to store additional - * information.

- * - * @return an array of the extra fields - */ - public ZipExtraField[] getExtraFields() { - return getParseableExtraFields(); - } - - /** - * Retrieves extra fields. - * @param includeUnparseable whether to also return unparseable - * extra fields as {@link UnparseableExtraFieldData} if such data - * exists. - * @return an array of the extra fields - * - * @since 1.1 - */ - public ZipExtraField[] getExtraFields(final boolean includeUnparseable) { - return includeUnparseable ? - getAllExtraFields() : - getParseableExtraFields(); - } - - private ZipExtraField[] getParseableExtraFieldsNoCopy() { - if (extraFields == null) { - return noExtraFields; - } - return extraFields; - } - - private ZipExtraField[] getParseableExtraFields() { - final ZipExtraField[] parseableExtraFields = getParseableExtraFieldsNoCopy(); - return (parseableExtraFields == extraFields) ? copyOf(parseableExtraFields) : parseableExtraFields; - } - - /** - * Get all extra fields, including unparseable ones. - * @return An array of all extra fields. Not necessarily a copy of internal data structures, hence private method - */ - private ZipExtraField[] getAllExtraFieldsNoCopy() { - if (extraFields == null) { - return getUnparseableOnly(); - } - return unparseableExtra != null ? getMergedFields() : extraFields; - } - - private ZipExtraField[] copyOf(final ZipExtraField[] src){ - return copyOf(src, src.length); - } - - private ZipExtraField[] copyOf(final ZipExtraField[] src, final int length) { - final ZipExtraField[] cpy = new ZipExtraField[length]; - System.arraycopy(src, 0, cpy, 0, Math.min(src.length, length)); - return cpy; - } - - private ZipExtraField[] getMergedFields() { - final ZipExtraField[] zipExtraFields = copyOf(extraFields, extraFields.length + 1); - zipExtraFields[extraFields.length] = unparseableExtra; - return zipExtraFields; - } - - private ZipExtraField[] getUnparseableOnly() { - return unparseableExtra == null ? noExtraFields : new ZipExtraField[] { unparseableExtra }; - } - - private ZipExtraField[] getAllExtraFields() { - final ZipExtraField[] allExtraFieldsNoCopy = getAllExtraFieldsNoCopy(); - return (allExtraFieldsNoCopy == extraFields) ? copyOf( allExtraFieldsNoCopy) : allExtraFieldsNoCopy; - } - /** - * Adds an extra field - replacing an already present extra field - * of the same type. - * - *

If no extra field of the same type exists, the field will be - * added as last field.

- * @param ze an extra field - */ - public void addExtraField(final ZipExtraField ze) { - if (ze instanceof UnparseableExtraFieldData) { - unparseableExtra = (UnparseableExtraFieldData) ze; - } else { - if (extraFields == null) { - extraFields = new ZipExtraField[]{ ze}; - } else { - if (getExtraField(ze.getHeaderId())!= null){ - removeExtraField(ze.getHeaderId()); - } - final ZipExtraField[] zipExtraFields = copyOf(extraFields, extraFields.length + 1); - zipExtraFields[zipExtraFields.length -1] = ze; - extraFields = zipExtraFields; - } - } - setExtra(); - } - - /** - * Adds an extra field - replacing an already present extra field - * of the same type. - * - *

The new extra field will be the first one.

- * @param ze an extra field - */ - public void addAsFirstExtraField(final ZipExtraField ze) { - if (ze instanceof UnparseableExtraFieldData) { - unparseableExtra = (UnparseableExtraFieldData) ze; - } else { - if (getExtraField(ze.getHeaderId()) != null){ - removeExtraField(ze.getHeaderId()); - } - final ZipExtraField[] copy = extraFields; - final int newLen = extraFields != null ? extraFields.length + 1: 1; - extraFields = new ZipExtraField[newLen]; - extraFields[0] = ze; - if (copy != null){ - System.arraycopy(copy, 0, extraFields, 1, extraFields.length - 1); - } - } - setExtra(); - } - - /** - * Remove an extra field. - * @param type the type of extra field to remove - */ - public void removeExtraField(final ZipShort type) { - if (extraFields == null) { - throw new java.util.NoSuchElementException(); - } - - final List newResult = new ArrayList<>(); - for (final ZipExtraField extraField : extraFields) { - if (!type.equals(extraField.getHeaderId())){ - newResult.add( extraField); - } - } - if (extraFields.length == newResult.size()) { - throw new java.util.NoSuchElementException(); - } - extraFields = newResult.toArray(new ZipExtraField[newResult.size()]); - setExtra(); - } - - /** - * Removes unparseable extra field data. - * - * @since 1.1 - */ - public void removeUnparseableExtraFieldData() { - if (unparseableExtra == null) { - throw new java.util.NoSuchElementException(); - } - unparseableExtra = null; - setExtra(); - } - - /** - * Looks up an extra field by its header id. - * - * @param type the header id - * @return null if no such field exists. - */ - public ZipExtraField getExtraField(final ZipShort type) { - if (extraFields != null) { - for (final ZipExtraField extraField : extraFields) { - if (type.equals(extraField.getHeaderId())) { - return extraField; - } - } - } - return null; - } - - /** - * Looks up extra field data that couldn't be parsed correctly. - * - * @return null if no such field exists. - * - * @since 1.1 - */ - public UnparseableExtraFieldData getUnparseableExtraFieldData() { - return unparseableExtra; - } - - /** - * Parses the given bytes as extra field data and consumes any - * unparseable data as an {@link UnparseableExtraFieldData} - * instance. - * @param extra an array of bytes to be parsed into extra fields - * @throws RuntimeException if the bytes cannot be parsed - * @throws RuntimeException on error - */ - @Override - public void setExtra(final byte[] extra) throws RuntimeException { - try { - final ZipExtraField[] local = - ExtraFieldUtils.parse(extra, true, - ExtraFieldUtils.UnparseableExtraField.READ); - mergeExtraFields(local, true); - } catch (final ZipException e) { - // actually this is not possible as of Commons Compress 1.1 - throw new RuntimeException("Error parsing extra fields for entry: " //NOSONAR - + getName() + " - " + e.getMessage(), e); - } - } - - /** - * Unfortunately {@link java.util.zip.ZipOutputStream - * java.util.zip.ZipOutputStream} seems to access the extra data - * directly, so overriding getExtra doesn't help - we need to - * modify super's data directly. - */ - protected void setExtra() { - super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getAllExtraFieldsNoCopy())); - } - - /** - * Sets the central directory part of extra fields. - * @param b an array of bytes to be parsed into extra fields - */ - public void setCentralDirectoryExtra(final byte[] b) { - try { - final ZipExtraField[] central = - ExtraFieldUtils.parse(b, false, - ExtraFieldUtils.UnparseableExtraField.READ); - mergeExtraFields(central, false); - } catch (final ZipException e) { - throw new RuntimeException(e.getMessage(), e); //NOSONAR - } - } - - /** - * Retrieves the extra data for the local file data. - * @return the extra data for local file - */ - public byte[] getLocalFileDataExtra() { - final byte[] extra = getExtra(); - return extra != null ? extra : EMPTY; - } - - /** - * Retrieves the extra data for the central directory. - * @return the central directory extra data - */ - public byte[] getCentralDirectoryExtra() { - return ExtraFieldUtils.mergeCentralDirectoryData(getAllExtraFieldsNoCopy()); - } - - /** - * Get the name of the entry. - * - *

This method returns the raw name as it is stored inside of the archive.

- * - * @return the entry name - */ - @Override - public String getName() { - return name == null ? super.getName() : name; - } - - /** - * Is this entry a directory? - * @return true if the entry is a directory - */ - @Override - public boolean isDirectory() { - return getName().endsWith("/"); - } - - /** - * Set the name of the entry. - * @param name the name to use - */ - protected void setName(String name) { - if (name != null && getPlatform() == PLATFORM_FAT - && !name.contains("/")) { - name = name.replace('\\', '/'); - } - this.name = name; - } - - /** - * Gets the uncompressed size of the entry data. - * - *

Note: {@link ZipArchiveInputStream} may create - * entries that return {@link #SIZE_UNKNOWN SIZE_UNKNOWN} as long - * as the entry hasn't been read completely.

- * - * @return the entry size - */ - @Override - public long getSize() { - return size; - } - - /** - * Sets the uncompressed size of the entry data. - * @param size the uncompressed size in bytes - * @throws IllegalArgumentException if the specified size is less - * than 0 - */ - @Override - public void setSize(final long size) { - if (size < 0) { - throw new IllegalArgumentException("invalid entry size"); - } - this.size = size; - } - - /** - * Sets the name using the raw bytes and the string created from - * it by guessing or using the configured encoding. - * @param name the name to use created from the raw bytes using - * the guessed or configured encoding - * @param rawName the bytes originally read as name from the - * archive - * @since 1.2 - */ - protected void setName(final String name, final byte[] rawName) { - setName(name); - this.rawName = rawName; - } - - /** - * Returns the raw bytes that made up the name before it has been - * converted using the configured or guessed encoding. - * - *

This method will return null if this instance has not been - * read from an archive.

- * - * @return the raw name bytes - * @since 1.2 - */ - public byte[] getRawName() { - if (rawName != null) { - final byte[] b = new byte[rawName.length]; - System.arraycopy(rawName, 0, b, 0, rawName.length); - return b; - } - return null; - } - - protected long getLocalHeaderOffset() { - return this.localHeaderOffset; - } - - protected void setLocalHeaderOffset(long localHeaderOffset) { - this.localHeaderOffset = localHeaderOffset; - } - - @Override - public long getDataOffset() { - return dataOffset; - } - - /** - * Sets the data offset. - * - * @param dataOffset - * new value of data offset. - */ - protected void setDataOffset(long dataOffset) { - this.dataOffset = dataOffset; - } - - @Override - public boolean isStreamContiguous() { - return isStreamContiguous; - } - - protected void setStreamContiguous(boolean isStreamContiguous) { - this.isStreamContiguous = isStreamContiguous; - } - - /** - * Get the hashCode of the entry. - * This uses the name as the hashcode. - * @return a hashcode. - */ - @Override - public int hashCode() { - // this method has severe consequences on performance. We cannot rely - // on the super.hashCode() method since super.getName() always return - // the empty string in the current implemention (there's no setter) - // so it is basically draining the performance of a hashmap lookup - return getName().hashCode(); - } - - /** - * The "general purpose bit" field. - * @return the general purpose bit - * @since 1.1 - */ - public GeneralPurposeBit getGeneralPurposeBit() { - return gpb; - } - - /** - * The "general purpose bit" field. - * @param b the general purpose bit - * @since 1.1 - */ - public void setGeneralPurposeBit(final GeneralPurposeBit b) { - gpb = b; - } - - /** - * If there are no extra fields, use the given fields as new extra - * data - otherwise merge the fields assuming the existing fields - * and the new fields stem from different locations inside the - * archive. - * @param f the extra fields to merge - * @param local whether the new fields originate from local data - */ - private void mergeExtraFields(final ZipExtraField[] f, final boolean local) - throws ZipException { - if (extraFields == null) { - setExtraFields(f); - } else { - for (final ZipExtraField element : f) { - ZipExtraField existing; - if (element instanceof UnparseableExtraFieldData) { - existing = unparseableExtra; - } else { - existing = getExtraField(element.getHeaderId()); - } - if (existing == null) { - addExtraField(element); - } else { - if (local) { - final byte[] b = element.getLocalFileDataData(); - existing.parseFromLocalFileData(b, 0, b.length); - } else { - final byte[] b = element.getCentralDirectoryData(); - existing.parseFromCentralDirectoryData(b, 0, b.length); - } - } - } - setExtra(); - } - } - - /** - * Wraps {@link java.util.zip.ZipEntry#getTime} with a {@link Date} as the - * entry's last modified date. - * - *

Changes to the implementation of {@link java.util.zip.ZipEntry#getTime} - * leak through and the returned value may depend on your local - * time zone as well as your version of Java.

- */ - @Override - public Date getLastModifiedDate() { - return new Date(getTime()); - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final ZipArchiveEntry other = (ZipArchiveEntry) obj; - final String myName = getName(); - final String otherName = other.getName(); - if (myName == null) { - if (otherName != null) { - return false; - } - } else if (!myName.equals(otherName)) { - return false; - } - String myComment = getComment(); - String otherComment = other.getComment(); - if (myComment == null) { - myComment = ""; - } - if (otherComment == null) { - otherComment = ""; - } - return getTime() == other.getTime() - && myComment.equals(otherComment) - && getInternalAttributes() == other.getInternalAttributes() - && getPlatform() == other.getPlatform() - && getExternalAttributes() == other.getExternalAttributes() - && getMethod() == other.getMethod() - && getSize() == other.getSize() - && getCrc() == other.getCrc() - && getCompressedSize() == other.getCompressedSize() - && Arrays.equals(getCentralDirectoryExtra(), - other.getCentralDirectoryExtra()) - && Arrays.equals(getLocalFileDataExtra(), - other.getLocalFileDataExtra()) - && localHeaderOffset == other.localHeaderOffset - && dataOffset == other.dataOffset - && gpb.equals(other.gpb); - } - - /** - * Sets the "version made by" field. - * @param versionMadeBy "version made by" field - * @since 1.11 - */ - public void setVersionMadeBy(final int versionMadeBy) { - this.versionMadeBy = versionMadeBy; - } - - /** - * Sets the "version required to expand" field. - * @param versionRequired "version required to expand" field - * @since 1.11 - */ - public void setVersionRequired(final int versionRequired) { - this.versionRequired = versionRequired; - } - - /** - * The "version required to expand" field. - * @return "version required to expand" field - * @since 1.11 - */ - public int getVersionRequired() { - return versionRequired; - } - - /** - * The "version made by" field. - * @return "version made by" field - * @since 1.11 - */ - public int getVersionMadeBy() { - return versionMadeBy; - } - - /** - * The content of the flags field. - * @return content of the flags field - * @since 1.11 - */ - public int getRawFlag() { - return rawFlag; - } - - /** - * Sets the content of the flags field. - * @param rawFlag content of the flags field - * @since 1.11 - */ - public void setRawFlag(final int rawFlag) { - this.rawFlag = rawFlag; - } - - /** - * The source of the name field value. - * @return source of the name field value - * @since 1.16 - */ - public NameSource getNameSource() { - return nameSource; - } - - /** - * Sets the source of the name field value. - * @param nameSource source of the name field value - * @since 1.16 - */ - public void setNameSource(NameSource nameSource) { - this.nameSource = nameSource; - } - - /** - * The source of the comment field value. - * @return source of the comment field value - * @since 1.16 - */ - public CommentSource getCommentSource() { - return commentSource; - } - - /** - * Sets the source of the comment field value. - * @param commentSource source of the comment field value - * @since 1.16 - */ - public void setCommentSource(CommentSource commentSource) { - this.commentSource = commentSource; - } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java b/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java deleted file mode 100644 index e7122b9a6ce..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryPredicate.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -/** - * A predicate to test if a #ZipArchiveEntry matches a criteria. - * Some day this can extend java.util.function.Predicate - * - * @since 1.10 - */ -public interface ZipArchiveEntryPredicate { - /** - * Indicate if the given entry should be included in the operation - * @param zipArchiveEntry the entry to test - * @return true if the entry should be included - */ - boolean test(ZipArchiveEntry zipArchiveEntry); -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest.java b/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest.java deleted file mode 100644 index 9c13f7e2786..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.parallel.InputStreamSupplier; - -import java.io.InputStream; - -/** - * A Thread-safe representation of a ZipArchiveEntry that is used to add entries to parallel archives. - * - * @since 1.10 - */ -public class ZipArchiveEntryRequest { - /* - The zipArchiveEntry is not thread safe, and cannot be safely accessed by the getters of this class. - It is safely accessible during the construction part of this class and also after the - thread pools have been shut down. - */ - private final ZipArchiveEntry zipArchiveEntry; - private final InputStreamSupplier payloadSupplier; - private final int method; - - - private ZipArchiveEntryRequest(final ZipArchiveEntry zipArchiveEntry, final InputStreamSupplier payloadSupplier) { - // this constructor has "safe" access to all member variables on zipArchiveEntry - this.zipArchiveEntry = zipArchiveEntry; - this.payloadSupplier = payloadSupplier; - this.method = zipArchiveEntry.getMethod(); - } - - /** - * Create a ZipArchiveEntryRequest - * @param zipArchiveEntry The entry to use - * @param payloadSupplier The payload that will be added to the zip entry. - * @return The newly created request - */ - public static ZipArchiveEntryRequest createZipArchiveEntryRequest(final ZipArchiveEntry zipArchiveEntry, final InputStreamSupplier payloadSupplier) { - return new ZipArchiveEntryRequest(zipArchiveEntry, payloadSupplier); - } - - /** - * The paylaod that will be added to this zip entry - * @return The input stream. - */ - public InputStream getPayloadStream() { - return payloadSupplier.get(); - } - - /** - * The compression method to use - * @return The compression method to use - */ - public int getMethod(){ - return method; - } - - - /** - * Gets the underlying entry. Do not use this methods from threads that did not create the instance itself ! - * @return the zipeArchiveEntry that is basis for this request - */ - ZipArchiveEntry getZipArchiveEntry() { - return zipArchiveEntry; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier.java b/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier.java deleted file mode 100644 index c6ac957afaa..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -/** - * Supplies {@link ZipArchiveEntryRequest}. - * - * Implementations are required to support thread-handover. While an instance will - * not be accessed concurrently by multiple threads, it will be called by - * a different thread than it was created on. - * - * @since 1.13 - */ -public interface ZipArchiveEntryRequestSupplier { - - /** - * Supply a {@link ZipArchiveEntryRequest} to be added to a parallel archive. - * @return The {@link ZipArchiveEntryRequest} instance. Should never be null. - */ - ZipArchiveEntryRequest get(); -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java b/src/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java deleted file mode 100644 index 729d92e5deb..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java +++ /dev/null @@ -1,1214 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.nio.ByteBuffer; -import java.util.zip.CRC32; -import java.util.zip.DataFormatException; -import java.util.zip.Inflater; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; -import org.apache.commons.compress.compressors.deflate64.Deflate64CompressorInputStream; -import org.apache.commons.compress.utils.ArchiveUtils; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD; -import static org.apache.commons.compress.archivers.zip.ZipConstants.SHORT; -import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD; -import static org.apache.commons.compress.archivers.zip.ZipConstants.ZIP64_MAGIC; - -/** - * Implements an input stream that can read Zip archives. - * - *

As of Apache Commons Compress it transparently supports Zip64 - * extensions and thus individual entries and archives larger than 4 - * GB or with more than 65536 entries.

- * - *

The {@link ZipFile} class is preferred when reading from files - * as {@link ZipArchiveInputStream} is limited by not being able to - * read the central directory header before returning entries. In - * particular {@link ZipArchiveInputStream}

- * - *
    - * - *
  • may return entries that are not part of the central directory - * at all and shouldn't be considered part of the archive.
  • - * - *
  • may return several entries with the same name.
  • - * - *
  • will not return internal or external attributes.
  • - * - *
  • may return incomplete extra field data.
  • - * - *
  • may return unknown sizes and CRC values for entries until the - * next entry has been reached if the archive uses the data - * descriptor feature.
  • - * - *
- * - * @see ZipFile - * @NotThreadSafe - */ -public class ZipArchiveInputStream extends ArchiveInputStream implements InputStreamStatistics { - - /** The zip encoding to use for filenames and the file comment. */ - private final ZipEncoding zipEncoding; - - // the provided encoding (for unit tests) - final String encoding; - - /** Whether to look for and use Unicode extra fields. */ - private final boolean useUnicodeExtraFields; - - /** Wrapped stream, will always be a PushbackInputStream. */ - private final InputStream in; - - /** Inflater used for all deflated entries. */ - private final Inflater inf = new Inflater(true); - - /** Buffer used to read from the wrapped stream. */ - private final ByteBuffer buf = ByteBuffer.allocate(ZipArchiveOutputStream.BUFFER_SIZE); - - /** The entry that is currently being read. */ - private CurrentEntry current = null; - - /** Whether the stream has been closed. */ - private boolean closed = false; - - /** Whether the stream has reached the central directory - and thus found all entries. */ - private boolean hitCentralDirectory = false; - - /** - * When reading a stored entry that uses the data descriptor this - * stream has to read the full entry and caches it. This is the - * cache. - */ - private ByteArrayInputStream lastStoredEntry = null; - - /** Whether the stream will try to read STORED entries that use a data descriptor. */ - private boolean allowStoredEntriesWithDataDescriptor = false; - - /** Count decompressed bytes for current entry */ - private long uncompressedCount = 0; - - private static final int LFH_LEN = 30; - /* - local file header signature WORD - version needed to extract SHORT - general purpose bit flag SHORT - compression method SHORT - last mod file time SHORT - last mod file date SHORT - crc-32 WORD - compressed size WORD - uncompressed size WORD - file name length SHORT - extra field length SHORT - */ - - private static final int CFH_LEN = 46; - /* - central file header signature WORD - version made by SHORT - version needed to extract SHORT - general purpose bit flag SHORT - compression method SHORT - last mod file time SHORT - last mod file date SHORT - crc-32 WORD - compressed size WORD - uncompressed size WORD - file name length SHORT - extra field length SHORT - file comment length SHORT - disk number start SHORT - internal file attributes SHORT - external file attributes WORD - relative offset of local header WORD - */ - - private static final long TWO_EXP_32 = ZIP64_MAGIC + 1; - - // cached buffers - must only be used locally in the class (COMPRESS-172 - reduce garbage collection) - private final byte[] lfhBuf = new byte[LFH_LEN]; - private final byte[] skipBuf = new byte[1024]; - private final byte[] shortBuf = new byte[SHORT]; - private final byte[] wordBuf = new byte[WORD]; - private final byte[] twoDwordBuf = new byte[2 * DWORD]; - - private int entriesRead = 0; - - /** - * Create an instance using UTF-8 encoding - * @param inputStream the stream to wrap - */ - public ZipArchiveInputStream(final InputStream inputStream) { - this(inputStream, ZipEncodingHelper.UTF8); - } - - /** - * Create an instance using the specified encoding - * @param inputStream the stream to wrap - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @since 1.5 - */ - public ZipArchiveInputStream(final InputStream inputStream, final String encoding) { - this(inputStream, encoding, true); - } - - /** - * Create an instance using the specified encoding - * @param inputStream the stream to wrap - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. - */ - public ZipArchiveInputStream(final InputStream inputStream, final String encoding, final boolean useUnicodeExtraFields) { - this(inputStream, encoding, useUnicodeExtraFields, false); - } - - /** - * Create an instance using the specified encoding - * @param inputStream the stream to wrap - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. - * @param allowStoredEntriesWithDataDescriptor whether the stream - * will try to read STORED entries that use a data descriptor - * @since 1.1 - */ - public ZipArchiveInputStream(final InputStream inputStream, - final String encoding, - final boolean useUnicodeExtraFields, - final boolean allowStoredEntriesWithDataDescriptor) { - this.encoding = encoding; - zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - this.useUnicodeExtraFields = useUnicodeExtraFields; - in = new PushbackInputStream(inputStream, buf.capacity()); - this.allowStoredEntriesWithDataDescriptor = - allowStoredEntriesWithDataDescriptor; - // haven't read anything so far - buf.limit(0); - } - - public ZipArchiveEntry getNextZipEntry() throws IOException { - uncompressedCount = 0; - - boolean firstEntry = true; - if (closed || hitCentralDirectory) { - return null; - } - if (current != null) { - closeEntry(); - firstEntry = false; - } - - long currentHeaderOffset = getBytesRead(); - try { - if (firstEntry) { - // split archives have a special signature before the - // first local file header - look for it and fail with - // the appropriate error message if this is a split - // archive. - readFirstLocalFileHeader(lfhBuf); - } else { - readFully(lfhBuf); - } - } catch (final EOFException e) { - return null; - } - - final ZipLong sig = new ZipLong(lfhBuf); - if (sig.equals(ZipLong.CFH_SIG) || sig.equals(ZipLong.AED_SIG)) { - hitCentralDirectory = true; - skipRemainderOfArchive(); - return null; - } - if (!sig.equals(ZipLong.LFH_SIG)) { - throw new ZipException(String.format("Unexpected record signature: 0X%X", sig.getValue())); - } - - int off = WORD; - current = new CurrentEntry(); - - final int versionMadeBy = ZipShort.getValue(lfhBuf, off); - off += SHORT; - current.entry.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK); - - final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(lfhBuf, off); - final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames(); - final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; - current.hasDataDescriptor = gpFlag.usesDataDescriptor(); - current.entry.setGeneralPurposeBit(gpFlag); - - off += SHORT; - - current.entry.setMethod(ZipShort.getValue(lfhBuf, off)); - off += SHORT; - - final long time = ZipUtil.dosToJavaTime(ZipLong.getValue(lfhBuf, off)); - current.entry.setTime(time); - off += WORD; - - ZipLong size = null, cSize = null; - if (!current.hasDataDescriptor) { - current.entry.setCrc(ZipLong.getValue(lfhBuf, off)); - off += WORD; - - cSize = new ZipLong(lfhBuf, off); - off += WORD; - - size = new ZipLong(lfhBuf, off); - off += WORD; - } else { - off += 3 * WORD; - } - - final int fileNameLen = ZipShort.getValue(lfhBuf, off); - - off += SHORT; - - final int extraLen = ZipShort.getValue(lfhBuf, off); - off += SHORT; // NOSONAR - assignment as documentation - - final byte[] fileName = new byte[fileNameLen]; - readFully(fileName); - current.entry.setName(entryEncoding.decode(fileName), fileName); - if (hasUTF8Flag) { - current.entry.setNameSource(ZipArchiveEntry.NameSource.NAME_WITH_EFS_FLAG); - } - - final byte[] extraData = new byte[extraLen]; - readFully(extraData); - current.entry.setExtra(extraData); - - if (!hasUTF8Flag && useUnicodeExtraFields) { - ZipUtil.setNameAndCommentFromExtraFields(current.entry, fileName, null); - } - - processZip64Extra(size, cSize); - - current.entry.setLocalHeaderOffset(currentHeaderOffset); - current.entry.setDataOffset(getBytesRead()); - current.entry.setStreamContiguous(true); - - ZipMethod m = ZipMethod.getMethodByCode(current.entry.getMethod()); - if (current.entry.getCompressedSize() != ArchiveEntry.SIZE_UNKNOWN) { - if (ZipUtil.canHandleEntryData(current.entry) && m != ZipMethod.STORED && m != ZipMethod.DEFLATED) { - InputStream bis = new BoundedInputStream(in, current.entry.getCompressedSize()); - switch (m) { - case UNSHRINKING: - current.in = new UnshrinkingInputStream(bis); - break; - case IMPLODING: - current.in = new ExplodingInputStream( - current.entry.getGeneralPurposeBit().getSlidingDictionarySize(), - current.entry.getGeneralPurposeBit().getNumberOfShannonFanoTrees(), - bis); - break; - case BZIP2: - current.in = new BZip2CompressorInputStream(bis); - break; - case ENHANCED_DEFLATED: - current.in = new Deflate64CompressorInputStream(bis); - break; - default: - // we should never get here as all supported methods have been covered - // will cause an error when read is invoked, don't throw an exception here so people can - // skip unsupported entries - break; - } - } - } else if (m == ZipMethod.ENHANCED_DEFLATED) { - current.in = new Deflate64CompressorInputStream(in); - } - - entriesRead++; - return current.entry; - } - - /** - * Fills the given array with the first local file header and - * deals with splitting/spanning markers that may prefix the first - * LFH. - */ - private void readFirstLocalFileHeader(final byte[] lfh) throws IOException { - readFully(lfh); - final ZipLong sig = new ZipLong(lfh); - if (sig.equals(ZipLong.DD_SIG)) { - throw new UnsupportedZipFeatureException(UnsupportedZipFeatureException.Feature.SPLITTING); - } - - if (sig.equals(ZipLong.SINGLE_SEGMENT_SPLIT_MARKER)) { - // The archive is not really split as only one segment was - // needed in the end. Just skip over the marker. - final byte[] missedLfhBytes = new byte[4]; - readFully(missedLfhBytes); - System.arraycopy(lfh, 4, lfh, 0, LFH_LEN - 4); - System.arraycopy(missedLfhBytes, 0, lfh, LFH_LEN - 4, 4); - } - } - - /** - * Records whether a Zip64 extra is present and sets the size - * information from it if sizes are 0xFFFFFFFF and the entry - * doesn't use a data descriptor. - */ - private void processZip64Extra(final ZipLong size, final ZipLong cSize) { - final Zip64ExtendedInformationExtraField z64 = - (Zip64ExtendedInformationExtraField) - current.entry.getExtraField(Zip64ExtendedInformationExtraField.HEADER_ID); - current.usesZip64 = z64 != null; - if (!current.hasDataDescriptor) { - if (z64 != null // same as current.usesZip64 but avoids NPE warning - && (cSize.equals(ZipLong.ZIP64_MAGIC) || size.equals(ZipLong.ZIP64_MAGIC)) ) { - current.entry.setCompressedSize(z64.getCompressedSize().getLongValue()); - current.entry.setSize(z64.getSize().getLongValue()); - } else { - current.entry.setCompressedSize(cSize.getValue()); - current.entry.setSize(size.getValue()); - } - } - } - - @Override - public ArchiveEntry getNextEntry() throws IOException { - return getNextZipEntry(); - } - - /** - * Whether this class is able to read the given entry. - * - *

May return false if it is set up to use encryption or a - * compression method that hasn't been implemented yet.

- * @since 1.1 - */ - @Override - public boolean canReadEntryData(final ArchiveEntry ae) { - if (ae instanceof ZipArchiveEntry) { - final ZipArchiveEntry ze = (ZipArchiveEntry) ae; - return ZipUtil.canHandleEntryData(ze) - && supportsDataDescriptorFor(ze) - && supportsCompressedSizeFor(ze); - } - return false; - } - - @Override - public int read(final byte[] buffer, final int offset, final int length) throws IOException { - if (closed) { - throw new IOException("The stream is closed"); - } - - if (current == null) { - return -1; - } - - // avoid int overflow, check null buffer - if (offset > buffer.length || length < 0 || offset < 0 || buffer.length - offset < length) { - throw new ArrayIndexOutOfBoundsException(); - } - - ZipUtil.checkRequestedFeatures(current.entry); - if (!supportsDataDescriptorFor(current.entry)) { - throw new UnsupportedZipFeatureException(UnsupportedZipFeatureException.Feature.DATA_DESCRIPTOR, - current.entry); - } - if (!supportsCompressedSizeFor(current.entry)) { - throw new UnsupportedZipFeatureException(UnsupportedZipFeatureException.Feature.UNKNOWN_COMPRESSED_SIZE, - current.entry); - } - - int read; - if (current.entry.getMethod() == ZipArchiveOutputStream.STORED) { - read = readStored(buffer, offset, length); - } else if (current.entry.getMethod() == ZipArchiveOutputStream.DEFLATED) { - read = readDeflated(buffer, offset, length); - } else if (current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode() - || current.entry.getMethod() == ZipMethod.IMPLODING.getCode() - || current.entry.getMethod() == ZipMethod.ENHANCED_DEFLATED.getCode() - || current.entry.getMethod() == ZipMethod.BZIP2.getCode()) { - read = current.in.read(buffer, offset, length); - } else { - throw new UnsupportedZipFeatureException(ZipMethod.getMethodByCode(current.entry.getMethod()), - current.entry); - } - - if (read >= 0) { - current.crc.update(buffer, offset, read); - uncompressedCount += read; - } - - return read; - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - if (current.entry.getMethod() == ZipArchiveOutputStream.STORED) { - return current.bytesRead; - } else if (current.entry.getMethod() == ZipArchiveOutputStream.DEFLATED) { - return getBytesInflated(); - } else if (current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()) { - return ((UnshrinkingInputStream) current.in).getCompressedCount(); - } else if (current.entry.getMethod() == ZipMethod.IMPLODING.getCode()) { - return ((ExplodingInputStream) current.in).getCompressedCount(); - } else if (current.entry.getMethod() == ZipMethod.ENHANCED_DEFLATED.getCode()) { - return ((Deflate64CompressorInputStream) current.in).getCompressedCount(); - } else if (current.entry.getMethod() == ZipMethod.BZIP2.getCode()) { - return ((BZip2CompressorInputStream) current.in).getCompressedCount(); - } else { - return -1; - } - } - - /** - * @since 1.17 - */ - @Override - public long getUncompressedCount() { - return uncompressedCount; - } - - /** - * Implementation of read for STORED entries. - */ - private int readStored(final byte[] buffer, final int offset, final int length) throws IOException { - - if (current.hasDataDescriptor) { - if (lastStoredEntry == null) { - readStoredEntry(); - } - return lastStoredEntry.read(buffer, offset, length); - } - - final long csize = current.entry.getSize(); - if (current.bytesRead >= csize) { - return -1; - } - - if (buf.position() >= buf.limit()) { - buf.position(0); - final int l = in.read(buf.array()); - if (l == -1) { - return -1; - } - buf.limit(l); - - count(l); - current.bytesReadFromStream += l; - } - - int toRead = Math.min(buf.remaining(), length); - if ((csize - current.bytesRead) < toRead) { - // if it is smaller than toRead then it fits into an int - toRead = (int) (csize - current.bytesRead); - } - buf.get(buffer, offset, toRead); - current.bytesRead += toRead; - return toRead; - } - - /** - * Implementation of read for DEFLATED entries. - */ - private int readDeflated(final byte[] buffer, final int offset, final int length) throws IOException { - final int read = readFromInflater(buffer, offset, length); - if (read <= 0) { - if (inf.finished()) { - return -1; - } else if (inf.needsDictionary()) { - throw new ZipException("This archive needs a preset dictionary" - + " which is not supported by Commons" - + " Compress."); - } else if (read == -1) { - throw new IOException("Truncated ZIP file"); - } - } - return read; - } - - /** - * Potentially reads more bytes to fill the inflater's buffer and - * reads from it. - */ - private int readFromInflater(final byte[] buffer, final int offset, final int length) throws IOException { - int read = 0; - do { - if (inf.needsInput()) { - final int l = fill(); - if (l > 0) { - current.bytesReadFromStream += buf.limit(); - } else if (l == -1) { - return -1; - } else { - break; - } - } - try { - read = inf.inflate(buffer, offset, length); - } catch (final DataFormatException e) { - throw (IOException) new ZipException(e.getMessage()).initCause(e); - } - } while (read == 0 && inf.needsInput()); - return read; - } - - @Override - public void close() throws IOException { - if (!closed) { - closed = true; - try { - in.close(); - } finally { - inf.end(); - } - } - } - - /** - * Skips over and discards value bytes of data from this input - * stream. - * - *

This implementation may end up skipping over some smaller - * number of bytes, possibly 0, if and only if it reaches the end - * of the underlying stream.

- * - *

The actual number of bytes skipped is returned.

- * - * @param value the number of bytes to be skipped. - * @return the actual number of bytes skipped. - * @throws IOException - if an I/O error occurs. - * @throws IllegalArgumentException - if value is negative. - */ - @Override - public long skip(final long value) throws IOException { - if (value >= 0) { - long skipped = 0; - while (skipped < value) { - final long rem = value - skipped; - final int x = read(skipBuf, 0, (int) (skipBuf.length > rem ? rem : skipBuf.length)); - if (x == -1) { - return skipped; - } - skipped += x; - } - return skipped; - } - throw new IllegalArgumentException(); - } - - /** - * Checks if the signature matches what is expected for a zip file. - * Does not currently handle self-extracting zips which may have arbitrary - * leading content. - * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true, if this stream is a zip archive stream, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < ZipArchiveOutputStream.LFH_SIG.length) { - return false; - } - - return checksig(signature, ZipArchiveOutputStream.LFH_SIG) // normal file - || checksig(signature, ZipArchiveOutputStream.EOCD_SIG) // empty zip - || checksig(signature, ZipArchiveOutputStream.DD_SIG) // split zip - || checksig(signature, ZipLong.SINGLE_SEGMENT_SPLIT_MARKER.getBytes()); - } - - private static boolean checksig(final byte[] signature, final byte[] expected) { - for (int i = 0; i < expected.length; i++) { - if (signature[i] != expected[i]) { - return false; - } - } - return true; - } - - /** - * Closes the current ZIP archive entry and positions the underlying - * stream to the beginning of the next entry. All per-entry variables - * and data structures are cleared. - *

- * If the compressed size of this entry is included in the entry header, - * then any outstanding bytes are simply skipped from the underlying - * stream without uncompressing them. This allows an entry to be safely - * closed even if the compression method is unsupported. - *

- * In case we don't know the compressed size of this entry or have - * already buffered too much data from the underlying stream to support - * uncompression, then the uncompression process is completed and the - * end position of the stream is adjusted based on the result of that - * process. - * - * @throws IOException if an error occurs - */ - private void closeEntry() throws IOException { - if (closed) { - throw new IOException("The stream is closed"); - } - if (current == null) { - return; - } - - // Ensure all entry bytes are read - if (currentEntryHasOutstandingBytes()) { - drainCurrentEntryData(); - } else { - // this is guaranteed to exhaust the stream - skip(Long.MAX_VALUE); //NOSONAR - - final long inB = current.entry.getMethod() == ZipArchiveOutputStream.DEFLATED - ? getBytesInflated() : current.bytesRead; - - // this is at most a single read() operation and can't - // exceed the range of int - final int diff = (int) (current.bytesReadFromStream - inB); - - // Pushback any required bytes - if (diff > 0) { - pushback(buf.array(), buf.limit() - diff, diff); - current.bytesReadFromStream -= diff; - } - - // Drain remainder of entry if not all data bytes were required - if (currentEntryHasOutstandingBytes()) { - drainCurrentEntryData(); - } - } - - if (lastStoredEntry == null && current.hasDataDescriptor) { - readDataDescriptor(); - } - - inf.reset(); - buf.clear().flip(); - current = null; - lastStoredEntry = null; - } - - /** - * If the compressed size of the current entry is included in the entry header - * and there are any outstanding bytes in the underlying stream, then - * this returns true. - * - * @return true, if current entry is determined to have outstanding bytes, false otherwise - */ - private boolean currentEntryHasOutstandingBytes() { - return current.bytesReadFromStream <= current.entry.getCompressedSize() - && !current.hasDataDescriptor; - } - - /** - * Read all data of the current entry from the underlying stream - * that hasn't been read, yet. - */ - private void drainCurrentEntryData() throws IOException { - long remaining = current.entry.getCompressedSize() - current.bytesReadFromStream; - while (remaining > 0) { - final long n = in.read(buf.array(), 0, (int) Math.min(buf.capacity(), remaining)); - if (n < 0) { - throw new EOFException("Truncated ZIP entry: " - + ArchiveUtils.sanitize(current.entry.getName())); - } - count(n); - remaining -= n; - } - } - - /** - * Get the number of bytes Inflater has actually processed. - * - *

for Java < Java7 the getBytes* methods in - * Inflater/Deflater seem to return unsigned ints rather than - * longs that start over with 0 at 2^32.

- * - *

The stream knows how many bytes it has read, but not how - * many the Inflater actually consumed - it should be between the - * total number of bytes read for the entry and the total number - * minus the last read operation. Here we just try to make the - * value close enough to the bytes we've read by assuming the - * number of bytes consumed must be smaller than (or equal to) the - * number of bytes read but not smaller by more than 2^32.

- */ - private long getBytesInflated() { - long inB = inf.getBytesRead(); - if (current.bytesReadFromStream >= TWO_EXP_32) { - while (inB + TWO_EXP_32 <= current.bytesReadFromStream) { - inB += TWO_EXP_32; - } - } - return inB; - } - - private int fill() throws IOException { - if (closed) { - throw new IOException("The stream is closed"); - } - final int length = in.read(buf.array()); - if (length > 0) { - buf.limit(length); - count(buf.limit()); - inf.setInput(buf.array(), 0, buf.limit()); - } - return length; - } - - private void readFully(final byte[] b) throws IOException { - final int count = IOUtils.readFully(in, b); - count(count); - if (count < b.length) { - throw new EOFException(); - } - } - - private void readDataDescriptor() throws IOException { - readFully(wordBuf); - ZipLong val = new ZipLong(wordBuf); - if (ZipLong.DD_SIG.equals(val)) { - // data descriptor with signature, skip sig - readFully(wordBuf); - val = new ZipLong(wordBuf); - } - current.entry.setCrc(val.getValue()); - - // if there is a ZIP64 extra field, sizes are eight bytes - // each, otherwise four bytes each. Unfortunately some - // implementations - namely Java7 - use eight bytes without - // using a ZIP64 extra field - - // https://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7073588 - - // just read 16 bytes and check whether bytes nine to twelve - // look like one of the signatures of what could follow a data - // descriptor (ignoring archive decryption headers for now). - // If so, push back eight bytes and assume sizes are four - // bytes, otherwise sizes are eight bytes each. - readFully(twoDwordBuf); - final ZipLong potentialSig = new ZipLong(twoDwordBuf, DWORD); - if (potentialSig.equals(ZipLong.CFH_SIG) || potentialSig.equals(ZipLong.LFH_SIG)) { - pushback(twoDwordBuf, DWORD, DWORD); - current.entry.setCompressedSize(ZipLong.getValue(twoDwordBuf)); - current.entry.setSize(ZipLong.getValue(twoDwordBuf, WORD)); - } else { - current.entry.setCompressedSize(ZipEightByteInteger.getLongValue(twoDwordBuf)); - current.entry.setSize(ZipEightByteInteger.getLongValue(twoDwordBuf, DWORD)); - } - } - - /** - * Whether this entry requires a data descriptor this library can work with. - * - * @return true if allowStoredEntriesWithDataDescriptor is true, - * the entry doesn't require any data descriptor or the method is - * DEFLATED or ENHANCED_DEFLATED. - */ - private boolean supportsDataDescriptorFor(final ZipArchiveEntry entry) { - return !entry.getGeneralPurposeBit().usesDataDescriptor() - - || (allowStoredEntriesWithDataDescriptor && entry.getMethod() == ZipEntry.STORED) - || entry.getMethod() == ZipEntry.DEFLATED - || entry.getMethod() == ZipMethod.ENHANCED_DEFLATED.getCode(); - } - - /** - * Whether the compressed size for the entry is either known or - * not required by the compression method being used. - */ - private boolean supportsCompressedSizeFor(final ZipArchiveEntry entry) { - return entry.getCompressedSize() != ArchiveEntry.SIZE_UNKNOWN - || entry.getMethod() == ZipEntry.DEFLATED - || entry.getMethod() == ZipMethod.ENHANCED_DEFLATED.getCode() - || (entry.getGeneralPurposeBit().usesDataDescriptor() - && allowStoredEntriesWithDataDescriptor - && entry.getMethod() == ZipEntry.STORED); - } - - /** - * Caches a stored entry that uses the data descriptor. - * - *
    - *
  • Reads a stored entry until the signature of a local file - * header, central directory header or data descriptor has been - * found.
  • - *
  • Stores all entry data in lastStoredEntry.

    - *
  • Rewinds the stream to position at the data - * descriptor.
  • - *
  • reads the data descriptor
  • - *
- * - *

After calling this method the entry should know its size, - * the entry's data is cached and the stream is positioned at the - * next local file or central directory header.

- */ - private void readStoredEntry() throws IOException { - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - int off = 0; - boolean done = false; - - // length of DD without signature - final int ddLen = current.usesZip64 ? WORD + 2 * DWORD : 3 * WORD; - - while (!done) { - final int r = in.read(buf.array(), off, ZipArchiveOutputStream.BUFFER_SIZE - off); - if (r <= 0) { - // read the whole archive without ever finding a - // central directory - throw new IOException("Truncated ZIP file"); - } - if (r + off < 4) { - // buffer too small to check for a signature, loop - off += r; - continue; - } - - done = bufferContainsSignature(bos, off, r, ddLen); - if (!done) { - off = cacheBytesRead(bos, off, r, ddLen); - } - } - - final byte[] b = bos.toByteArray(); - lastStoredEntry = new ByteArrayInputStream(b); - } - - private static final byte[] LFH = ZipLong.LFH_SIG.getBytes(); - private static final byte[] CFH = ZipLong.CFH_SIG.getBytes(); - private static final byte[] DD = ZipLong.DD_SIG.getBytes(); - - /** - * Checks whether the current buffer contains the signature of a - * "data descriptor", "local file header" or - * "central directory entry". - * - *

If it contains such a signature, reads the data descriptor - * and positions the stream right after the data descriptor.

- */ - private boolean bufferContainsSignature(final ByteArrayOutputStream bos, final int offset, final int lastRead, final int expectedDDLen) - throws IOException { - - boolean done = false; - int readTooMuch = 0; - for (int i = 0; !done && i < offset + lastRead - 4; i++) { - if (buf.array()[i] == LFH[0] && buf.array()[i + 1] == LFH[1]) { - if ((buf.array()[i + 2] == LFH[2] && buf.array()[i + 3] == LFH[3]) - || (buf.array()[i] == CFH[2] && buf.array()[i + 3] == CFH[3])) { - // found a LFH or CFH: - readTooMuch = offset + lastRead - i - expectedDDLen; - done = true; - } - else if (buf.array()[i + 2] == DD[2] && buf.array()[i + 3] == DD[3]) { - // found DD: - readTooMuch = offset + lastRead - i; - done = true; - } - if (done) { - // * push back bytes read in excess as well as the data - // descriptor - // * copy the remaining bytes to cache - // * read data descriptor - pushback(buf.array(), offset + lastRead - readTooMuch, readTooMuch); - bos.write(buf.array(), 0, i); - readDataDescriptor(); - } - } - } - return done; - } - - /** - * If the last read bytes could hold a data descriptor and an - * incomplete signature then save the last bytes to the front of - * the buffer and cache everything in front of the potential data - * descriptor into the given ByteArrayOutputStream. - * - *

Data descriptor plus incomplete signature (3 bytes in the - * worst case) can be 20 bytes max.

- */ - private int cacheBytesRead(final ByteArrayOutputStream bos, int offset, final int lastRead, final int expecteDDLen) { - final int cacheable = offset + lastRead - expecteDDLen - 3; - if (cacheable > 0) { - bos.write(buf.array(), 0, cacheable); - System.arraycopy(buf.array(), cacheable, buf.array(), 0, expecteDDLen + 3); - offset = expecteDDLen + 3; - } else { - offset += lastRead; - } - return offset; - } - - private void pushback(final byte[] buf, final int offset, final int length) throws IOException { - ((PushbackInputStream) in).unread(buf, offset, length); - pushedBackBytes(length); - } - - // End of Central Directory Record - // end of central dir signature WORD - // number of this disk SHORT - // number of the disk with the - // start of the central directory SHORT - // total number of entries in the - // central directory on this disk SHORT - // total number of entries in - // the central directory SHORT - // size of the central directory WORD - // offset of start of central - // directory with respect to - // the starting disk number WORD - // .ZIP file comment length SHORT - // .ZIP file comment up to 64KB - // - - /** - * Reads the stream until it find the "End of central directory - * record" and consumes it as well. - */ - private void skipRemainderOfArchive() throws IOException { - // skip over central directory. One LFH has been read too much - // already. The calculation discounts file names and extra - // data so it will be too short. - realSkip((long) entriesRead * CFH_LEN - LFH_LEN); - findEocdRecord(); - realSkip((long) ZipFile.MIN_EOCD_SIZE - WORD /* signature */ - SHORT /* comment len */); - readFully(shortBuf); - // file comment - realSkip(ZipShort.getValue(shortBuf)); - } - - /** - * Reads forward until the signature of the "End of central - * directory" record is found. - */ - private void findEocdRecord() throws IOException { - int currentByte = -1; - boolean skipReadCall = false; - while (skipReadCall || (currentByte = readOneByte()) > -1) { - skipReadCall = false; - if (!isFirstByteOfEocdSig(currentByte)) { - continue; - } - currentByte = readOneByte(); - if (currentByte != ZipArchiveOutputStream.EOCD_SIG[1]) { - if (currentByte == -1) { - break; - } - skipReadCall = isFirstByteOfEocdSig(currentByte); - continue; - } - currentByte = readOneByte(); - if (currentByte != ZipArchiveOutputStream.EOCD_SIG[2]) { - if (currentByte == -1) { - break; - } - skipReadCall = isFirstByteOfEocdSig(currentByte); - continue; - } - currentByte = readOneByte(); - if (currentByte == -1 - || currentByte == ZipArchiveOutputStream.EOCD_SIG[3]) { - break; - } - skipReadCall = isFirstByteOfEocdSig(currentByte); - } - } - - /** - * Skips bytes by reading from the underlying stream rather than - * the (potentially inflating) archive stream - which {@link - * #skip} would do. - * - * Also updates bytes-read counter. - */ - private void realSkip(final long value) throws IOException { - if (value >= 0) { - long skipped = 0; - while (skipped < value) { - final long rem = value - skipped; - final int x = in.read(skipBuf, 0, (int) (skipBuf.length > rem ? rem : skipBuf.length)); - if (x == -1) { - return; - } - count(x); - skipped += x; - } - return; - } - throw new IllegalArgumentException(); - } - - /** - * Reads bytes by reading from the underlying stream rather than - * the (potentially inflating) archive stream - which {@link #read} would do. - * - * Also updates bytes-read counter. - */ - private int readOneByte() throws IOException { - final int b = in.read(); - if (b != -1) { - count(1); - } - return b; - } - - private boolean isFirstByteOfEocdSig(final int b) { - return b == ZipArchiveOutputStream.EOCD_SIG[0]; - } - - /** - * Structure collecting information for the entry that is - * currently being read. - */ - private static final class CurrentEntry { - - /** - * Current ZIP entry. - */ - private final ZipArchiveEntry entry = new ZipArchiveEntry(); - - /** - * Does the entry use a data descriptor? - */ - private boolean hasDataDescriptor; - - /** - * Does the entry have a ZIP64 extended information extra field. - */ - private boolean usesZip64; - - /** - * Number of bytes of entry content read by the client if the - * entry is STORED. - */ - private long bytesRead; - - /** - * Number of bytes of entry content read from the stream. - * - *

This may be more than the actual entry's length as some - * stuff gets buffered up and needs to be pushed back when the - * end of the entry has been reached.

- */ - private long bytesReadFromStream; - - /** - * The checksum calculated as the current entry is read. - */ - private final CRC32 crc = new CRC32(); - - /** - * The input stream decompressing the data for shrunk and imploded entries. - */ - private InputStream in; - } - - /** - * Bounded input stream adapted from commons-io - */ - private class BoundedInputStream extends InputStream { - - /** the wrapped input stream */ - private final InputStream in; - - /** the max length to provide */ - private final long max; - - /** the number of bytes already returned */ - private long pos = 0; - - /** - * Creates a new BoundedInputStream that wraps the given input - * stream and limits it to a certain size. - * - * @param in The wrapped input stream - * @param size The maximum number of bytes to return - */ - public BoundedInputStream(final InputStream in, final long size) { - this.max = size; - this.in = in; - } - - @Override - public int read() throws IOException { - if (max >= 0 && pos >= max) { - return -1; - } - final int result = in.read(); - pos++; - count(1); - current.bytesReadFromStream++; - return result; - } - - @Override - public int read(final byte[] b) throws IOException { - return this.read(b, 0, b.length); - } - - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (max >= 0 && pos >= max) { - return -1; - } - final long maxRead = max >= 0 ? Math.min(len, max - pos) : len; - final int bytesRead = in.read(b, off, (int) maxRead); - - if (bytesRead == -1) { - return -1; - } - - pos += bytesRead; - count(bytesRead); - current.bytesReadFromStream += bytesRead; - return bytesRead; - } - - @Override - public long skip(final long n) throws IOException { - final long toSkip = max >= 0 ? Math.min(n, max - pos) : n; - final long skippedBytes = IOUtils.skip(in, toSkip); - pos += skippedBytes; - return skippedBytes; - } - - @Override - public int available() throws IOException { - if (max >= 0 && pos >= max) { - return 0; - } - return in.available(); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java b/src/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java deleted file mode 100644 index 6a8cacc02b9..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java +++ /dev/null @@ -1,1687 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.Calendar; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.zip.Deflater; -import java.util.zip.ZipException; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.utils.IOUtils; - -import static org.apache.commons.compress.archivers.zip.ZipConstants.DATA_DESCRIPTOR_MIN_VERSION; -import static org.apache.commons.compress.archivers.zip.ZipConstants.DEFLATE_MIN_VERSION; -import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD; -import static org.apache.commons.compress.archivers.zip.ZipConstants.INITIAL_VERSION; -import static org.apache.commons.compress.archivers.zip.ZipConstants.SHORT; -import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD; -import static org.apache.commons.compress.archivers.zip.ZipConstants.ZIP64_MAGIC; -import static org.apache.commons.compress.archivers.zip.ZipConstants.ZIP64_MAGIC_SHORT; -import static org.apache.commons.compress.archivers.zip.ZipConstants.ZIP64_MIN_VERSION; -import static org.apache.commons.compress.archivers.zip.ZipLong.putLong; -import static org.apache.commons.compress.archivers.zip.ZipShort.putShort; - -/** - * Reimplementation of {@link java.util.zip.ZipOutputStream - * java.util.zip.ZipOutputStream} that does handle the extended - * functionality of this package, especially internal/external file - * attributes and extra fields with different layouts for local file - * data and central directory entries. - * - *

This class will try to use {@link - * java.nio.channels.SeekableByteChannel} when it knows that the - * output is going to go to a file.

- * - *

If SeekableByteChannel cannot be used, this implementation will use - * a Data Descriptor to store size and CRC information for {@link - * #DEFLATED DEFLATED} entries, this means, you don't need to - * calculate them yourself. Unfortunately this is not possible for - * the {@link #STORED STORED} method, here setting the CRC and - * uncompressed size information is required before {@link - * #putArchiveEntry(ArchiveEntry)} can be called.

- * - *

As of Apache Commons Compress 1.3 it transparently supports Zip64 - * extensions and thus individual entries and archives larger than 4 - * GB or with more than 65536 entries in most cases but explicit - * control is provided via {@link #setUseZip64}. If the stream can not - * use SeekableByteChannel and you try to write a ZipArchiveEntry of - * unknown size then Zip64 extensions will be disabled by default.

- * - * @NotThreadSafe - */ -public class ZipArchiveOutputStream extends ArchiveOutputStream { - - static final int BUFFER_SIZE = 512; - private static final int LFH_SIG_OFFSET = 0; - private static final int LFH_VERSION_NEEDED_OFFSET = 4; - private static final int LFH_GPB_OFFSET = 6; - private static final int LFH_METHOD_OFFSET = 8; - private static final int LFH_TIME_OFFSET = 10; - private static final int LFH_CRC_OFFSET = 14; - private static final int LFH_COMPRESSED_SIZE_OFFSET = 18; - private static final int LFH_ORIGINAL_SIZE_OFFSET = 22; - private static final int LFH_FILENAME_LENGTH_OFFSET = 26; - private static final int LFH_EXTRA_LENGTH_OFFSET = 28; - private static final int LFH_FILENAME_OFFSET = 30; - private static final int CFH_SIG_OFFSET = 0; - private static final int CFH_VERSION_MADE_BY_OFFSET = 4; - private static final int CFH_VERSION_NEEDED_OFFSET = 6; - private static final int CFH_GPB_OFFSET = 8; - private static final int CFH_METHOD_OFFSET = 10; - private static final int CFH_TIME_OFFSET = 12; - private static final int CFH_CRC_OFFSET = 16; - private static final int CFH_COMPRESSED_SIZE_OFFSET = 20; - private static final int CFH_ORIGINAL_SIZE_OFFSET = 24; - private static final int CFH_FILENAME_LENGTH_OFFSET = 28; - private static final int CFH_EXTRA_LENGTH_OFFSET = 30; - private static final int CFH_COMMENT_LENGTH_OFFSET = 32; - private static final int CFH_DISK_NUMBER_OFFSET = 34; - private static final int CFH_INTERNAL_ATTRIBUTES_OFFSET = 36; - private static final int CFH_EXTERNAL_ATTRIBUTES_OFFSET = 38; - private static final int CFH_LFH_OFFSET = 42; - private static final int CFH_FILENAME_OFFSET = 46; - - /** indicates if this archive is finished. protected for use in Jar implementation */ - protected boolean finished = false; - - /** - * Compression method for deflated entries. - */ - public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED; - - /** - * Default compression level for deflated entries. - */ - public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION; - - /** - * Compression method for stored entries. - */ - public static final int STORED = java.util.zip.ZipEntry.STORED; - - /** - * default encoding for file names and comment. - */ - static final String DEFAULT_ENCODING = ZipEncodingHelper.UTF8; - - /** - * General purpose flag, which indicates that filenames are - * written in UTF-8. - * @deprecated use {@link GeneralPurposeBit#UFT8_NAMES_FLAG} instead - */ - @Deprecated - public static final int EFS_FLAG = GeneralPurposeBit.UFT8_NAMES_FLAG; - - private static final byte[] EMPTY = new byte[0]; - - /** - * Current entry. - */ - private CurrentEntry entry; - - /** - * The file comment. - */ - private String comment = ""; - - /** - * Compression level for next entry. - */ - private int level = DEFAULT_COMPRESSION; - - /** - * Has the compression level changed when compared to the last - * entry? - */ - private boolean hasCompressionLevelChanged = false; - - /** - * Default compression method for next entry. - */ - private int method = java.util.zip.ZipEntry.DEFLATED; - - /** - * List of ZipArchiveEntries written so far. - */ - private final List entries = - new LinkedList<>(); - - private final StreamCompressor streamCompressor; - - /** - * Start of central directory. - */ - private long cdOffset = 0; - - /** - * Length of central directory. - */ - private long cdLength = 0; - - /** - * Helper, a 0 as ZipShort. - */ - private static final byte[] ZERO = {0, 0}; - - /** - * Helper, a 0 as ZipLong. - */ - private static final byte[] LZERO = {0, 0, 0, 0}; - - private static final byte[] ONE = ZipLong.getBytes(1L); - - /** - * Holds some book-keeping data for each entry. - */ - private final Map metaData = - new HashMap<>(); - - /** - * The encoding to use for filenames and the file comment. - * - *

For a list of possible values see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html. - * Defaults to UTF-8.

- */ - private String encoding = DEFAULT_ENCODING; - - /** - * The zip encoding to use for filenames and the file comment. - * - * This field is of internal use and will be set in {@link - * #setEncoding(String)}. - */ - private ZipEncoding zipEncoding = - ZipEncodingHelper.getZipEncoding(DEFAULT_ENCODING); - - - /** - * This Deflater object is used for output. - * - */ - protected final Deflater def; - /** - * Optional random access output. - */ - private final SeekableByteChannel channel; - - private final OutputStream out; - - /** - * whether to use the general purpose bit flag when writing UTF-8 - * filenames or not. - */ - private boolean useUTF8Flag = true; - - /** - * Whether to encode non-encodable file names as UTF-8. - */ - private boolean fallbackToUTF8 = false; - - /** - * whether to create UnicodePathExtraField-s for each entry. - */ - private UnicodeExtraFieldPolicy createUnicodeExtraFields = UnicodeExtraFieldPolicy.NEVER; - - /** - * Whether anything inside this archive has used a ZIP64 feature. - * - * @since 1.3 - */ - private boolean hasUsedZip64 = false; - - private Zip64Mode zip64Mode = Zip64Mode.AsNeeded; - - private final byte[] copyBuffer = new byte[32768]; - private final Calendar calendarInstance = Calendar.getInstance(); - - /** - * Creates a new ZIP OutputStream filtering the underlying stream. - * @param out the outputstream to zip - */ - public ZipArchiveOutputStream(final OutputStream out) { - this.out = out; - this.channel = null; - def = new Deflater(level, true); - streamCompressor = StreamCompressor.create(out, def); - } - - /** - * Creates a new ZIP OutputStream writing to a File. Will use - * random access if possible. - * @param file the file to zip to - * @throws IOException on error - */ - public ZipArchiveOutputStream(final File file) throws IOException { - def = new Deflater(level, true); - OutputStream o = null; - SeekableByteChannel _channel = null; - StreamCompressor _streamCompressor = null; - try { - _channel = Files.newByteChannel(file.toPath(), - EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE, - StandardOpenOption.READ, - StandardOpenOption.TRUNCATE_EXISTING)); - // will never get opened properly when an exception is thrown so doesn't need to get closed - _streamCompressor = StreamCompressor.create(_channel, def); //NOSONAR - } catch (final IOException e) { - IOUtils.closeQuietly(_channel); - _channel = null; - o = new FileOutputStream(file); - _streamCompressor = StreamCompressor.create(o, def); - } - out = o; - channel = _channel; - streamCompressor = _streamCompressor; - } - - /** - * Creates a new ZIP OutputStream writing to a SeekableByteChannel. - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to write to an in-memory archive using random - * access.

- * - * @param channel the channel to zip to - * @throws IOException on error - * @since 1.13 - */ - public ZipArchiveOutputStream(SeekableByteChannel channel) throws IOException { - this.channel = channel; - def = new Deflater(level, true); - streamCompressor = StreamCompressor.create(channel, def); - out = null; - } - - /** - * This method indicates whether this archive is writing to a - * seekable stream (i.e., to a random access file). - * - *

For seekable streams, you don't need to calculate the CRC or - * uncompressed size for {@link #STORED} entries before - * invoking {@link #putArchiveEntry(ArchiveEntry)}. - * @return true if seekable - */ - public boolean isSeekable() { - return channel != null; - } - - /** - * The encoding to use for filenames and the file comment. - * - *

For a list of possible values see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html. - * Defaults to UTF-8.

- * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - */ - public void setEncoding(final String encoding) { - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - if (useUTF8Flag && !ZipEncodingHelper.isUTF8(encoding)) { - useUTF8Flag = false; - } - } - - /** - * The encoding to use for filenames and the file comment. - * - * @return null if using the platform's default character encoding. - */ - public String getEncoding() { - return encoding; - } - - /** - * Whether to set the language encoding flag if the file name - * encoding is UTF-8. - * - *

Defaults to true.

- * - * @param b whether to set the language encoding flag if the file - * name encoding is UTF-8 - */ - public void setUseLanguageEncodingFlag(final boolean b) { - useUTF8Flag = b && ZipEncodingHelper.isUTF8(encoding); - } - - /** - * Whether to create Unicode Extra Fields. - * - *

Defaults to NEVER.

- * - * @param b whether to create Unicode Extra Fields. - */ - public void setCreateUnicodeExtraFields(final UnicodeExtraFieldPolicy b) { - createUnicodeExtraFields = b; - } - - /** - * Whether to fall back to UTF and the language encoding flag if - * the file name cannot be encoded using the specified encoding. - * - *

Defaults to false.

- * - * @param b whether to fall back to UTF and the language encoding - * flag if the file name cannot be encoded using the specified - * encoding. - */ - public void setFallbackToUTF8(final boolean b) { - fallbackToUTF8 = b; - } - - /** - * Whether Zip64 extensions will be used. - * - *

When setting the mode to {@link Zip64Mode#Never Never}, - * {@link #putArchiveEntry}, {@link #closeArchiveEntry}, {@link - * #finish} or {@link #close} may throw a {@link - * Zip64RequiredException} if the entry's size or the total size - * of the archive exceeds 4GB or there are more than 65536 entries - * inside the archive. Any archive created in this mode will be - * readable by implementations that don't support Zip64.

- * - *

When setting the mode to {@link Zip64Mode#Always Always}, - * Zip64 extensions will be used for all entries. Any archive - * created in this mode may be unreadable by implementations that - * don't support Zip64 even if all its contents would be.

- * - *

When setting the mode to {@link Zip64Mode#AsNeeded - * AsNeeded}, Zip64 extensions will transparently be used for - * those entries that require them. This mode can only be used if - * the uncompressed size of the {@link ZipArchiveEntry} is known - * when calling {@link #putArchiveEntry} or the archive is written - * to a seekable output (i.e. you have used the {@link - * #ZipArchiveOutputStream(java.io.File) File-arg constructor}) - - * this mode is not valid when the output stream is not seekable - * and the uncompressed size is unknown when {@link - * #putArchiveEntry} is called.

- * - *

If no entry inside the resulting archive requires Zip64 - * extensions then {@link Zip64Mode#Never Never} will create the - * smallest archive. {@link Zip64Mode#AsNeeded AsNeeded} will - * create a slightly bigger archive if the uncompressed size of - * any entry has initially been unknown and create an archive - * identical to {@link Zip64Mode#Never Never} otherwise. {@link - * Zip64Mode#Always Always} will create an archive that is at - * least 24 bytes per entry bigger than the one {@link - * Zip64Mode#Never Never} would create.

- * - *

Defaults to {@link Zip64Mode#AsNeeded AsNeeded} unless - * {@link #putArchiveEntry} is called with an entry of unknown - * size and data is written to a non-seekable stream - in this - * case the default is {@link Zip64Mode#Never Never}.

- * - * @since 1.3 - * @param mode Whether Zip64 extensions will be used. - */ - public void setUseZip64(final Zip64Mode mode) { - zip64Mode = mode; - } - - /** - * {@inheritDoc} - * @throws Zip64RequiredException if the archive's size exceeds 4 - * GByte or there are more than 65535 entries inside the archive - * and {@link #setUseZip64} is {@link Zip64Mode#Never}. - */ - @Override - public void finish() throws IOException { - if (finished) { - throw new IOException("This archive has already been finished"); - } - - if (entry != null) { - throw new IOException("This archive contains unclosed entries."); - } - - cdOffset = streamCompressor.getTotalBytesWritten(); - writeCentralDirectoryInChunks(); - - cdLength = streamCompressor.getTotalBytesWritten() - cdOffset; - writeZip64CentralDirectory(); - writeCentralDirectoryEnd(); - metaData.clear(); - entries.clear(); - streamCompressor.close(); - finished = true; - } - - private void writeCentralDirectoryInChunks() throws IOException { - final int NUM_PER_WRITE = 1000; - final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(70 * NUM_PER_WRITE); - int count = 0; - for (final ZipArchiveEntry ze : entries) { - byteArrayOutputStream.write(createCentralFileHeader(ze)); - if (++count > NUM_PER_WRITE){ - writeCounted(byteArrayOutputStream.toByteArray()); - byteArrayOutputStream.reset(); - count = 0; - } - } - writeCounted(byteArrayOutputStream.toByteArray()); - } - - /** - * Writes all necessary data for this entry. - * @throws IOException on error - * @throws Zip64RequiredException if the entry's uncompressed or - * compressed size exceeds 4 GByte and {@link #setUseZip64} - * is {@link Zip64Mode#Never}. - */ - @Override - public void closeArchiveEntry() throws IOException { - preClose(); - - flushDeflater(); - - final long bytesWritten = streamCompressor.getTotalBytesWritten() - entry.dataStart; - final long realCrc = streamCompressor.getCrc32(); - entry.bytesRead = streamCompressor.getBytesRead(); - final Zip64Mode effectiveMode = getEffectiveZip64Mode(entry.entry); - final boolean actuallyNeedsZip64 = handleSizesAndCrc(bytesWritten, realCrc, effectiveMode); - closeEntry(actuallyNeedsZip64, false); - streamCompressor.reset(); - } - - /** - * Writes all necessary data for this entry. - * - * @param phased This entry is second phase of a 2-phase zip creation, size, compressed size and crc - * are known in ZipArchiveEntry - * @throws IOException on error - * @throws Zip64RequiredException if the entry's uncompressed or - * compressed size exceeds 4 GByte and {@link #setUseZip64} - * is {@link Zip64Mode#Never}. - */ - private void closeCopiedEntry(final boolean phased) throws IOException { - preClose(); - entry.bytesRead = entry.entry.getSize(); - final Zip64Mode effectiveMode = getEffectiveZip64Mode(entry.entry); - final boolean actuallyNeedsZip64 = checkIfNeedsZip64(effectiveMode); - closeEntry(actuallyNeedsZip64, phased); - } - - private void closeEntry(final boolean actuallyNeedsZip64, final boolean phased) throws IOException { - if (!phased && channel != null) { - rewriteSizesAndCrc(actuallyNeedsZip64); - } - - if (!phased) { - writeDataDescriptor(entry.entry); - } - entry = null; - } - - private void preClose() throws IOException { - if (finished) { - throw new IOException("Stream has already been finished"); - } - - if (entry == null) { - throw new IOException("No current entry to close"); - } - - if (!entry.hasWritten) { - write(EMPTY, 0, 0); - } - } - - /** - * Adds an archive entry with a raw input stream. - * - * If crc, size and compressed size are supplied on the entry, these values will be used as-is. - * Zip64 status is re-established based on the settings in this stream, and the supplied value - * is ignored. - * - * The entry is put and closed immediately. - * - * @param entry The archive entry to add - * @param rawStream The raw input stream of a different entry. May be compressed/encrypted. - * @throws IOException If copying fails - */ - public void addRawArchiveEntry(final ZipArchiveEntry entry, final InputStream rawStream) - throws IOException { - final ZipArchiveEntry ae = new ZipArchiveEntry(entry); - if (hasZip64Extra(ae)) { - // Will be re-added as required. this may make the file generated with this method - // somewhat smaller than standard mode, - // since standard mode is unable to remove the zip 64 header. - ae.removeExtraField(Zip64ExtendedInformationExtraField.HEADER_ID); - } - final boolean is2PhaseSource = ae.getCrc() != ZipArchiveEntry.CRC_UNKNOWN - && ae.getSize() != ArchiveEntry.SIZE_UNKNOWN - && ae.getCompressedSize() != ArchiveEntry.SIZE_UNKNOWN; - putArchiveEntry(ae, is2PhaseSource); - copyFromZipInputStream(rawStream); - closeCopiedEntry(is2PhaseSource); - } - - /** - * Ensures all bytes sent to the deflater are written to the stream. - */ - private void flushDeflater() throws IOException { - if (entry.entry.getMethod() == DEFLATED) { - streamCompressor.flushDeflater(); - } - } - - /** - * Ensures the current entry's size and CRC information is set to - * the values just written, verifies it isn't too big in the - * Zip64Mode.Never case and returns whether the entry would - * require a Zip64 extra field. - */ - private boolean handleSizesAndCrc(final long bytesWritten, final long crc, - final Zip64Mode effectiveMode) - throws ZipException { - if (entry.entry.getMethod() == DEFLATED) { - /* It turns out def.getBytesRead() returns wrong values if - * the size exceeds 4 GB on Java < Java7 - entry.entry.setSize(def.getBytesRead()); - */ - entry.entry.setSize(entry.bytesRead); - entry.entry.setCompressedSize(bytesWritten); - entry.entry.setCrc(crc); - - } else if (channel == null) { - if (entry.entry.getCrc() != crc) { - throw new ZipException("bad CRC checksum for entry " - + entry.entry.getName() + ": " - + Long.toHexString(entry.entry.getCrc()) - + " instead of " - + Long.toHexString(crc)); - } - - if (entry.entry.getSize() != bytesWritten) { - throw new ZipException("bad size for entry " - + entry.entry.getName() + ": " - + entry.entry.getSize() - + " instead of " - + bytesWritten); - } - } else { /* method is STORED and we used SeekableByteChannel */ - entry.entry.setSize(bytesWritten); - entry.entry.setCompressedSize(bytesWritten); - entry.entry.setCrc(crc); - } - - return checkIfNeedsZip64(effectiveMode); - } - - /** - * Verifies the sizes aren't too big in the Zip64Mode.Never case - * and returns whether the entry would require a Zip64 extra - * field. - */ - private boolean checkIfNeedsZip64(final Zip64Mode effectiveMode) - throws ZipException { - final boolean actuallyNeedsZip64 = isZip64Required(entry.entry, effectiveMode); - if (actuallyNeedsZip64 && effectiveMode == Zip64Mode.Never) { - throw new Zip64RequiredException(Zip64RequiredException.getEntryTooBigMessage(entry.entry)); - } - return actuallyNeedsZip64; - } - - private boolean isZip64Required(final ZipArchiveEntry entry1, final Zip64Mode requestedMode) { - return requestedMode == Zip64Mode.Always || isTooLageForZip32(entry1); - } - - private boolean isTooLageForZip32(final ZipArchiveEntry zipArchiveEntry){ - return zipArchiveEntry.getSize() >= ZIP64_MAGIC || zipArchiveEntry.getCompressedSize() >= ZIP64_MAGIC; - } - - /** - * When using random access output, write the local file header - * and potentiall the ZIP64 extra containing the correct CRC and - * compressed/uncompressed sizes. - */ - private void rewriteSizesAndCrc(final boolean actuallyNeedsZip64) - throws IOException { - final long save = channel.position(); - - channel.position(entry.localDataStart); - writeOut(ZipLong.getBytes(entry.entry.getCrc())); - if (!hasZip64Extra(entry.entry) || !actuallyNeedsZip64) { - writeOut(ZipLong.getBytes(entry.entry.getCompressedSize())); - writeOut(ZipLong.getBytes(entry.entry.getSize())); - } else { - writeOut(ZipLong.ZIP64_MAGIC.getBytes()); - writeOut(ZipLong.ZIP64_MAGIC.getBytes()); - } - - if (hasZip64Extra(entry.entry)) { - final ByteBuffer name = getName(entry.entry); - final int nameLen = name.limit() - name.position(); - // seek to ZIP64 extra, skip header and size information - channel.position(entry.localDataStart + 3 * WORD + 2 * SHORT - + nameLen + 2 * SHORT); - // inside the ZIP64 extra uncompressed size comes - // first, unlike the LFH, CD or data descriptor - writeOut(ZipEightByteInteger.getBytes(entry.entry.getSize())); - writeOut(ZipEightByteInteger.getBytes(entry.entry.getCompressedSize())); - - if (!actuallyNeedsZip64) { - // do some cleanup: - // * rewrite version needed to extract - channel.position(entry.localDataStart - 5 * SHORT); - writeOut(ZipShort.getBytes(versionNeededToExtract(entry.entry.getMethod(), false, false))); - - // * remove ZIP64 extra so it doesn't get written - // to the central directory - entry.entry.removeExtraField(Zip64ExtendedInformationExtraField - .HEADER_ID); - entry.entry.setExtra(); - - // * reset hasUsedZip64 if it has been set because - // of this entry - if (entry.causedUseOfZip64) { - hasUsedZip64 = false; - } - } - } - channel.position(save); - } - - /** - * {@inheritDoc} - * @throws ClassCastException if entry is not an instance of ZipArchiveEntry - * @throws Zip64RequiredException if the entry's uncompressed or - * compressed size is known to exceed 4 GByte and {@link #setUseZip64} - * is {@link Zip64Mode#Never}. - */ - @Override - public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException { - putArchiveEntry(archiveEntry, false); - } - - /** - * Writes the headers for an archive entry to the output stream. - * The caller must then write the content to the stream and call - * {@link #closeArchiveEntry()} to complete the process. - - * @param archiveEntry The archiveEntry - * @param phased If true size, compressedSize and crc required to be known up-front in the archiveEntry - * @throws ClassCastException if entry is not an instance of ZipArchiveEntry - * @throws Zip64RequiredException if the entry's uncompressed or - * compressed size is known to exceed 4 GByte and {@link #setUseZip64} - * is {@link Zip64Mode#Never}. - */ - private void putArchiveEntry(final ArchiveEntry archiveEntry, final boolean phased) throws IOException { - if (finished) { - throw new IOException("Stream has already been finished"); - } - - if (entry != null) { - closeArchiveEntry(); - } - - entry = new CurrentEntry((ZipArchiveEntry) archiveEntry); - entries.add(entry.entry); - - setDefaults(entry.entry); - - final Zip64Mode effectiveMode = getEffectiveZip64Mode(entry.entry); - validateSizeInformation(effectiveMode); - - if (shouldAddZip64Extra(entry.entry, effectiveMode)) { - - final Zip64ExtendedInformationExtraField z64 = getZip64Extra(entry.entry); - - ZipEightByteInteger size; - ZipEightByteInteger compressedSize; - if (phased) { - // sizes are already known - size = new ZipEightByteInteger(entry.entry.getSize()); - compressedSize = new ZipEightByteInteger(entry.entry.getCompressedSize()); - } else if (entry.entry.getMethod() == STORED - && entry.entry.getSize() != ArchiveEntry.SIZE_UNKNOWN) { - // actually, we already know the sizes - compressedSize = size = new ZipEightByteInteger(entry.entry.getSize()); - } else { - // just a placeholder, real data will be in data - // descriptor or inserted later via SeekableByteChannel - compressedSize = size = ZipEightByteInteger.ZERO; - } - z64.setSize(size); - z64.setCompressedSize(compressedSize); - entry.entry.setExtra(); - } - - if (entry.entry.getMethod() == DEFLATED && hasCompressionLevelChanged) { - def.setLevel(level); - hasCompressionLevelChanged = false; - } - writeLocalFileHeader((ZipArchiveEntry) archiveEntry, phased); - } - - /** - * Provides default values for compression method and last - * modification time. - */ - private void setDefaults(final ZipArchiveEntry entry) { - if (entry.getMethod() == -1) { // not specified - entry.setMethod(method); - } - - if (entry.getTime() == -1) { // not specified - entry.setTime(System.currentTimeMillis()); - } - } - - /** - * Throws an exception if the size is unknown for a stored entry - * that is written to a non-seekable output or the entry is too - * big to be written without Zip64 extra but the mode has been set - * to Never. - */ - private void validateSizeInformation(final Zip64Mode effectiveMode) - throws ZipException { - // Size/CRC not required if SeekableByteChannel is used - if (entry.entry.getMethod() == STORED && channel == null) { - if (entry.entry.getSize() == ArchiveEntry.SIZE_UNKNOWN) { - throw new ZipException("uncompressed size is required for" - + " STORED method when not writing to a" - + " file"); - } - if (entry.entry.getCrc() == ZipArchiveEntry.CRC_UNKNOWN) { - throw new ZipException("crc checksum is required for STORED" - + " method when not writing to a file"); - } - entry.entry.setCompressedSize(entry.entry.getSize()); - } - - if ((entry.entry.getSize() >= ZIP64_MAGIC - || entry.entry.getCompressedSize() >= ZIP64_MAGIC) - && effectiveMode == Zip64Mode.Never) { - throw new Zip64RequiredException(Zip64RequiredException - .getEntryTooBigMessage(entry.entry)); - } - } - - /** - * Whether to addd a Zip64 extended information extra field to the - * local file header. - * - *

Returns true if

- * - *
    - *
  • mode is Always
  • - *
  • or we already know it is going to be needed
  • - *
  • or the size is unknown and we can ensure it won't hurt - * other implementations if we add it (i.e. we can erase its - * usage
  • - *
- */ - private boolean shouldAddZip64Extra(final ZipArchiveEntry entry, final Zip64Mode mode) { - return mode == Zip64Mode.Always - || entry.getSize() >= ZIP64_MAGIC - || entry.getCompressedSize() >= ZIP64_MAGIC - || (entry.getSize() == ArchiveEntry.SIZE_UNKNOWN - && channel != null && mode != Zip64Mode.Never); - } - - /** - * Set the file comment. - * @param comment the comment - */ - public void setComment(final String comment) { - this.comment = comment; - } - - /** - * Sets the compression level for subsequent entries. - * - *

Default is Deflater.DEFAULT_COMPRESSION.

- * @param level the compression level. - * @throws IllegalArgumentException if an invalid compression - * level is specified. - */ - public void setLevel(final int level) { - if (level < Deflater.DEFAULT_COMPRESSION - || level > Deflater.BEST_COMPRESSION) { - throw new IllegalArgumentException("Invalid compression level: " - + level); - } - hasCompressionLevelChanged = (this.level != level); - this.level = level; - } - - /** - * Sets the default compression method for subsequent entries. - * - *

Default is DEFLATED.

- * @param method an int from java.util.zip.ZipEntry - */ - public void setMethod(final int method) { - this.method = method; - } - - /** - * Whether this stream is able to write the given entry. - * - *

May return false if it is set up to use encryption or a - * compression method that hasn't been implemented yet.

- * @since 1.1 - */ - @Override - public boolean canWriteEntryData(final ArchiveEntry ae) { - if (ae instanceof ZipArchiveEntry) { - final ZipArchiveEntry zae = (ZipArchiveEntry) ae; - return zae.getMethod() != ZipMethod.IMPLODING.getCode() - && zae.getMethod() != ZipMethod.UNSHRINKING.getCode() - && ZipUtil.canHandleEntryData(zae); - } - return false; - } - - /** - * Writes bytes to ZIP entry. - * @param b the byte array to write - * @param offset the start position to write from - * @param length the number of bytes to write - * @throws IOException on error - */ - @Override - public void write(final byte[] b, final int offset, final int length) throws IOException { - if (entry == null) { - throw new IllegalStateException("No current entry"); - } - ZipUtil.checkRequestedFeatures(entry.entry); - final long writtenThisTime = streamCompressor.write(b, offset, length, entry.entry.getMethod()); - count(writtenThisTime); - } - - /** - * Write bytes to output or random access file. - * @param data the byte array to write - * @throws IOException on error - */ - private void writeCounted(final byte[] data) throws IOException { - streamCompressor.writeCounted(data); - } - - private void copyFromZipInputStream(final InputStream src) throws IOException { - if (entry == null) { - throw new IllegalStateException("No current entry"); - } - ZipUtil.checkRequestedFeatures(entry.entry); - entry.hasWritten = true; - int length; - while ((length = src.read(copyBuffer)) >= 0 ) - { - streamCompressor.writeCounted(copyBuffer, 0, length); - count( length ); - } - } - - /** - * Closes this output stream and releases any system resources - * associated with the stream. - * - * @throws IOException if an I/O error occurs. - * @throws Zip64RequiredException if the archive's size exceeds 4 - * GByte or there are more than 65535 entries inside the archive - * and {@link #setUseZip64} is {@link Zip64Mode#Never}. - */ - @Override - public void close() throws IOException { - if (!finished) { - finish(); - } - destroy(); - } - - /** - * Flushes this output stream and forces any buffered output bytes - * to be written out to the stream. - * - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - if (out != null) { - out.flush(); - } - } - - /* - * Various ZIP constants shared between this class, ZipArchiveInputStream and ZipFile - */ - /** - * local file header signature - */ - static final byte[] LFH_SIG = ZipLong.LFH_SIG.getBytes(); //NOSONAR - /** - * data descriptor signature - */ - static final byte[] DD_SIG = ZipLong.DD_SIG.getBytes(); //NOSONAR - /** - * central file header signature - */ - static final byte[] CFH_SIG = ZipLong.CFH_SIG.getBytes(); //NOSONAR - /** - * end of central dir signature - */ - static final byte[] EOCD_SIG = ZipLong.getBytes(0X06054B50L); //NOSONAR - /** - * ZIP64 end of central dir signature - */ - static final byte[] ZIP64_EOCD_SIG = ZipLong.getBytes(0X06064B50L); //NOSONAR - /** - * ZIP64 end of central dir locator signature - */ - static final byte[] ZIP64_EOCD_LOC_SIG = ZipLong.getBytes(0X07064B50L); //NOSONAR - - /** - * Writes next block of compressed data to the output stream. - * @throws IOException on error - */ - protected final void deflate() throws IOException { - streamCompressor.deflate(); - } - - /** - * Writes the local file header entry - * @param ze the entry to write - * @throws IOException on error - */ - protected void writeLocalFileHeader(final ZipArchiveEntry ze) throws IOException { - writeLocalFileHeader(ze, false); - } - - private void writeLocalFileHeader(final ZipArchiveEntry ze, final boolean phased) throws IOException { - final boolean encodable = zipEncoding.canEncode(ze.getName()); - final ByteBuffer name = getName(ze); - - if (createUnicodeExtraFields != UnicodeExtraFieldPolicy.NEVER) { - addUnicodeExtraFields(ze, encodable, name); - } - - final long localHeaderStart = streamCompressor.getTotalBytesWritten(); - final byte[] localHeader = createLocalFileHeader(ze, name, encodable, phased, localHeaderStart); - metaData.put(ze, new EntryMetaData(localHeaderStart, usesDataDescriptor(ze.getMethod(), phased))); - entry.localDataStart = localHeaderStart + LFH_CRC_OFFSET; // At crc offset - writeCounted(localHeader); - entry.dataStart = streamCompressor.getTotalBytesWritten(); - } - - - private byte[] createLocalFileHeader(final ZipArchiveEntry ze, final ByteBuffer name, final boolean encodable, - final boolean phased, long archiveOffset) { - ResourceAlignmentExtraField oldAlignmentEx = - (ResourceAlignmentExtraField) ze.getExtraField(ResourceAlignmentExtraField.ID); - if (oldAlignmentEx != null) { - ze.removeExtraField(ResourceAlignmentExtraField.ID); - } - - int alignment = ze.getAlignment(); - if (alignment <= 0 && oldAlignmentEx != null) { - alignment = oldAlignmentEx.getAlignment(); - } - - if (alignment > 1 || (oldAlignmentEx != null && !oldAlignmentEx.allowMethodChange())) { - int oldLength = LFH_FILENAME_OFFSET + - name.limit() - name.position() + - ze.getLocalFileDataExtra().length; - - int padding = (int) ((-archiveOffset - oldLength - ZipExtraField.EXTRAFIELD_HEADER_SIZE - - ResourceAlignmentExtraField.BASE_SIZE) & - (alignment - 1)); - ze.addExtraField(new ResourceAlignmentExtraField(alignment, - oldAlignmentEx != null && oldAlignmentEx.allowMethodChange(), padding)); - } - - final byte[] extra = ze.getLocalFileDataExtra(); - final int nameLen = name.limit() - name.position(); - final int len = LFH_FILENAME_OFFSET + nameLen + extra.length; - final byte[] buf = new byte[len]; - - System.arraycopy(LFH_SIG, 0, buf, LFH_SIG_OFFSET, WORD); - - //store method in local variable to prevent multiple method calls - final int zipMethod = ze.getMethod(); - final boolean dataDescriptor = usesDataDescriptor(zipMethod, phased); - - putShort(versionNeededToExtract(zipMethod, hasZip64Extra(ze), dataDescriptor), buf, LFH_VERSION_NEEDED_OFFSET); - - final GeneralPurposeBit generalPurposeBit = getGeneralPurposeBits(!encodable && fallbackToUTF8, dataDescriptor); - generalPurposeBit.encode(buf, LFH_GPB_OFFSET); - - // compression method - putShort(zipMethod, buf, LFH_METHOD_OFFSET); - - ZipUtil.toDosTime(calendarInstance, ze.getTime(), buf, LFH_TIME_OFFSET); - - // CRC - if (phased){ - putLong(ze.getCrc(), buf, LFH_CRC_OFFSET); - } else if (zipMethod == DEFLATED || channel != null) { - System.arraycopy(LZERO, 0, buf, LFH_CRC_OFFSET, WORD); - } else { - putLong(ze.getCrc(), buf, LFH_CRC_OFFSET); - } - - // compressed length - // uncompressed length - if (hasZip64Extra(entry.entry)){ - // point to ZIP64 extended information extra field for - // sizes, may get rewritten once sizes are known if - // stream is seekable - ZipLong.ZIP64_MAGIC.putLong(buf, LFH_COMPRESSED_SIZE_OFFSET); - ZipLong.ZIP64_MAGIC.putLong(buf, LFH_ORIGINAL_SIZE_OFFSET); - } else if (phased) { - putLong(ze.getCompressedSize(), buf, LFH_COMPRESSED_SIZE_OFFSET); - putLong(ze.getSize(), buf, LFH_ORIGINAL_SIZE_OFFSET); - } else if (zipMethod == DEFLATED || channel != null) { - System.arraycopy(LZERO, 0, buf, LFH_COMPRESSED_SIZE_OFFSET, WORD); - System.arraycopy(LZERO, 0, buf, LFH_ORIGINAL_SIZE_OFFSET, WORD); - } else { // Stored - putLong(ze.getSize(), buf, LFH_COMPRESSED_SIZE_OFFSET); - putLong(ze.getSize(), buf, LFH_ORIGINAL_SIZE_OFFSET); - } - // file name length - putShort(nameLen, buf, LFH_FILENAME_LENGTH_OFFSET); - - // extra field length - putShort(extra.length, buf, LFH_EXTRA_LENGTH_OFFSET); - - // file name - System.arraycopy( name.array(), name.arrayOffset(), buf, LFH_FILENAME_OFFSET, nameLen); - - // extra fields - System.arraycopy(extra, 0, buf, LFH_FILENAME_OFFSET + nameLen, extra.length); - - return buf; - } - - - /** - * Adds UnicodeExtra fields for name and file comment if mode is - * ALWAYS or the data cannot be encoded using the configured - * encoding. - */ - private void addUnicodeExtraFields(final ZipArchiveEntry ze, final boolean encodable, - final ByteBuffer name) - throws IOException { - if (createUnicodeExtraFields == UnicodeExtraFieldPolicy.ALWAYS - || !encodable) { - ze.addExtraField(new UnicodePathExtraField(ze.getName(), - name.array(), - name.arrayOffset(), - name.limit() - - name.position())); - } - - final String comm = ze.getComment(); - if (comm != null && !"".equals(comm)) { - - final boolean commentEncodable = zipEncoding.canEncode(comm); - - if (createUnicodeExtraFields == UnicodeExtraFieldPolicy.ALWAYS - || !commentEncodable) { - final ByteBuffer commentB = getEntryEncoding(ze).encode(comm); - ze.addExtraField(new UnicodeCommentExtraField(comm, - commentB.array(), - commentB.arrayOffset(), - commentB.limit() - - commentB.position()) - ); - } - } - } - - /** - * Writes the data descriptor entry. - * @param ze the entry to write - * @throws IOException on error - */ - protected void writeDataDescriptor(final ZipArchiveEntry ze) throws IOException { - if (!usesDataDescriptor(ze.getMethod(), false)) { - return; - } - writeCounted(DD_SIG); - writeCounted(ZipLong.getBytes(ze.getCrc())); - if (!hasZip64Extra(ze)) { - writeCounted(ZipLong.getBytes(ze.getCompressedSize())); - writeCounted(ZipLong.getBytes(ze.getSize())); - } else { - writeCounted(ZipEightByteInteger.getBytes(ze.getCompressedSize())); - writeCounted(ZipEightByteInteger.getBytes(ze.getSize())); - } - } - - /** - * Writes the central file header entry. - * @param ze the entry to write - * @throws IOException on error - * @throws Zip64RequiredException if the archive's size exceeds 4 - * GByte and {@link Zip64Mode #setUseZip64} is {@link - * Zip64Mode#Never}. - */ - protected void writeCentralFileHeader(final ZipArchiveEntry ze) throws IOException { - final byte[] centralFileHeader = createCentralFileHeader(ze); - writeCounted(centralFileHeader); - } - - private byte[] createCentralFileHeader(final ZipArchiveEntry ze) throws IOException { - - final EntryMetaData entryMetaData = metaData.get(ze); - final boolean needsZip64Extra = hasZip64Extra(ze) - || ze.getCompressedSize() >= ZIP64_MAGIC - || ze.getSize() >= ZIP64_MAGIC - || entryMetaData.offset >= ZIP64_MAGIC - || zip64Mode == Zip64Mode.Always; - - if (needsZip64Extra && zip64Mode == Zip64Mode.Never) { - // must be the offset that is too big, otherwise an - // exception would have been throw in putArchiveEntry or - // closeArchiveEntry - throw new Zip64RequiredException(Zip64RequiredException - .ARCHIVE_TOO_BIG_MESSAGE); - } - - - handleZip64Extra(ze, entryMetaData.offset, needsZip64Extra); - - return createCentralFileHeader(ze, getName(ze), entryMetaData, needsZip64Extra); - } - - /** - * Writes the central file header entry. - * @param ze the entry to write - * @param name The encoded name - * @param entryMetaData meta data for this file - * @throws IOException on error - */ - private byte[] createCentralFileHeader(final ZipArchiveEntry ze, final ByteBuffer name, - final EntryMetaData entryMetaData, - final boolean needsZip64Extra) throws IOException { - final byte[] extra = ze.getCentralDirectoryExtra(); - - // file comment length - String comm = ze.getComment(); - if (comm == null) { - comm = ""; - } - - final ByteBuffer commentB = getEntryEncoding(ze).encode(comm); - final int nameLen = name.limit() - name.position(); - final int commentLen = commentB.limit() - commentB.position(); - final int len= CFH_FILENAME_OFFSET + nameLen + extra.length + commentLen; - final byte[] buf = new byte[len]; - - System.arraycopy(CFH_SIG, 0, buf, CFH_SIG_OFFSET, WORD); - - // version made by - // CheckStyle:MagicNumber OFF - putShort((ze.getPlatform() << 8) | (!hasUsedZip64 ? DATA_DESCRIPTOR_MIN_VERSION : ZIP64_MIN_VERSION), - buf, CFH_VERSION_MADE_BY_OFFSET); - - final int zipMethod = ze.getMethod(); - final boolean encodable = zipEncoding.canEncode(ze.getName()); - putShort(versionNeededToExtract(zipMethod, needsZip64Extra, entryMetaData.usesDataDescriptor), - buf, CFH_VERSION_NEEDED_OFFSET); - getGeneralPurposeBits(!encodable && fallbackToUTF8, entryMetaData.usesDataDescriptor).encode(buf, CFH_GPB_OFFSET); - - // compression method - putShort(zipMethod, buf, CFH_METHOD_OFFSET); - - - // last mod. time and date - ZipUtil.toDosTime(calendarInstance, ze.getTime(), buf, CFH_TIME_OFFSET); - - // CRC - // compressed length - // uncompressed length - putLong(ze.getCrc(), buf, CFH_CRC_OFFSET); - if (ze.getCompressedSize() >= ZIP64_MAGIC - || ze.getSize() >= ZIP64_MAGIC - || zip64Mode == Zip64Mode.Always) { - ZipLong.ZIP64_MAGIC.putLong(buf, CFH_COMPRESSED_SIZE_OFFSET); - ZipLong.ZIP64_MAGIC.putLong(buf, CFH_ORIGINAL_SIZE_OFFSET); - } else { - putLong(ze.getCompressedSize(), buf, CFH_COMPRESSED_SIZE_OFFSET); - putLong(ze.getSize(), buf, CFH_ORIGINAL_SIZE_OFFSET); - } - - putShort(nameLen, buf, CFH_FILENAME_LENGTH_OFFSET); - - // extra field length - putShort(extra.length, buf, CFH_EXTRA_LENGTH_OFFSET); - - putShort(commentLen, buf, CFH_COMMENT_LENGTH_OFFSET); - - // disk number start - System.arraycopy(ZERO, 0, buf, CFH_DISK_NUMBER_OFFSET, SHORT); - - // internal file attributes - putShort(ze.getInternalAttributes(), buf, CFH_INTERNAL_ATTRIBUTES_OFFSET); - - // external file attributes - putLong(ze.getExternalAttributes(), buf, CFH_EXTERNAL_ATTRIBUTES_OFFSET); - - // relative offset of LFH - if (entryMetaData.offset >= ZIP64_MAGIC || zip64Mode == Zip64Mode.Always) { - putLong(ZIP64_MAGIC, buf, CFH_LFH_OFFSET); - } else { - putLong(Math.min(entryMetaData.offset, ZIP64_MAGIC), buf, CFH_LFH_OFFSET); - } - - // file name - System.arraycopy(name.array(), name.arrayOffset(), buf, CFH_FILENAME_OFFSET, nameLen); - - final int extraStart = CFH_FILENAME_OFFSET + nameLen; - System.arraycopy(extra, 0, buf, extraStart, extra.length); - - final int commentStart = extraStart + extra.length; - - // file comment - System.arraycopy(commentB.array(), commentB.arrayOffset(), buf, commentStart, commentLen); - return buf; - } - - /** - * If the entry needs Zip64 extra information inside the central - * directory then configure its data. - */ - private void handleZip64Extra(final ZipArchiveEntry ze, final long lfhOffset, - final boolean needsZip64Extra) { - if (needsZip64Extra) { - final Zip64ExtendedInformationExtraField z64 = getZip64Extra(ze); - if (ze.getCompressedSize() >= ZIP64_MAGIC - || ze.getSize() >= ZIP64_MAGIC - || zip64Mode == Zip64Mode.Always) { - z64.setCompressedSize(new ZipEightByteInteger(ze.getCompressedSize())); - z64.setSize(new ZipEightByteInteger(ze.getSize())); - } else { - // reset value that may have been set for LFH - z64.setCompressedSize(null); - z64.setSize(null); - } - if (lfhOffset >= ZIP64_MAGIC || zip64Mode == Zip64Mode.Always) { - z64.setRelativeHeaderOffset(new ZipEightByteInteger(lfhOffset)); - } - ze.setExtra(); - } - } - - /** - * Writes the "End of central dir record". - * @throws IOException on error - * @throws Zip64RequiredException if the archive's size exceeds 4 - * GByte or there are more than 65535 entries inside the archive - * and {@link Zip64Mode #setUseZip64} is {@link Zip64Mode#Never}. - */ - protected void writeCentralDirectoryEnd() throws IOException { - writeCounted(EOCD_SIG); - - // disk numbers - writeCounted(ZERO); - writeCounted(ZERO); - - // number of entries - final int numberOfEntries = entries.size(); - if (numberOfEntries > ZIP64_MAGIC_SHORT - && zip64Mode == Zip64Mode.Never) { - throw new Zip64RequiredException(Zip64RequiredException - .TOO_MANY_ENTRIES_MESSAGE); - } - if (cdOffset > ZIP64_MAGIC && zip64Mode == Zip64Mode.Never) { - throw new Zip64RequiredException(Zip64RequiredException - .ARCHIVE_TOO_BIG_MESSAGE); - } - - final byte[] num = ZipShort.getBytes(Math.min(numberOfEntries, - ZIP64_MAGIC_SHORT)); - writeCounted(num); - writeCounted(num); - - // length and location of CD - writeCounted(ZipLong.getBytes(Math.min(cdLength, ZIP64_MAGIC))); - writeCounted(ZipLong.getBytes(Math.min(cdOffset, ZIP64_MAGIC))); - - // ZIP file comment - final ByteBuffer data = this.zipEncoding.encode(comment); - final int dataLen = data.limit() - data.position(); - writeCounted(ZipShort.getBytes(dataLen)); - streamCompressor.writeCounted(data.array(), data.arrayOffset(), dataLen); - } - - /** - * Writes the "ZIP64 End of central dir record" and - * "ZIP64 End of central dir locator". - * @throws IOException on error - * @since 1.3 - */ - protected void writeZip64CentralDirectory() throws IOException { - if (zip64Mode == Zip64Mode.Never) { - return; - } - - if (!hasUsedZip64 - && (cdOffset >= ZIP64_MAGIC || cdLength >= ZIP64_MAGIC - || entries.size() >= ZIP64_MAGIC_SHORT)) { - // actually "will use" - hasUsedZip64 = true; - } - - if (!hasUsedZip64) { - return; - } - - final long offset = streamCompressor.getTotalBytesWritten(); - - writeOut(ZIP64_EOCD_SIG); - // size, we don't have any variable length as we don't support - // the extensible data sector, yet - writeOut(ZipEightByteInteger - .getBytes(SHORT /* version made by */ - + SHORT /* version needed to extract */ - + WORD /* disk number */ - + WORD /* disk with central directory */ - + DWORD /* number of entries in CD on this disk */ - + DWORD /* total number of entries */ - + DWORD /* size of CD */ - + (long) DWORD /* offset of CD */ - )); - - // version made by and version needed to extract - writeOut(ZipShort.getBytes(ZIP64_MIN_VERSION)); - writeOut(ZipShort.getBytes(ZIP64_MIN_VERSION)); - - // disk numbers - four bytes this time - writeOut(LZERO); - writeOut(LZERO); - - // number of entries - final byte[] num = ZipEightByteInteger.getBytes(entries.size()); - writeOut(num); - writeOut(num); - - // length and location of CD - writeOut(ZipEightByteInteger.getBytes(cdLength)); - writeOut(ZipEightByteInteger.getBytes(cdOffset)); - - // no "zip64 extensible data sector" for now - - // and now the "ZIP64 end of central directory locator" - writeOut(ZIP64_EOCD_LOC_SIG); - - // disk number holding the ZIP64 EOCD record - writeOut(LZERO); - // relative offset of ZIP64 EOCD record - writeOut(ZipEightByteInteger.getBytes(offset)); - // total number of disks - writeOut(ONE); - } - - /** - * Write bytes to output or random access file. - * @param data the byte array to write - * @throws IOException on error - */ - protected final void writeOut(final byte[] data) throws IOException { - streamCompressor.writeOut(data, 0, data.length); - } - - - /** - * Write bytes to output or random access file. - * @param data the byte array to write - * @param offset the start position to write from - * @param length the number of bytes to write - * @throws IOException on error - */ - protected final void writeOut(final byte[] data, final int offset, final int length) - throws IOException { - streamCompressor.writeOut(data, offset, length); - } - - - private GeneralPurposeBit getGeneralPurposeBits(final boolean utfFallback, boolean usesDataDescriptor) { - final GeneralPurposeBit b = new GeneralPurposeBit(); - b.useUTF8ForNames(useUTF8Flag || utfFallback); - if (usesDataDescriptor) { - b.useDataDescriptor(true); - } - return b; - } - - private int versionNeededToExtract(final int zipMethod, final boolean zip64, final boolean usedDataDescriptor) { - if (zip64) { - return ZIP64_MIN_VERSION; - } - if (usedDataDescriptor) { - return DATA_DESCRIPTOR_MIN_VERSION; - } - return versionNeededToExtractMethod(zipMethod); - } - - private boolean usesDataDescriptor(final int zipMethod, boolean phased) { - return !phased && zipMethod == DEFLATED && channel == null; - } - - private int versionNeededToExtractMethod(int zipMethod) { - return zipMethod == DEFLATED ? DEFLATE_MIN_VERSION : INITIAL_VERSION; - } - - /** - * Creates a new zip entry taking some information from the given - * file and using the provided name. - * - *

The name will be adjusted to end with a forward slash "/" if - * the file is a directory. If the file is not a directory a - * potential trailing forward slash will be stripped from the - * entry name.

- * - *

Must not be used if the stream has already been closed.

- */ - @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) - throws IOException { - if (finished) { - throw new IOException("Stream has already been finished"); - } - return new ZipArchiveEntry(inputFile, entryName); - } - - /** - * Get the existing ZIP64 extended information extra field or - * create a new one and add it to the entry. - * - * @since 1.3 - */ - private Zip64ExtendedInformationExtraField - getZip64Extra(final ZipArchiveEntry ze) { - if (entry != null) { - entry.causedUseOfZip64 = !hasUsedZip64; - } - hasUsedZip64 = true; - Zip64ExtendedInformationExtraField z64 = - (Zip64ExtendedInformationExtraField) - ze.getExtraField(Zip64ExtendedInformationExtraField - .HEADER_ID); - if (z64 == null) { - /* - System.err.println("Adding z64 for " + ze.getName() - + ", method: " + ze.getMethod() - + " (" + (ze.getMethod() == STORED) + ")" - + ", channel: " + (channel != null)); - */ - z64 = new Zip64ExtendedInformationExtraField(); - } - - // even if the field is there already, make sure it is the first one - ze.addAsFirstExtraField(z64); - - return z64; - } - - /** - * Is there a ZIP64 extended information extra field for the - * entry? - * - * @since 1.3 - */ - private boolean hasZip64Extra(final ZipArchiveEntry ze) { - return ze.getExtraField(Zip64ExtendedInformationExtraField - .HEADER_ID) - != null; - } - - /** - * If the mode is AsNeeded and the entry is a compressed entry of - * unknown size that gets written to a non-seekable stream then - * change the default to Never. - * - * @since 1.3 - */ - private Zip64Mode getEffectiveZip64Mode(final ZipArchiveEntry ze) { - if (zip64Mode != Zip64Mode.AsNeeded - || channel != null - || ze.getMethod() != DEFLATED - || ze.getSize() != ArchiveEntry.SIZE_UNKNOWN) { - return zip64Mode; - } - return Zip64Mode.Never; - } - - private ZipEncoding getEntryEncoding(final ZipArchiveEntry ze) { - final boolean encodable = zipEncoding.canEncode(ze.getName()); - return !encodable && fallbackToUTF8 - ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; - } - - private ByteBuffer getName(final ZipArchiveEntry ze) throws IOException { - return getEntryEncoding(ze).encode(ze.getName()); - } - - /** - * Closes the underlying stream/file without finishing the - * archive, the result will likely be a corrupt archive. - * - *

This method only exists to support tests that generate - * corrupt archives so they can clean up any temporary files.

- */ - void destroy() throws IOException { - if (channel != null) { - channel.close(); - } - if (out != null) { - out.close(); - } - } - - /** - * enum that represents the possible policies for creating Unicode - * extra fields. - */ - public static final class UnicodeExtraFieldPolicy { - /** - * Always create Unicode extra fields. - */ - public static final UnicodeExtraFieldPolicy ALWAYS = new UnicodeExtraFieldPolicy("always"); - /** - * Never create Unicode extra fields. - */ - public static final UnicodeExtraFieldPolicy NEVER = new UnicodeExtraFieldPolicy("never"); - /** - * Create Unicode extra fields for filenames that cannot be - * encoded using the specified encoding. - */ - public static final UnicodeExtraFieldPolicy NOT_ENCODEABLE = - new UnicodeExtraFieldPolicy("not encodeable"); - - private final String name; - private UnicodeExtraFieldPolicy(final String n) { - name = n; - } - @Override - public String toString() { - return name; - } - } - - /** - * Structure collecting information for the entry that is - * currently being written. - */ - private static final class CurrentEntry { - private CurrentEntry(final ZipArchiveEntry entry) { - this.entry = entry; - } - /** - * Current ZIP entry. - */ - private final ZipArchiveEntry entry; - /** - * Offset for CRC entry in the local file header data for the - * current entry starts here. - */ - private long localDataStart = 0; - /** - * Data for local header data - */ - private long dataStart = 0; - /** - * Number of bytes read for the current entry (can't rely on - * Deflater#getBytesRead) when using DEFLATED. - */ - private long bytesRead = 0; - /** - * Whether current entry was the first one using ZIP64 features. - */ - private boolean causedUseOfZip64 = false; - /** - * Whether write() has been called at all. - * - *

In order to create a valid archive {@link - * #closeArchiveEntry closeArchiveEntry} will write an empty - * array to get the CRC right if nothing has been written to - * the stream at all.

- */ - private boolean hasWritten; - } - - private static final class EntryMetaData { - private final long offset; - private final boolean usesDataDescriptor; - private EntryMetaData(long offset, boolean usesDataDescriptor) { - this.offset = offset; - this.usesDataDescriptor = usesDataDescriptor; - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipConstants.java b/src/org/apache/commons/compress/archivers/zip/ZipConstants.java deleted file mode 100644 index c230991a346..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipConstants.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -/** - * Various constants used throughout the package. - * - * @since 1.3 - */ -final class ZipConstants { - /** Masks last eight bits */ - static final int BYTE_MASK = 0xFF; - - /** length of a ZipShort in bytes */ - static final int SHORT = 2; - - /** length of a ZipLong in bytes */ - static final int WORD = 4; - - /** length of a ZipEightByteInteger in bytes */ - static final int DWORD = 8; - - /** Initial ZIP specification version */ - static final int INITIAL_VERSION = 10; - - /** - * ZIP specification version that introduced DEFLATE compression method. - * @since 1.15 - */ - static final int DEFLATE_MIN_VERSION = 20; - - /** ZIP specification version that introduced data descriptor method */ - static final int DATA_DESCRIPTOR_MIN_VERSION = 20; - - /** ZIP specification version that introduced ZIP64 */ - static final int ZIP64_MIN_VERSION = 45; - - /** - * Value stored in two-byte size and similar fields if ZIP64 - * extensions are used. - */ - static final int ZIP64_MAGIC_SHORT = 0xFFFF; - - /** - * Value stored in four-byte size and similar fields if ZIP64 - * extensions are used. - */ - static final long ZIP64_MAGIC = 0xFFFFFFFFL; - - private ZipConstants() { } - -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java b/src/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java deleted file mode 100644 index 9d9e2ec82bd..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipEightByteInteger.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.Serializable; -import java.math.BigInteger; - -import static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK; - -/** - * Utility class that represents an eight byte integer with conversion - * rules for the little endian byte order of ZIP files. - * @Immutable - * - * @since 1.2 - */ -public final class ZipEightByteInteger implements Serializable { - private static final long serialVersionUID = 1L; - - private static final int BYTE_1 = 1; - private static final int BYTE_1_MASK = 0xFF00; - private static final int BYTE_1_SHIFT = 8; - - private static final int BYTE_2 = 2; - private static final int BYTE_2_MASK = 0xFF0000; - private static final int BYTE_2_SHIFT = 16; - - private static final int BYTE_3 = 3; - private static final long BYTE_3_MASK = 0xFF000000L; - private static final int BYTE_3_SHIFT = 24; - - private static final int BYTE_4 = 4; - private static final long BYTE_4_MASK = 0xFF00000000L; - private static final int BYTE_4_SHIFT = 32; - - private static final int BYTE_5 = 5; - private static final long BYTE_5_MASK = 0xFF0000000000L; - private static final int BYTE_5_SHIFT = 40; - - private static final int BYTE_6 = 6; - private static final long BYTE_6_MASK = 0xFF000000000000L; - private static final int BYTE_6_SHIFT = 48; - - private static final int BYTE_7 = 7; - private static final long BYTE_7_MASK = 0x7F00000000000000L; - private static final int BYTE_7_SHIFT = 56; - - private static final int LEFTMOST_BIT_SHIFT = 63; - private static final byte LEFTMOST_BIT = (byte) 0x80; - - private final BigInteger value; - - public static final ZipEightByteInteger ZERO = new ZipEightByteInteger(0); - - /** - * Create instance from a number. - * @param value the long to store as a ZipEightByteInteger - */ - public ZipEightByteInteger(final long value) { - this(BigInteger.valueOf(value)); - } - - /** - * Create instance from a number. - * @param value the BigInteger to store as a ZipEightByteInteger - */ - public ZipEightByteInteger(final BigInteger value) { - this.value = value; - } - - /** - * Create instance from bytes. - * @param bytes the bytes to store as a ZipEightByteInteger - */ - public ZipEightByteInteger (final byte[] bytes) { - this(bytes, 0); - } - - /** - * Create instance from the eight bytes starting at offset. - * @param bytes the bytes to store as a ZipEightByteInteger - * @param offset the offset to start - */ - public ZipEightByteInteger (final byte[] bytes, final int offset) { - value = ZipEightByteInteger.getValue(bytes, offset); - } - - /** - * Get value as eight bytes in big endian byte order. - * @return value as eight bytes in big endian order - */ - public byte[] getBytes() { - return ZipEightByteInteger.getBytes(value); - } - - /** - * Get value as Java long. - * @return value as a long - */ - public long getLongValue() { - return value.longValue(); - } - - /** - * Get value as Java long. - * @return value as a long - */ - public BigInteger getValue() { - return value; - } - - /** - * Get value as eight bytes in big endian byte order. - * @param value the value to convert - * @return value as eight bytes in big endian byte order - */ - public static byte[] getBytes(final long value) { - return getBytes(BigInteger.valueOf(value)); - } - - /** - * Get value as eight bytes in big endian byte order. - * @param value the value to convert - * @return value as eight bytes in big endian byte order - */ - public static byte[] getBytes(final BigInteger value) { - final byte[] result = new byte[8]; - final long val = value.longValue(); - result[0] = (byte) ((val & BYTE_MASK)); - result[BYTE_1] = (byte) ((val & BYTE_1_MASK) >> BYTE_1_SHIFT); - result[BYTE_2] = (byte) ((val & BYTE_2_MASK) >> BYTE_2_SHIFT); - result[BYTE_3] = (byte) ((val & BYTE_3_MASK) >> BYTE_3_SHIFT); - result[BYTE_4] = (byte) ((val & BYTE_4_MASK) >> BYTE_4_SHIFT); - result[BYTE_5] = (byte) ((val & BYTE_5_MASK) >> BYTE_5_SHIFT); - result[BYTE_6] = (byte) ((val & BYTE_6_MASK) >> BYTE_6_SHIFT); - result[BYTE_7] = (byte) ((val & BYTE_7_MASK) >> BYTE_7_SHIFT); - if (value.testBit(LEFTMOST_BIT_SHIFT)) { - result[BYTE_7] |= LEFTMOST_BIT; - } - return result; - } - - /** - * Helper method to get the value as a Java long from eight bytes - * starting at given array offset - * @param bytes the array of bytes - * @param offset the offset to start - * @return the corresponding Java long value - */ - public static long getLongValue(final byte[] bytes, final int offset) { - return getValue(bytes, offset).longValue(); - } - - /** - * Helper method to get the value as a Java BigInteger from eight - * bytes starting at given array offset - * @param bytes the array of bytes - * @param offset the offset to start - * @return the corresponding Java BigInteger value - */ - public static BigInteger getValue(final byte[] bytes, final int offset) { - long value = ((long) bytes[offset + BYTE_7] << BYTE_7_SHIFT) & BYTE_7_MASK; - value += ((long) bytes[offset + BYTE_6] << BYTE_6_SHIFT) & BYTE_6_MASK; - value += ((long) bytes[offset + BYTE_5] << BYTE_5_SHIFT) & BYTE_5_MASK; - value += ((long) bytes[offset + BYTE_4] << BYTE_4_SHIFT) & BYTE_4_MASK; - value += ((long) bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK; - value += ((long) bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK; - value += ((long) bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK; - value += ((long) bytes[offset] & BYTE_MASK); - final BigInteger val = BigInteger.valueOf(value); - return (bytes[offset + BYTE_7] & LEFTMOST_BIT) == LEFTMOST_BIT - ? val.setBit(LEFTMOST_BIT_SHIFT) : val; - } - - /** - * Helper method to get the value as a Java long from an eight-byte array - * @param bytes the array of bytes - * @return the corresponding Java long value - */ - public static long getLongValue(final byte[] bytes) { - return getLongValue(bytes, 0); - } - - /** - * Helper method to get the value as a Java long from an eight-byte array - * @param bytes the array of bytes - * @return the corresponding Java BigInteger value - */ - public static BigInteger getValue(final byte[] bytes) { - return getValue(bytes, 0); - } - - /** - * Override to make two instances with same value equal. - * @param o an object to compare - * @return true if the objects are equal - */ - @Override - public boolean equals(final Object o) { - if (o == null || !(o instanceof ZipEightByteInteger)) { - return false; - } - return value.equals(((ZipEightByteInteger) o).getValue()); - } - - /** - * Override to make two instances with same value equal. - * @return the hashCode of the value stored in the ZipEightByteInteger - */ - @Override - public int hashCode() { - return value.hashCode(); - } - - @Override - public String toString() { - return "ZipEightByteInteger value: " + value; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipEncoding.java b/src/org/apache/commons/compress/archivers/zip/ZipEncoding.java deleted file mode 100644 index dacd063699e..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipEncoding.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.archivers.zip; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * An interface for encoders that do a pretty encoding of ZIP - * filenames. - * - *

There are mostly two implementations, one that uses java.nio - * {@link java.nio.charset.Charset Charset} and one implementation, - * which copes with simple 8 bit charsets, because java-1.4 did not - * support Cp437 in java.nio.

- * - *

The main reason for defining an own encoding layer comes from - * the problems with {@link java.lang.String#getBytes(String) - * String.getBytes}, which encodes unknown characters as ASCII - * quotation marks ('?'). Quotation marks are per definition an - * invalid filename on some operating systems like Windows, which - * leads to ignored ZIP entries.

- * - *

All implementations should implement this interface in a - * reentrant way.

- */ -public interface ZipEncoding { - /** - * Check, whether the given string may be losslessly encoded using this - * encoding. - * - * @param name A filename or ZIP comment. - * @return Whether the given name may be encoded with out any losses. - */ - boolean canEncode(String name); - - /** - * Encode a filename or a comment to a byte array suitable for - * storing it to a serialized zip entry. - * - *

Examples for CP 437 (in pseudo-notation, right hand side is - * C-style notation):

- *
-     *  encode("\u20AC_for_Dollar.txt") = "%U20AC_for_Dollar.txt"
-     *  encode("\u00D6lf\u00E4sser.txt") = "\231lf\204sser.txt"
-     * 
- * - * @param name A filename or ZIP comment. - * @return A byte buffer with a backing array containing the - * encoded name. Unmappable characters or malformed - * character sequences are mapped to a sequence of utf-16 - * words encoded in the format %Uxxxx. It is - * assumed, that the byte buffer is positioned at the - * beginning of the encoded result, the byte buffer has a - * backing array and the limit of the byte buffer points - * to the end of the encoded result. - * @throws IOException on error - */ - ByteBuffer encode(String name) throws IOException; - - /** - * @param data The byte values to decode. - * @return The decoded string. - * @throws IOException on error - */ - String decode(byte [] data) throws IOException; -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipEncodingHelper.java b/src/org/apache/commons/compress/archivers/zip/ZipEncodingHelper.java deleted file mode 100644 index 8aeb789e207..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipEncodingHelper.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.archivers.zip; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.charset.UnsupportedCharsetException; - -/** - * Static helper functions for robustly encoding filenames in zip files. - */ -public abstract class ZipEncodingHelper { - - - /** - * name of the encoding UTF-8 - */ - static final String UTF8 = "UTF8"; - - /** - * the encoding UTF-8 - */ - static final ZipEncoding UTF8_ZIP_ENCODING = getZipEncoding(UTF8); - - /** - * Instantiates a zip encoding. An NIO based character set encoder/decoder will be returned. - * As a special case, if the character set is UTF-8, the nio encoder will be configured replace malformed and - * unmappable characters with '?'. This matches existing behavior from the older fallback encoder. - *

- * If the requested characer set cannot be found, the platform default will - * be used instead. - *

- * @param name The name of the zip encoding. Specify {@code null} for - * the platform's default encoding. - * @return A zip encoding for the given encoding name. - */ - public static ZipEncoding getZipEncoding(final String name) { - Charset cs = Charset.defaultCharset(); - if (name != null) { - try { - cs = Charset.forName(name); - } catch (UnsupportedCharsetException e) { // NOSONAR we use the default encoding instead - } - } - boolean useReplacement = isUTF8(cs.name()); - return new NioZipEncoding(cs, useReplacement); - } - - /** - * Returns whether a given encoding is UTF-8. If the given name is null, then check the platform's default encoding. - * - * @param charsetName If the given name is null, then check the platform's default encoding. - */ - static boolean isUTF8(String charsetName) { - if (charsetName == null) { - // check platform's default encoding - charsetName = Charset.defaultCharset().name(); - } - if (StandardCharsets.UTF_8.name().equalsIgnoreCase(charsetName)) { - return true; - } - for (final String alias : StandardCharsets.UTF_8.aliases()) { - if (alias.equalsIgnoreCase(charsetName)) { - return true; - } - } - return false; - } - - static ByteBuffer growBufferBy(ByteBuffer buffer, int increment) { - buffer.limit(buffer.position()); - buffer.rewind(); - - final ByteBuffer on = ByteBuffer.allocate(buffer.capacity() + increment); - - on.put(buffer); - return on; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipExtraField.java b/src/org/apache/commons/compress/archivers/zip/ZipExtraField.java deleted file mode 100644 index 2c44b2a52da..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipExtraField.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.zip.ZipException; - -/** - * General format of extra field data. - * - *

Extra fields usually appear twice per file, once in the local - * file data and once in the central directory. Usually they are the - * same, but they don't have to be. {@link - * java.util.zip.ZipOutputStream java.util.zip.ZipOutputStream} will - * only use the local file data in both places.

- * - */ -public interface ZipExtraField { - /** - * Size of an extra field field header (id + length). - * @since 1.14 - */ - int EXTRAFIELD_HEADER_SIZE = 4; - - /** - * The Header-ID. - * - * @return The HeaderId value - */ - ZipShort getHeaderId(); - - /** - * Length of the extra field in the local file data - without - * Header-ID or length specifier. - * @return the length of the field in the local file data - */ - ZipShort getLocalFileDataLength(); - - /** - * Length of the extra field in the central directory - without - * Header-ID or length specifier. - * @return the length of the field in the central directory - */ - ZipShort getCentralDirectoryLength(); - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * @return the data - */ - byte[] getLocalFileDataData(); - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * @return the data - */ - byte[] getCentralDirectoryData(); - - /** - * Populate data from this array as if it was in local file data. - * - * @param buffer the buffer to read data from - * @param offset offset into buffer to read data - * @param length the length of data - * @throws ZipException on error - */ - void parseFromLocalFileData(byte[] buffer, int offset, int length) - throws ZipException; - - /** - * Populate data from this array as if it was in central directory data. - * - * @param buffer the buffer to read data from - * @param offset offset into buffer to read data - * @param length the length of data - * @throws ZipException on error - */ - void parseFromCentralDirectoryData(byte[] buffer, int offset, int length) - throws ZipException; -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipFile.java b/src/org/apache/commons/compress/archivers/zip/ZipFile.java deleted file mode 100644 index 6beedcb52d2..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipFile.java +++ /dev/null @@ -1,1278 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.Closeable; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.SequenceInputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.zip.Inflater; -import java.util.zip.ZipException; - -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; -import org.apache.commons.compress.compressors.deflate64.Deflate64CompressorInputStream; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD; -import static org.apache.commons.compress.archivers.zip.ZipConstants.SHORT; -import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD; -import static org.apache.commons.compress.archivers.zip.ZipConstants.ZIP64_MAGIC; -import static org.apache.commons.compress.archivers.zip.ZipConstants.ZIP64_MAGIC_SHORT; - -/** - * Replacement for java.util.ZipFile. - * - *

This class adds support for file name encodings other than UTF-8 - * (which is required to work on ZIP files created by native zip tools - * and is able to skip a preamble like the one found in self - * extracting archives. Furthermore it returns instances of - * org.apache.commons.compress.archivers.zip.ZipArchiveEntry - * instead of java.util.zip.ZipEntry.

- * - *

It doesn't extend java.util.zip.ZipFile as it would - * have to reimplement all methods anyway. Like - * java.util.ZipFile, it uses SeekableByteChannel under the - * covers and supports compressed and uncompressed entries. As of - * Apache Commons Compress 1.3 it also transparently supports Zip64 - * extensions and thus individual entries and archives larger than 4 - * GB or with more than 65536 entries.

- * - *

The method signatures mimic the ones of - * java.util.zip.ZipFile, with a couple of exceptions: - * - *

    - *
  • There is no getName method.
  • - *
  • entries has been renamed to getEntries.
  • - *
  • getEntries and getEntry return - * org.apache.commons.compress.archivers.zip.ZipArchiveEntry - * instances.
  • - *
  • close is allowed to throw IOException.
  • - *
- * - */ -public class ZipFile implements Closeable { - private static final int HASH_SIZE = 509; - static final int NIBLET_MASK = 0x0f; - static final int BYTE_SHIFT = 8; - private static final int POS_0 = 0; - private static final int POS_1 = 1; - private static final int POS_2 = 2; - private static final int POS_3 = 3; - private static final byte[] ONE_ZERO_BYTE = new byte[1]; - - /** - * List of entries in the order they appear inside the central - * directory. - */ - private final List entries = - new LinkedList<>(); - - /** - * Maps String to list of ZipArchiveEntrys, name -> actual entries. - */ - private final Map> nameMap = - new HashMap<>(HASH_SIZE); - - /** - * The encoding to use for filenames and the file comment. - * - *

For a list of possible values see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html. - * Defaults to UTF-8.

- */ - private final String encoding; - - /** - * The zip encoding to use for filenames and the file comment. - */ - private final ZipEncoding zipEncoding; - - /** - * File name of actual source. - */ - private final String archiveName; - - /** - * The actual data source. - */ - private final SeekableByteChannel archive; - - /** - * Whether to look for and use Unicode extra fields. - */ - private final boolean useUnicodeExtraFields; - - /** - * Whether the file is closed. - */ - private volatile boolean closed = true; - - // cached buffers - must only be used locally in the class (COMPRESS-172 - reduce garbage collection) - private final byte[] dwordBuf = new byte[DWORD]; - private final byte[] wordBuf = new byte[WORD]; - private final byte[] cfhBuf = new byte[CFH_LEN]; - private final byte[] shortBuf = new byte[SHORT]; - private final ByteBuffer dwordBbuf = ByteBuffer.wrap(dwordBuf); - private final ByteBuffer wordBbuf = ByteBuffer.wrap(wordBuf); - private final ByteBuffer cfhBbuf = ByteBuffer.wrap(cfhBuf); - - /** - * Opens the given file for reading, assuming "UTF8" for file names. - * - * @param f the archive. - * - * @throws IOException if an error occurs while reading the file. - */ - public ZipFile(final File f) throws IOException { - this(f, ZipEncodingHelper.UTF8); - } - - /** - * Opens the given file for reading, assuming "UTF8". - * - * @param name name of the archive. - * - * @throws IOException if an error occurs while reading the file. - */ - public ZipFile(final String name) throws IOException { - this(new File(name), ZipEncodingHelper.UTF8); - } - - /** - * Opens the given file for reading, assuming the specified - * encoding for file names, scanning unicode extra fields. - * - * @param name name of the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * - * @throws IOException if an error occurs while reading the file. - */ - public ZipFile(final String name, final String encoding) throws IOException { - this(new File(name), encoding, true); - } - - /** - * Opens the given file for reading, assuming the specified - * encoding for file names and scanning for unicode extra fields. - * - * @param f the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * - * @throws IOException if an error occurs while reading the file. - */ - public ZipFile(final File f, final String encoding) throws IOException { - this(f, encoding, true); - } - - /** - * Opens the given file for reading, assuming the specified - * encoding for file names. - * - * @param f the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. - * - * @throws IOException if an error occurs while reading the file. - */ - public ZipFile(final File f, final String encoding, final boolean useUnicodeExtraFields) - throws IOException { - this(Files.newByteChannel(f.toPath(), EnumSet.of(StandardOpenOption.READ)), - f.getAbsolutePath(), encoding, useUnicodeExtraFields, true); - } - - /** - * Opens the given channel for reading, assuming "UTF8" for file names. - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the archive. - * - * @throws IOException if an error occurs while reading the file. - * @since 1.13 - */ - public ZipFile(final SeekableByteChannel channel) - throws IOException { - this(channel, "unknown archive", ZipEncodingHelper.UTF8, true); - } - - /** - * Opens the given channel for reading, assuming the specified - * encoding for file names. - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * - * @throws IOException if an error occurs while reading the file. - * @since 1.13 - */ - public ZipFile(final SeekableByteChannel channel, final String encoding) - throws IOException { - this(channel, "unknown archive", encoding, true); - } - - /** - * Opens the given channel for reading, assuming the specified - * encoding for file names. - * - *

{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.

- * - * @param channel the archive. - * @param archiveName name of the archive, used for error messages only. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. - * - * @throws IOException if an error occurs while reading the file. - * @since 1.13 - */ - public ZipFile(final SeekableByteChannel channel, final String archiveName, - final String encoding, final boolean useUnicodeExtraFields) - throws IOException { - this(channel, archiveName, encoding, useUnicodeExtraFields, false); - } - - private ZipFile(final SeekableByteChannel channel, final String archiveName, - final String encoding, final boolean useUnicodeExtraFields, - final boolean closeOnError) - throws IOException { - this.archiveName = archiveName; - this.encoding = encoding; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); - this.useUnicodeExtraFields = useUnicodeExtraFields; - archive = channel; - boolean success = false; - try { - final Map entriesWithoutUTF8Flag = - populateFromCentralDirectory(); - resolveLocalFileHeaderData(entriesWithoutUTF8Flag); - success = true; - } finally { - closed = !success; - if (!success && closeOnError) { - IOUtils.closeQuietly(archive); - } - } - } - - /** - * The encoding to use for filenames and the file comment. - * - * @return null if using the platform's default character encoding. - */ - public String getEncoding() { - return encoding; - } - - /** - * Closes the archive. - * @throws IOException if an error occurs closing the archive. - */ - @Override - public void close() throws IOException { - // this flag is only written here and read in finalize() which - // can never be run in parallel. - // no synchronization needed. - closed = true; - - archive.close(); - } - - /** - * close a zipfile quietly; throw no io fault, do nothing - * on a null parameter - * @param zipfile file to close, can be null - */ - public static void closeQuietly(final ZipFile zipfile) { - IOUtils.closeQuietly(zipfile); - } - - /** - * Returns all entries. - * - *

Entries will be returned in the same order they appear - * within the archive's central directory.

- * - * @return all entries as {@link ZipArchiveEntry} instances - */ - public Enumeration getEntries() { - return Collections.enumeration(entries); - } - - /** - * Returns all entries in physical order. - * - *

Entries will be returned in the same order their contents - * appear within the archive.

- * - * @return all entries as {@link ZipArchiveEntry} instances - * - * @since 1.1 - */ - public Enumeration getEntriesInPhysicalOrder() { - final ZipArchiveEntry[] allEntries = entries.toArray(new ZipArchiveEntry[entries.size()]); - Arrays.sort(allEntries, offsetComparator); - return Collections.enumeration(Arrays.asList(allEntries)); - } - - /** - * Returns a named entry - or {@code null} if no entry by - * that name exists. - * - *

If multiple entries with the same name exist the first entry - * in the archive's central directory by that name is - * returned.

- * - * @param name name of the entry. - * @return the ZipArchiveEntry corresponding to the given name - or - * {@code null} if not present. - */ - public ZipArchiveEntry getEntry(final String name) { - final LinkedList entriesOfThatName = nameMap.get(name); - return entriesOfThatName != null ? entriesOfThatName.getFirst() : null; - } - - /** - * Returns all named entries in the same order they appear within - * the archive's central directory. - * - * @param name name of the entry. - * @return the Iterable<ZipArchiveEntry> corresponding to the - * given name - * @since 1.6 - */ - public Iterable getEntries(final String name) { - final List entriesOfThatName = nameMap.get(name); - return entriesOfThatName != null ? entriesOfThatName - : Collections.emptyList(); - } - - /** - * Returns all named entries in the same order their contents - * appear within the archive. - * - * @param name name of the entry. - * @return the Iterable<ZipArchiveEntry> corresponding to the - * given name - * @since 1.6 - */ - public Iterable getEntriesInPhysicalOrder(final String name) { - ZipArchiveEntry[] entriesOfThatName = new ZipArchiveEntry[0]; - if (nameMap.containsKey(name)) { - entriesOfThatName = nameMap.get(name).toArray(entriesOfThatName); - Arrays.sort(entriesOfThatName, offsetComparator); - } - return Arrays.asList(entriesOfThatName); - } - - /** - * Whether this class is able to read the given entry. - * - *

May return false if it is set up to use encryption or a - * compression method that hasn't been implemented yet.

- * @since 1.1 - * @param ze the entry - * @return whether this class is able to read the given entry. - */ - public boolean canReadEntryData(final ZipArchiveEntry ze) { - return ZipUtil.canHandleEntryData(ze); - } - - /** - * Expose the raw stream of the archive entry (compressed form). - * - *

This method does not relate to how/if we understand the payload in the - * stream, since we really only intend to move it on to somewhere else.

- * - * @param ze The entry to get the stream for - * @return The raw input stream containing (possibly) compressed data. - * @since 1.11 - */ - public InputStream getRawInputStream(final ZipArchiveEntry ze) { - if (!(ze instanceof Entry)) { - return null; - } - final long start = ze.getDataOffset(); - return createBoundedInputStream(start, ze.getCompressedSize()); - } - - - /** - * Transfer selected entries from this zipfile to a given #ZipArchiveOutputStream. - * Compression and all other attributes will be as in this file. - *

This method transfers entries based on the central directory of the zip file.

- * - * @param target The zipArchiveOutputStream to write the entries to - * @param predicate A predicate that selects which entries to write - * @throws IOException on error - */ - public void copyRawEntries(final ZipArchiveOutputStream target, final ZipArchiveEntryPredicate predicate) - throws IOException { - final Enumeration src = getEntriesInPhysicalOrder(); - while (src.hasMoreElements()) { - final ZipArchiveEntry entry = src.nextElement(); - if (predicate.test( entry)) { - target.addRawArchiveEntry(entry, getRawInputStream(entry)); - } - } - } - - /** - * Returns an InputStream for reading the contents of the given entry. - * - * @param ze the entry to get the stream for. - * @return a stream to read the entry from. The returned stream - * implements {@link InputStreamStatistics}. - * @throws IOException if unable to create an input stream from the zipentry - */ - public InputStream getInputStream(final ZipArchiveEntry ze) - throws IOException { - if (!(ze instanceof Entry)) { - return null; - } - // cast validity is checked just above - ZipUtil.checkRequestedFeatures(ze); - final long start = ze.getDataOffset(); - - // doesn't get closed if the method is not supported - which - // should never happen because of the checkRequestedFeatures - // call above - final InputStream is = - new BufferedInputStream(createBoundedInputStream(start, ze.getCompressedSize())); //NOSONAR - switch (ZipMethod.getMethodByCode(ze.getMethod())) { - case STORED: - return new StoredStatisticsStream(is); - case UNSHRINKING: - return new UnshrinkingInputStream(is); - case IMPLODING: - return new ExplodingInputStream(ze.getGeneralPurposeBit().getSlidingDictionarySize(), - ze.getGeneralPurposeBit().getNumberOfShannonFanoTrees(), is); - case DEFLATED: - final Inflater inflater = new Inflater(true); - // Inflater with nowrap=true has this odd contract for a zero padding - // byte following the data stream; this used to be zlib's requirement - // and has been fixed a long time ago, but the contract persists so - // we comply. - // https://docs.oracle.com/javase/7/docs/api/java/util/zip/Inflater.html#Inflater(boolean) - return new InflaterInputStreamWithStatistics(new SequenceInputStream(is, new ByteArrayInputStream(ONE_ZERO_BYTE)), - inflater) { - @Override - public void close() throws IOException { - try { - super.close(); - } finally { - inflater.end(); - } - } - }; - case BZIP2: - return new BZip2CompressorInputStream(is); - case ENHANCED_DEFLATED: - return new Deflate64CompressorInputStream(is); - case AES_ENCRYPTED: - case EXPANDING_LEVEL_1: - case EXPANDING_LEVEL_2: - case EXPANDING_LEVEL_3: - case EXPANDING_LEVEL_4: - case JPEG: - case LZMA: - case PKWARE_IMPLODING: - case PPMD: - case TOKENIZATION: - case UNKNOWN: - case WAVPACK: - case XZ: - default: - throw new ZipException("Found unsupported compression method " - + ze.getMethod()); - } - } - - /** - *

- * Convenience method to return the entry's content as a String if isUnixSymlink() - * returns true for it, otherwise returns null. - *

- * - *

This method assumes the symbolic link's file name uses the - * same encoding that as been specified for this ZipFile.

- * - * @param entry ZipArchiveEntry object that represents the symbolic link - * @return entry's content as a String - * @throws IOException problem with content's input stream - * @since 1.5 - */ - public String getUnixSymlink(final ZipArchiveEntry entry) throws IOException { - if (entry != null && entry.isUnixSymlink()) { - try (InputStream in = getInputStream(entry)) { - return zipEncoding.decode(IOUtils.toByteArray(in)); - } - } - return null; - } - - /** - * Ensures that the close method of this zipfile is called when - * there are no more references to it. - * @see #close() - */ - @Override - protected void finalize() throws Throwable { - try { - if (!closed) { - System.err.println("Cleaning up unclosed ZipFile for archive " - + archiveName); - close(); - } - } finally { - super.finalize(); - } - } - - /** - * Length of a "central directory" entry structure without file - * name, extra fields or comment. - */ - private static final int CFH_LEN = - /* version made by */ SHORT - /* version needed to extract */ + SHORT - /* general purpose bit flag */ + SHORT - /* compression method */ + SHORT - /* last mod file time */ + SHORT - /* last mod file date */ + SHORT - /* crc-32 */ + WORD - /* compressed size */ + WORD - /* uncompressed size */ + WORD - /* filename length */ + SHORT - /* extra field length */ + SHORT - /* file comment length */ + SHORT - /* disk number start */ + SHORT - /* internal file attributes */ + SHORT - /* external file attributes */ + WORD - /* relative offset of local header */ + WORD; - - private static final long CFH_SIG = - ZipLong.getValue(ZipArchiveOutputStream.CFH_SIG); - - /** - * Reads the central directory of the given archive and populates - * the internal tables with ZipArchiveEntry instances. - * - *

The ZipArchiveEntrys will know all data that can be obtained from - * the central directory alone, but not the data that requires the - * local file header or additional data to be read.

- * - * @return a map of zipentries that didn't have the language - * encoding flag set when read. - */ - private Map populateFromCentralDirectory() - throws IOException { - final HashMap noUTF8Flag = - new HashMap<>(); - - positionAtCentralDirectory(); - - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - long sig = ZipLong.getValue(wordBuf); - - if (sig != CFH_SIG && startsWithLocalFileHeader()) { - throw new IOException("central directory is empty, can't expand" - + " corrupt archive."); - } - - while (sig == CFH_SIG) { - readCentralDirectoryEntry(noUTF8Flag); - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - sig = ZipLong.getValue(wordBuf); - } - return noUTF8Flag; - } - - /** - * Reads an individual entry of the central directory, creats an - * ZipArchiveEntry from it and adds it to the global maps. - * - * @param noUTF8Flag map used to collect entries that don't have - * their UTF-8 flag set and whose name will be set by data read - * from the local file header later. The current entry may be - * added to this map. - */ - private void - readCentralDirectoryEntry(final Map noUTF8Flag) - throws IOException { - cfhBbuf.rewind(); - IOUtils.readFully(archive, cfhBbuf); - int off = 0; - final Entry ze = new Entry(); - - final int versionMadeBy = ZipShort.getValue(cfhBuf, off); - off += SHORT; - ze.setVersionMadeBy(versionMadeBy); - ze.setPlatform((versionMadeBy >> BYTE_SHIFT) & NIBLET_MASK); - - ze.setVersionRequired(ZipShort.getValue(cfhBuf, off)); - off += SHORT; // version required - - final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(cfhBuf, off); - final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames(); - final ZipEncoding entryEncoding = - hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; - if (hasUTF8Flag) { - ze.setNameSource(ZipArchiveEntry.NameSource.NAME_WITH_EFS_FLAG); - } - ze.setGeneralPurposeBit(gpFlag); - ze.setRawFlag(ZipShort.getValue(cfhBuf, off)); - - off += SHORT; - - //noinspection MagicConstant - ze.setMethod(ZipShort.getValue(cfhBuf, off)); - off += SHORT; - - final long time = ZipUtil.dosToJavaTime(ZipLong.getValue(cfhBuf, off)); - ze.setTime(time); - off += WORD; - - ze.setCrc(ZipLong.getValue(cfhBuf, off)); - off += WORD; - - ze.setCompressedSize(ZipLong.getValue(cfhBuf, off)); - off += WORD; - - ze.setSize(ZipLong.getValue(cfhBuf, off)); - off += WORD; - - final int fileNameLen = ZipShort.getValue(cfhBuf, off); - off += SHORT; - - final int extraLen = ZipShort.getValue(cfhBuf, off); - off += SHORT; - - final int commentLen = ZipShort.getValue(cfhBuf, off); - off += SHORT; - - final int diskStart = ZipShort.getValue(cfhBuf, off); - off += SHORT; - - ze.setInternalAttributes(ZipShort.getValue(cfhBuf, off)); - off += SHORT; - - ze.setExternalAttributes(ZipLong.getValue(cfhBuf, off)); - off += WORD; - - final byte[] fileName = new byte[fileNameLen]; - IOUtils.readFully(archive, ByteBuffer.wrap(fileName)); - ze.setName(entryEncoding.decode(fileName), fileName); - - // LFH offset, - ze.setLocalHeaderOffset(ZipLong.getValue(cfhBuf, off)); - // data offset will be filled later - entries.add(ze); - - final byte[] cdExtraData = new byte[extraLen]; - IOUtils.readFully(archive, ByteBuffer.wrap(cdExtraData)); - ze.setCentralDirectoryExtra(cdExtraData); - - setSizesAndOffsetFromZip64Extra(ze, diskStart); - - final byte[] comment = new byte[commentLen]; - IOUtils.readFully(archive, ByteBuffer.wrap(comment)); - ze.setComment(entryEncoding.decode(comment)); - - if (!hasUTF8Flag && useUnicodeExtraFields) { - noUTF8Flag.put(ze, new NameAndComment(fileName, comment)); - } - } - - /** - * If the entry holds a Zip64 extended information extra field, - * read sizes from there if the entry's sizes are set to - * 0xFFFFFFFFF, do the same for the offset of the local file - * header. - * - *

Ensures the Zip64 extra either knows both compressed and - * uncompressed size or neither of both as the internal logic in - * ExtraFieldUtils forces the field to create local header data - * even if they are never used - and here a field with only one - * size would be invalid.

- */ - private void setSizesAndOffsetFromZip64Extra(final ZipArchiveEntry ze, - final int diskStart) - throws IOException { - final Zip64ExtendedInformationExtraField z64 = - (Zip64ExtendedInformationExtraField) - ze.getExtraField(Zip64ExtendedInformationExtraField.HEADER_ID); - if (z64 != null) { - final boolean hasUncompressedSize = ze.getSize() == ZIP64_MAGIC; - final boolean hasCompressedSize = ze.getCompressedSize() == ZIP64_MAGIC; - final boolean hasRelativeHeaderOffset = - ze.getLocalHeaderOffset() == ZIP64_MAGIC; - z64.reparseCentralDirectoryData(hasUncompressedSize, - hasCompressedSize, - hasRelativeHeaderOffset, - diskStart == ZIP64_MAGIC_SHORT); - - if (hasUncompressedSize) { - ze.setSize(z64.getSize().getLongValue()); - } else if (hasCompressedSize) { - z64.setSize(new ZipEightByteInteger(ze.getSize())); - } - - if (hasCompressedSize) { - ze.setCompressedSize(z64.getCompressedSize().getLongValue()); - } else if (hasUncompressedSize) { - z64.setCompressedSize(new ZipEightByteInteger(ze.getCompressedSize())); - } - - if (hasRelativeHeaderOffset) { - ze.setLocalHeaderOffset(z64.getRelativeHeaderOffset().getLongValue()); - } - } - } - - /** - * Length of the "End of central directory record" - which is - * supposed to be the last structure of the archive - without file - * comment. - */ - static final int MIN_EOCD_SIZE = - /* end of central dir signature */ WORD - /* number of this disk */ + SHORT - /* number of the disk with the */ - /* start of the central directory */ + SHORT - /* total number of entries in */ - /* the central dir on this disk */ + SHORT - /* total number of entries in */ - /* the central dir */ + SHORT - /* size of the central directory */ + WORD - /* offset of start of central */ - /* directory with respect to */ - /* the starting disk number */ + WORD - /* zipfile comment length */ + SHORT; - - /** - * Maximum length of the "End of central directory record" with a - * file comment. - */ - private static final int MAX_EOCD_SIZE = MIN_EOCD_SIZE - /* maximum length of zipfile comment */ + ZIP64_MAGIC_SHORT; - - /** - * Offset of the field that holds the location of the first - * central directory entry inside the "End of central directory - * record" relative to the start of the "End of central directory - * record". - */ - private static final int CFD_LOCATOR_OFFSET = - /* end of central dir signature */ WORD - /* number of this disk */ + SHORT - /* number of the disk with the */ - /* start of the central directory */ + SHORT - /* total number of entries in */ - /* the central dir on this disk */ + SHORT - /* total number of entries in */ - /* the central dir */ + SHORT - /* size of the central directory */ + WORD; - - /** - * Length of the "Zip64 end of central directory locator" - which - * should be right in front of the "end of central directory - * record" if one is present at all. - */ - private static final int ZIP64_EOCDL_LENGTH = - /* zip64 end of central dir locator sig */ WORD - /* number of the disk with the start */ - /* start of the zip64 end of */ - /* central directory */ + WORD - /* relative offset of the zip64 */ - /* end of central directory record */ + DWORD - /* total number of disks */ + WORD; - - /** - * Offset of the field that holds the location of the "Zip64 end - * of central directory record" inside the "Zip64 end of central - * directory locator" relative to the start of the "Zip64 end of - * central directory locator". - */ - private static final int ZIP64_EOCDL_LOCATOR_OFFSET = - /* zip64 end of central dir locator sig */ WORD - /* number of the disk with the start */ - /* start of the zip64 end of */ - /* central directory */ + WORD; - - /** - * Offset of the field that holds the location of the first - * central directory entry inside the "Zip64 end of central - * directory record" relative to the start of the "Zip64 end of - * central directory record". - */ - private static final int ZIP64_EOCD_CFD_LOCATOR_OFFSET = - /* zip64 end of central dir */ - /* signature */ WORD - /* size of zip64 end of central */ - /* directory record */ + DWORD - /* version made by */ + SHORT - /* version needed to extract */ + SHORT - /* number of this disk */ + WORD - /* number of the disk with the */ - /* start of the central directory */ + WORD - /* total number of entries in the */ - /* central directory on this disk */ + DWORD - /* total number of entries in the */ - /* central directory */ + DWORD - /* size of the central directory */ + DWORD; - - /** - * Searches for either the "Zip64 end of central directory - * locator" or the "End of central dir record", parses - * it and positions the stream at the first central directory - * record. - */ - private void positionAtCentralDirectory() - throws IOException { - positionAtEndOfCentralDirectoryRecord(); - boolean found = false; - final boolean searchedForZip64EOCD = - archive.position() > ZIP64_EOCDL_LENGTH; - if (searchedForZip64EOCD) { - archive.position(archive.position() - ZIP64_EOCDL_LENGTH); - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - found = Arrays.equals(ZipArchiveOutputStream.ZIP64_EOCD_LOC_SIG, - wordBuf); - } - if (!found) { - // not a ZIP64 archive - if (searchedForZip64EOCD) { - skipBytes(ZIP64_EOCDL_LENGTH - WORD); - } - positionAtCentralDirectory32(); - } else { - positionAtCentralDirectory64(); - } - } - - /** - * Parses the "Zip64 end of central directory locator", - * finds the "Zip64 end of central directory record" using the - * parsed information, parses that and positions the stream at the - * first central directory record. - * - * Expects stream to be positioned right behind the "Zip64 - * end of central directory locator"'s signature. - */ - private void positionAtCentralDirectory64() - throws IOException { - skipBytes(ZIP64_EOCDL_LOCATOR_OFFSET - - WORD /* signature has already been read */); - dwordBbuf.rewind(); - IOUtils.readFully(archive, dwordBbuf); - archive.position(ZipEightByteInteger.getLongValue(dwordBuf)); - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - if (!Arrays.equals(wordBuf, ZipArchiveOutputStream.ZIP64_EOCD_SIG)) { - throw new ZipException("archive's ZIP64 end of central " - + "directory locator is corrupt."); - } - skipBytes(ZIP64_EOCD_CFD_LOCATOR_OFFSET - - WORD /* signature has already been read */); - dwordBbuf.rewind(); - IOUtils.readFully(archive, dwordBbuf); - archive.position(ZipEightByteInteger.getLongValue(dwordBuf)); - } - - /** - * Parses the "End of central dir record" and positions - * the stream at the first central directory record. - * - * Expects stream to be positioned at the beginning of the - * "End of central dir record". - */ - private void positionAtCentralDirectory32() - throws IOException { - skipBytes(CFD_LOCATOR_OFFSET); - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - archive.position(ZipLong.getValue(wordBuf)); - } - - /** - * Searches for the and positions the stream at the start of the - * "End of central dir record". - */ - private void positionAtEndOfCentralDirectoryRecord() - throws IOException { - final boolean found = tryToLocateSignature(MIN_EOCD_SIZE, MAX_EOCD_SIZE, - ZipArchiveOutputStream.EOCD_SIG); - if (!found) { - throw new ZipException("archive is not a ZIP archive"); - } - } - - /** - * Searches the archive backwards from minDistance to maxDistance - * for the given signature, positions the RandomaccessFile right - * at the signature if it has been found. - */ - private boolean tryToLocateSignature(final long minDistanceFromEnd, - final long maxDistanceFromEnd, - final byte[] sig) throws IOException { - boolean found = false; - long off = archive.size() - minDistanceFromEnd; - final long stopSearching = - Math.max(0L, archive.size() - maxDistanceFromEnd); - if (off >= 0) { - for (; off >= stopSearching; off--) { - archive.position(off); - try { - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - wordBbuf.flip(); - } catch (EOFException ex) { - break; - } - int curr = wordBbuf.get(); - if (curr == sig[POS_0]) { - curr = wordBbuf.get(); - if (curr == sig[POS_1]) { - curr = wordBbuf.get(); - if (curr == sig[POS_2]) { - curr = wordBbuf.get(); - if (curr == sig[POS_3]) { - found = true; - break; - } - } - } - } - } - } - if (found) { - archive.position(off); - } - return found; - } - - /** - * Skips the given number of bytes or throws an EOFException if - * skipping failed. - */ - private void skipBytes(final int count) throws IOException { - long currentPosition = archive.position(); - long newPosition = currentPosition + count; - if (newPosition > archive.size()) { - throw new EOFException(); - } - archive.position(newPosition); - } - - /** - * Number of bytes in local file header up to the "length of - * filename" entry. - */ - private static final long LFH_OFFSET_FOR_FILENAME_LENGTH = - /* local file header signature */ WORD - /* version needed to extract */ + SHORT - /* general purpose bit flag */ + SHORT - /* compression method */ + SHORT - /* last mod file time */ + SHORT - /* last mod file date */ + SHORT - /* crc-32 */ + WORD - /* compressed size */ + WORD - /* uncompressed size */ + (long) WORD; - - /** - * Walks through all recorded entries and adds the data available - * from the local file header. - * - *

Also records the offsets for the data to read from the - * entries.

- */ - private void resolveLocalFileHeaderData(final Map - entriesWithoutUTF8Flag) - throws IOException { - for (final ZipArchiveEntry zipArchiveEntry : entries) { - // entries is filled in populateFromCentralDirectory and - // never modified - final Entry ze = (Entry) zipArchiveEntry; - final long offset = ze.getLocalHeaderOffset(); - archive.position(offset + LFH_OFFSET_FOR_FILENAME_LENGTH); - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - wordBbuf.flip(); - wordBbuf.get(shortBuf); - final int fileNameLen = ZipShort.getValue(shortBuf); - wordBbuf.get(shortBuf); - final int extraFieldLen = ZipShort.getValue(shortBuf); - skipBytes(fileNameLen); - final byte[] localExtraData = new byte[extraFieldLen]; - IOUtils.readFully(archive, ByteBuffer.wrap(localExtraData)); - ze.setExtra(localExtraData); - ze.setDataOffset(offset + LFH_OFFSET_FOR_FILENAME_LENGTH - + SHORT + SHORT + fileNameLen + extraFieldLen); - ze.setStreamContiguous(true); - - if (entriesWithoutUTF8Flag.containsKey(ze)) { - final NameAndComment nc = entriesWithoutUTF8Flag.get(ze); - ZipUtil.setNameAndCommentFromExtraFields(ze, nc.name, - nc.comment); - } - - final String name = ze.getName(); - LinkedList entriesOfThatName = nameMap.get(name); - if (entriesOfThatName == null) { - entriesOfThatName = new LinkedList<>(); - nameMap.put(name, entriesOfThatName); - } - entriesOfThatName.addLast(ze); - } - } - - /** - * Checks whether the archive starts with a LFH. If it doesn't, - * it may be an empty archive. - */ - private boolean startsWithLocalFileHeader() throws IOException { - archive.position(0); - wordBbuf.rewind(); - IOUtils.readFully(archive, wordBbuf); - return Arrays.equals(wordBuf, ZipArchiveOutputStream.LFH_SIG); - } - - /** - * Creates new BoundedInputStream, according to implementation of - * underlying archive channel. - */ - private BoundedInputStream createBoundedInputStream(long start, long remaining) { - return archive instanceof FileChannel ? - new BoundedFileChannelInputStream(start, remaining) : - new BoundedInputStream(start, remaining); - } - - /** - * InputStream that delegates requests to the underlying - * SeekableByteChannel, making sure that only bytes from a certain - * range can be read. - */ - private class BoundedInputStream extends InputStream { - private ByteBuffer singleByteBuffer; - private final long end; - private long loc; - - BoundedInputStream(final long start, final long remaining) { - this.end = start+remaining; - if (this.end < start) { - // check for potential vulnerability due to overflow - throw new IllegalArgumentException("Invalid length of stream at offset="+start+", length="+remaining); - } - loc = start; - } - - @Override - public synchronized int read() throws IOException { - if (loc >= end) { - return -1; - } - if (singleByteBuffer == null) { - singleByteBuffer = ByteBuffer.allocate(1); - } - else { - singleByteBuffer.rewind(); - } - int read = read(loc, singleByteBuffer); - if (read < 0) { - return read; - } - loc++; - return singleByteBuffer.get() & 0xff; - } - - @Override - public synchronized int read(final byte[] b, final int off, int len) throws IOException { - if (len <= 0) { - return 0; - } - - if (len > end-loc) { - if (loc >= end) { - return -1; - } - len = (int)(end-loc); - } - - ByteBuffer buf; - buf = ByteBuffer.wrap(b, off, len); - int ret = read(loc, buf); - if (ret > 0) { - loc += ret; - return ret; - } - return ret; - } - - protected int read(long pos, ByteBuffer buf) throws IOException { - int read; - synchronized (archive) { - archive.position(pos); - read = archive.read(buf); - } - buf.flip(); - return read; - } - } - - /** - * Lock-free implementation of BoundedInputStream. The - * implementation uses positioned reads on the underlying archive - * file channel and therefore performs significantly faster in - * concurrent environment. - */ - private class BoundedFileChannelInputStream extends BoundedInputStream { - private final FileChannel archive; - - BoundedFileChannelInputStream(final long start, final long remaining) { - super(start, remaining); - archive = (FileChannel)ZipFile.this.archive; - } - - @Override - protected int read(long pos, ByteBuffer buf) throws IOException { - int read = archive.read(buf, pos); - buf.flip(); - return read; - } - } - - private static final class NameAndComment { - private final byte[] name; - private final byte[] comment; - private NameAndComment(final byte[] name, final byte[] comment) { - this.name = name; - this.comment = comment; - } - } - - /** - * Compares two ZipArchiveEntries based on their offset within the archive. - * - *

Won't return any meaningful results if one of the entries - * isn't part of the archive at all.

- * - * @since 1.1 - */ - private final Comparator offsetComparator = - new Comparator() { - @Override - public int compare(final ZipArchiveEntry e1, final ZipArchiveEntry e2) { - if (e1 == e2) { - return 0; - } - - final Entry ent1 = e1 instanceof Entry ? (Entry) e1 : null; - final Entry ent2 = e2 instanceof Entry ? (Entry) e2 : null; - if (ent1 == null) { - return 1; - } - if (ent2 == null) { - return -1; - } - final long val = (ent1.getLocalHeaderOffset() - - ent2.getLocalHeaderOffset()); - return val == 0 ? 0 : val < 0 ? -1 : +1; - } - }; - - /** - * Extends ZipArchiveEntry to store the offset within the archive. - */ - private static class Entry extends ZipArchiveEntry { - - Entry() { - } - - @Override - public int hashCode() { - return 3 * super.hashCode() - + (int) getLocalHeaderOffset()+(int)(getLocalHeaderOffset()>>32); - } - - @Override - public boolean equals(final Object other) { - if (super.equals(other)) { - // super.equals would return false if other were not an Entry - final Entry otherEntry = (Entry) other; - return getLocalHeaderOffset() - == otherEntry.getLocalHeaderOffset() - && getDataOffset() - == otherEntry.getDataOffset(); - } - return false; - } - } - - private static class StoredStatisticsStream extends CountingInputStream implements InputStreamStatistics { - StoredStatisticsStream(InputStream in) { - super(in); - } - - @Override - public long getCompressedCount() { - return super.getBytesRead(); - } - - @Override - public long getUncompressedCount() { - return getCompressedCount(); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipLong.java b/src/org/apache/commons/compress/archivers/zip/ZipLong.java deleted file mode 100644 index 6046c61da7b..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipLong.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import org.apache.commons.compress.utils.ByteUtils; - -import java.io.Serializable; - -import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD; - -/** - * Utility class that represents a four byte integer with conversion - * rules for the little endian byte order of ZIP files. - * @Immutable - */ -public final class ZipLong implements Cloneable, Serializable { - private static final long serialVersionUID = 1L; - - private final long value; - - /** Central File Header Signature */ - public static final ZipLong CFH_SIG = new ZipLong(0X02014B50L); - - /** Local File Header Signature */ - public static final ZipLong LFH_SIG = new ZipLong(0X04034B50L); - - /** - * Data Descriptor signature. - * - *

Actually, PKWARE uses this as marker for split/spanned - * archives and other archivers have started to use it as Data - * Descriptor signature (as well).

- * @since 1.1 - */ - public static final ZipLong DD_SIG = new ZipLong(0X08074B50L); - - /** - * Value stored in size and similar fields if ZIP64 extensions are - * used. - * @since 1.3 - */ - static final ZipLong ZIP64_MAGIC = new ZipLong(ZipConstants.ZIP64_MAGIC); - - /** - * Marks ZIP archives that were supposed to be split or spanned - * but only needed a single segment in then end (so are actually - * neither split nor spanned). - * - *

This is the "PK00" prefix found in some archives.

- * @since 1.5 - */ - public static final ZipLong SINGLE_SEGMENT_SPLIT_MARKER = - new ZipLong(0X30304B50L); - - /** - * Archive extra data record signature. - * @since 1.5 - */ - public static final ZipLong AED_SIG = new ZipLong(0X08064B50L); - - /** - * Create instance from a number. - * @param value the long to store as a ZipLong - */ - public ZipLong(final long value) { - this.value = value; - } - - /** - * create instance from a java int. - * @param value the int to store as a ZipLong - * @since 1.15 - */ - public ZipLong(int value) { - this.value = value; - } - - /** - * Create instance from bytes. - * @param bytes the bytes to store as a ZipLong - */ - public ZipLong (final byte[] bytes) { - this(bytes, 0); - } - - /** - * Create instance from the four bytes starting at offset. - * @param bytes the bytes to store as a ZipLong - * @param offset the offset to start - */ - public ZipLong (final byte[] bytes, final int offset) { - value = ZipLong.getValue(bytes, offset); - } - - /** - * Get value as four bytes in big endian byte order. - * @return value as four bytes in big endian order - */ - public byte[] getBytes() { - return ZipLong.getBytes(value); - } - - /** - * Get value as Java long. - * @return value as a long - */ - public long getValue() { - return value; - } - - /** - * Get value as a (signed) java int - * @return value as int - * @since 1.15 - */ - public int getIntValue() { return (int)value;} - - /** - * Get value as four bytes in big endian byte order. - * @param value the value to convert - * @return value as four bytes in big endian byte order - */ - public static byte[] getBytes(final long value) { - final byte[] result = new byte[WORD]; - putLong(value, result, 0); - return result; - } - - /** - * put the value as four bytes in big endian byte order. - * @param value the Java long to convert to bytes - * @param buf the output buffer - * @param offset - * The offset within the output buffer of the first byte to be written. - * must be non-negative and no larger than buf.length-4 - */ - - public static void putLong(final long value, final byte[] buf, int offset) { - ByteUtils.toLittleEndian(buf, value, offset, 4); - } - - public void putLong(final byte[] buf, final int offset) { - putLong(value, buf, offset); - } - - /** - * Helper method to get the value as a Java long from four bytes starting at given array offset - * @param bytes the array of bytes - * @param offset the offset to start - * @return the corresponding Java long value - */ - public static long getValue(final byte[] bytes, final int offset) { - return ByteUtils.fromLittleEndian(bytes, offset, 4); - } - - /** - * Helper method to get the value as a Java long from a four-byte array - * @param bytes the array of bytes - * @return the corresponding Java long value - */ - public static long getValue(final byte[] bytes) { - return getValue(bytes, 0); - } - - /** - * Override to make two instances with same value equal. - * @param o an object to compare - * @return true if the objects are equal - */ - @Override - public boolean equals(final Object o) { - if (o == null || !(o instanceof ZipLong)) { - return false; - } - return value == ((ZipLong) o).getValue(); - } - - /** - * Override to make two instances with same value equal. - * @return the value stored in the ZipLong - */ - @Override - public int hashCode() { - return (int) value; - } - - @Override - public Object clone() { - try { - return super.clone(); - } catch (final CloneNotSupportedException cnfe) { - // impossible - throw new RuntimeException(cnfe); //NOSONAR - } - } - - @Override - public String toString() { - return "ZipLong value: " + value; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipMethod.java b/src/org/apache/commons/compress/archivers/zip/ZipMethod.java deleted file mode 100644 index 0c9112d7b89..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipMethod.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.zip.ZipEntry; - -/** - * List of known compression methods - * - * Many of these methods are currently not supported by commons compress - * - * @since 1.5 - */ -public enum ZipMethod { - - /** - * Compression method 0 for uncompressed entries. - * - * @see ZipEntry#STORED - */ - STORED(ZipEntry.STORED), - - /** - * UnShrinking. - * dynamic Lempel-Ziv-Welch-Algorithm - * - * @see Explanation of fields: compression - * method: (2 bytes) - */ - UNSHRINKING(1), - - /** - * Reduced with compression factor 1. - * - * @see Explanation of fields: compression - * method: (2 bytes) - */ - EXPANDING_LEVEL_1(2), - - /** - * Reduced with compression factor 2. - * - * @see Explanation of fields: compression - * method: (2 bytes) - */ - EXPANDING_LEVEL_2(3), - - /** - * Reduced with compression factor 3. - * - * @see Explanation of fields: compression - * method: (2 bytes) - */ - EXPANDING_LEVEL_3(4), - - /** - * Reduced with compression factor 4. - * - * @see Explanation of fields: compression - * method: (2 bytes) - */ - EXPANDING_LEVEL_4(5), - - /** - * Imploding. - * - * @see Explanation of fields: compression - * method: (2 bytes) - */ - IMPLODING(6), - - /** - * Tokenization. - * - * @see Explanation of fields: compression - * method: (2 bytes) - */ - TOKENIZATION(7), - - /** - * Compression method 8 for compressed (deflated) entries. - * - * @see ZipEntry#DEFLATED - */ - DEFLATED(ZipEntry.DEFLATED), - - /** - * Compression Method 9 for enhanced deflate. - * - * @see https://www.winzip.com/wz54.htm - */ - ENHANCED_DEFLATED(9), - - /** - * PKWARE Data Compression Library Imploding. - * - * @see https://www.winzip.com/wz54.htm - */ - PKWARE_IMPLODING(10), - - /** - * Compression Method 12 for bzip2. - * - * @see https://www.winzip.com/wz54.htm - */ - BZIP2(12), - - /** - * Compression Method 14 for LZMA. - * - * @see https://www.7-zip.org/sdk.html - * @see https://www.winzip.com/wz54.htm - */ - LZMA(14), - - - /** - * Compression Method 95 for XZ. - * - * @see https://www.winzip.com/wz54.htm - */ - XZ(95), - - /** - * Compression Method 96 for Jpeg compression. - * - * @see https://www.winzip.com/wz54.htm - */ - JPEG(96), - - /** - * Compression Method 97 for WavPack. - * - * @see https://www.winzip.com/wz54.htm - */ - WAVPACK(97), - - /** - * Compression Method 98 for PPMd. - * - * @see https://www.winzip.com/wz54.htm - */ - PPMD(98), - - - /** - * Compression Method 99 for AES encryption. - * - * @see https://www.winzip.com/wz54.htm - */ - AES_ENCRYPTED(99), - - /** - * Unknown compression method. - */ - UNKNOWN(); - - static final int UNKNOWN_CODE = -1; - - private final int code; - - private static final Map codeToEnum; - - static { - final Map cte = new HashMap<>(); - for (final ZipMethod method : values()) { - cte.put(method.getCode(), method); - } - codeToEnum = Collections.unmodifiableMap(cte); - } - - private ZipMethod() { - this(UNKNOWN_CODE); - } - - /** - * private constructor for enum style class. - */ - ZipMethod(final int code) { - this.code = code; - } - - /** - * the code of the compression method. - * - * @see ZipArchiveEntry#getMethod() - * - * @return an integer code for the method - */ - public int getCode() { - return code; - } - - - /** - * returns the {@link ZipMethod} for the given code or null if the - * method is not known. - * @param code the code - * @return the {@link ZipMethod} for the given code or null if the - * method is not known. - */ - public static ZipMethod getMethodByCode(final int code) { - return codeToEnum.get(code); - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipShort.java b/src/org/apache/commons/compress/archivers/zip/ZipShort.java deleted file mode 100644 index ccb50940a3d..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipShort.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.Serializable; - -import org.apache.commons.compress.utils.ByteUtils; - -/** - * Utility class that represents a two byte integer with conversion - * rules for the little endian byte order of ZIP files. - * @Immutable - */ -public final class ZipShort implements Cloneable, Serializable { - /** - * ZipShort with a value of 0. - * @since 1.14 - */ - public static final ZipShort ZERO = new ZipShort(0); - - private static final long serialVersionUID = 1L; - - private final int value; - - /** - * Create instance from a number. - * @param value the int to store as a ZipShort - */ - public ZipShort (final int value) { - this.value = value; - } - - /** - * Create instance from bytes. - * @param bytes the bytes to store as a ZipShort - */ - public ZipShort (final byte[] bytes) { - this(bytes, 0); - } - - /** - * Create instance from the two bytes starting at offset. - * @param bytes the bytes to store as a ZipShort - * @param offset the offset to start - */ - public ZipShort (final byte[] bytes, final int offset) { - value = ZipShort.getValue(bytes, offset); - } - - /** - * Get value as two bytes in big endian byte order. - * @return the value as a a two byte array in big endian byte order - */ - public byte[] getBytes() { - final byte[] result = new byte[2]; - ByteUtils.toLittleEndian(result, value, 0, 2); - return result; - } - - /** - * Get value as Java int. - * @return value as a Java int - */ - public int getValue() { - return value; - } - - /** - * Get value as two bytes in big endian byte order. - * @param value the Java int to convert to bytes - * @return the converted int as a byte array in big endian byte order - */ - public static byte[] getBytes(final int value) { - final byte[] result = new byte[2]; - putShort(value, result, 0); - return result; - } - - /** - * put the value as two bytes in big endian byte order. - * @param value the Java int to convert to bytes - * @param buf the output buffer - * @param offset - * The offset within the output buffer of the first byte to be written. - * must be non-negative and no larger than buf.length-2 - */ - public static void putShort(final int value, final byte[] buf, final int offset) { - ByteUtils.toLittleEndian(buf, value, offset, 2); - } - - /** - * Helper method to get the value as a java int from two bytes starting at given array offset - * @param bytes the array of bytes - * @param offset the offset to start - * @return the corresponding java int value - */ - public static int getValue(final byte[] bytes, final int offset) { - return (int) ByteUtils.fromLittleEndian(bytes, offset, 2); - } - - /** - * Helper method to get the value as a java int from a two-byte array - * @param bytes the array of bytes - * @return the corresponding java int value - */ - public static int getValue(final byte[] bytes) { - return getValue(bytes, 0); - } - - /** - * Override to make two instances with same value equal. - * @param o an object to compare - * @return true if the objects are equal - */ - @Override - public boolean equals(final Object o) { - if (o == null || !(o instanceof ZipShort)) { - return false; - } - return value == ((ZipShort) o).getValue(); - } - - /** - * Override to make two instances with same value equal. - * @return the value stored in the ZipShort - */ - @Override - public int hashCode() { - return value; - } - - @Override - public Object clone() { - try { - return super.clone(); - } catch (final CloneNotSupportedException cnfe) { - // impossible - throw new RuntimeException(cnfe); //NOSONAR - } - } - - @Override - public String toString() { - return "ZipShort value: " + value; - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/ZipUtil.java b/src/org/apache/commons/compress/archivers/zip/ZipUtil.java deleted file mode 100644 index 8cc3e6a4c19..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/ZipUtil.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.archivers.zip; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Calendar; -import java.util.Date; -import java.util.zip.CRC32; -import java.util.zip.ZipEntry; - -/** - * Utility class for handling DOS and Java time conversions. - * @Immutable - */ -public abstract class ZipUtil { - /** - * Smallest date/time ZIP can handle. - */ - private static final byte[] DOS_TIME_MIN = ZipLong.getBytes(0x00002100L); - - /** - * Convert a Date object to a DOS date/time field. - * @param time the Date to convert - * @return the date as a ZipLong - */ - public static ZipLong toDosTime(final Date time) { - return new ZipLong(toDosTime(time.getTime())); - } - - /** - * Convert a Date object to a DOS date/time field. - * - *

Stolen from InfoZip's fileio.c

- * @param t number of milliseconds since the epoch - * @return the date as a byte array - */ - public static byte[] toDosTime(final long t) { - final byte[] result = new byte[4]; - toDosTime(t, result, 0); - return result; - } - - /** - * Convert a Date object to a DOS date/time field. - * - *

Stolen from InfoZip's fileio.c

- * @param t number of milliseconds since the epoch - * @param buf the output buffer - * @param offset - * The offset within the output buffer of the first byte to be written. - * must be non-negative and no larger than buf.length-4 - */ - public static void toDosTime(final long t, final byte[] buf, final int offset) { - toDosTime(Calendar.getInstance(), t, buf, offset); - } - - static void toDosTime(final Calendar c, final long t, final byte[] buf, final int offset) { - c.setTimeInMillis(t); - - final int year = c.get(Calendar.YEAR); - if (year < 1980) { - System.arraycopy(DOS_TIME_MIN, 0, buf, offset, DOS_TIME_MIN.length);// stop callers from changing the array - return; - } - final int month = c.get(Calendar.MONTH) + 1; - final long value = ((year - 1980) << 25) - | (month << 21) - | (c.get(Calendar.DAY_OF_MONTH) << 16) - | (c.get(Calendar.HOUR_OF_DAY) << 11) - | (c.get(Calendar.MINUTE) << 5) - | (c.get(Calendar.SECOND) >> 1); - ZipLong.putLong(value, buf, offset); - } - - - /** - * Assumes a negative integer really is a positive integer that - * has wrapped around and re-creates the original value. - * - * @param i the value to treat as unsigned int. - * @return the unsigned int as a long. - */ - public static long adjustToLong(final int i) { - if (i < 0) { - return 2 * ((long) Integer.MAX_VALUE) + 2 + i; - } - return i; - } - - /** - * Reverses a byte[] array. Reverses in-place (thus provided array is - * mutated), but also returns same for convenience. - * - * @param array to reverse (mutated in-place, but also returned for - * convenience). - * - * @return the reversed array (mutated in-place, but also returned for - * convenience). - * @since 1.5 - */ - public static byte[] reverse(final byte[] array) { - final int z = array.length - 1; // position of last element - for (int i = 0; i < array.length / 2; i++) { - final byte x = array[i]; - array[i] = array[z - i]; - array[z - i] = x; - } - return array; - } - - /** - * Converts a BigInteger into a long, and blows up - * (NumberFormatException) if the BigInteger is too big. - * - * @param big BigInteger to convert. - * @return long representation of the BigInteger. - */ - static long bigToLong(final BigInteger big) { - if (big.bitLength() <= 63) { // bitLength() doesn't count the sign bit. - return big.longValue(); - } - throw new NumberFormatException("The BigInteger cannot fit inside a 64 bit java long: [" + big + "]"); - } - - /** - *

- * Converts a long into a BigInteger. Negative numbers between -1 and - * -2^31 are treated as unsigned 32 bit (e.g., positive) integers. - * Negative numbers below -2^31 cause an IllegalArgumentException - * to be thrown. - *

- * - * @param l long to convert to BigInteger. - * @return BigInteger representation of the provided long. - */ - static BigInteger longToBig(long l) { - if (l < Integer.MIN_VALUE) { - throw new IllegalArgumentException("Negative longs < -2^31 not permitted: [" + l + "]"); - } else if (l < 0 && l >= Integer.MIN_VALUE) { - // If someone passes in a -2, they probably mean 4294967294 - // (For example, Unix UID/GID's are 32 bit unsigned.) - l = ZipUtil.adjustToLong((int) l); - } - return BigInteger.valueOf(l); - } - - /** - * Converts a signed byte into an unsigned integer representation - * (e.g., -1 becomes 255). - * - * @param b byte to convert to int - * @return int representation of the provided byte - * @since 1.5 - */ - public static int signedByteToUnsignedInt(final byte b) { - if (b >= 0) { - return b; - } - return 256 + b; - } - - /** - * Converts an unsigned integer to a signed byte (e.g., 255 becomes -1). - * - * @param i integer to convert to byte - * @return byte representation of the provided int - * @throws IllegalArgumentException if the provided integer is not inside the range [0,255]. - * @since 1.5 - */ - public static byte unsignedIntToSignedByte(final int i) { - if (i > 255 || i < 0) { - throw new IllegalArgumentException("Can only convert non-negative integers between [0,255] to byte: [" + i + "]"); - } - if (i < 128) { - return (byte) i; - } - return (byte) (i - 256); - } - - /** - * Convert a DOS date/time field to a Date object. - * - * @param zipDosTime contains the stored DOS time. - * @return a Date instance corresponding to the given time. - */ - public static Date fromDosTime(final ZipLong zipDosTime) { - final long dosTime = zipDosTime.getValue(); - return new Date(dosToJavaTime(dosTime)); - } - - /** - * Converts DOS time to Java time (number of milliseconds since - * epoch). - * @param dosTime time to convert - * @return converted time - */ - public static long dosToJavaTime(final long dosTime) { - final Calendar cal = Calendar.getInstance(); - // CheckStyle:MagicNumberCheck OFF - no point - cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980); - cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1); - cal.set(Calendar.DATE, (int) (dosTime >> 16) & 0x1f); - cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f); - cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f); - cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e); - cal.set(Calendar.MILLISECOND, 0); - // CheckStyle:MagicNumberCheck ON - return cal.getTime().getTime(); - } - - /** - * If the entry has Unicode*ExtraFields and the CRCs of the - * names/comments match those of the extra fields, transfer the - * known Unicode values from the extra field. - */ - static void setNameAndCommentFromExtraFields(final ZipArchiveEntry ze, - final byte[] originalNameBytes, - final byte[] commentBytes) { - final UnicodePathExtraField name = (UnicodePathExtraField) - ze.getExtraField(UnicodePathExtraField.UPATH_ID); - final String newName = getUnicodeStringIfOriginalMatches(name, - originalNameBytes); - if (newName != null) { - ze.setName(newName); - ze.setNameSource(ZipArchiveEntry.NameSource.UNICODE_EXTRA_FIELD); - } - - if (commentBytes != null && commentBytes.length > 0) { - final UnicodeCommentExtraField cmt = (UnicodeCommentExtraField) - ze.getExtraField(UnicodeCommentExtraField.UCOM_ID); - final String newComment = - getUnicodeStringIfOriginalMatches(cmt, commentBytes); - if (newComment != null) { - ze.setComment(newComment); - ze.setCommentSource(ZipArchiveEntry.CommentSource.UNICODE_EXTRA_FIELD); - } - } - } - - /** - * If the stored CRC matches the one of the given name, return the - * Unicode name of the given field. - * - *

If the field is null or the CRCs don't match, return null - * instead.

- */ - private static - String getUnicodeStringIfOriginalMatches(final AbstractUnicodeExtraField f, - final byte[] orig) { - if (f != null) { - final CRC32 crc32 = new CRC32(); - crc32.update(orig); - final long origCRC32 = crc32.getValue(); - - if (origCRC32 == f.getNameCRC32()) { - try { - return ZipEncodingHelper - .UTF8_ZIP_ENCODING.decode(f.getUnicodeName()); - } catch (final IOException ex) { - // UTF-8 unsupported? should be impossible the - // Unicode*ExtraField must contain some bad bytes - - // TODO log this anywhere? - return null; - } - } - } - return null; - } - - /** - * Create a copy of the given array - or return null if the - * argument is null. - */ - static byte[] copy(final byte[] from) { - if (from != null) { - final byte[] to = new byte[from.length]; - System.arraycopy(from, 0, to, 0, to.length); - return to; - } - return null; - } - - static void copy(final byte[] from, final byte[] to, final int offset) { - if (from != null) { - System.arraycopy(from, 0, to, offset, from.length); - } - } - - - /** - * Whether this library is able to read or write the given entry. - */ - static boolean canHandleEntryData(final ZipArchiveEntry entry) { - return supportsEncryptionOf(entry) && supportsMethodOf(entry); - } - - /** - * Whether this library supports the encryption used by the given - * entry. - * - * @return true if the entry isn't encrypted at all - */ - private static boolean supportsEncryptionOf(final ZipArchiveEntry entry) { - return !entry.getGeneralPurposeBit().usesEncryption(); - } - - /** - * Whether this library supports the compression method used by - * the given entry. - * - * @return true if the compression method is supported - */ - private static boolean supportsMethodOf(final ZipArchiveEntry entry) { - return entry.getMethod() == ZipEntry.STORED - || entry.getMethod() == ZipMethod.UNSHRINKING.getCode() - || entry.getMethod() == ZipMethod.IMPLODING.getCode() - || entry.getMethod() == ZipEntry.DEFLATED - || entry.getMethod() == ZipMethod.ENHANCED_DEFLATED.getCode() - || entry.getMethod() == ZipMethod.BZIP2.getCode(); - } - - /** - * Checks whether the entry requires features not (yet) supported - * by the library and throws an exception if it does. - */ - static void checkRequestedFeatures(final ZipArchiveEntry ze) - throws UnsupportedZipFeatureException { - if (!supportsEncryptionOf(ze)) { - throw - new UnsupportedZipFeatureException(UnsupportedZipFeatureException - .Feature.ENCRYPTION, ze); - } - if (!supportsMethodOf(ze)) { - final ZipMethod m = ZipMethod.getMethodByCode(ze.getMethod()); - if (m == null) { - throw - new UnsupportedZipFeatureException(UnsupportedZipFeatureException - .Feature.METHOD, ze); - } - throw new UnsupportedZipFeatureException(m, ze); - } - } -} diff --git a/src/org/apache/commons/compress/archivers/zip/package.html b/src/org/apache/commons/compress/archivers/zip/package.html deleted file mode 100644 index 521687be66f..00000000000 --- a/src/org/apache/commons/compress/archivers/zip/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides stream classes for reading and writing archives using - the ZIP format.

- - diff --git a/src/org/apache/commons/compress/changes/Change.java b/src/org/apache/commons/compress/changes/Change.java deleted file mode 100644 index fb901bd41a0..00000000000 --- a/src/org/apache/commons/compress/changes/Change.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.changes; - -import java.io.InputStream; - -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * Change holds meta information about a change. - * - * @Immutable - */ -class Change { - private final String targetFile; // entry name to delete - private final ArchiveEntry entry; // new entry to add - private final InputStream input; // source for new entry - private final boolean replaceMode; // change should replaceMode existing entries - - // Type of change - private final int type; - // Possible type values - static final int TYPE_DELETE = 1; - static final int TYPE_ADD = 2; - static final int TYPE_MOVE = 3; // NOT USED - static final int TYPE_DELETE_DIR = 4; - - /** - * Constructor. Takes the filename of the file to be deleted - * from the stream as argument. - * @param pFilename the filename of the file to delete - */ - Change(final String pFilename, final int type) { - if(pFilename == null) { - throw new NullPointerException(); - } - this.targetFile = pFilename; - this.type = type; - this.input = null; - this.entry = null; - this.replaceMode = true; - } - - /** - * Construct a change which adds an entry. - * - * @param pEntry the entry details - * @param pInput the InputStream for the entry data - */ - Change(final ArchiveEntry pEntry, final InputStream pInput, final boolean replace) { - if(pEntry == null || pInput == null) { - throw new NullPointerException(); - } - this.entry = pEntry; - this.input = pInput; - type = TYPE_ADD; - targetFile = null; - this.replaceMode = replace; - } - - ArchiveEntry getEntry() { - return entry; - } - - InputStream getInput() { - return input; - } - - String targetFile() { - return targetFile; - } - - int type() { - return type; - } - - boolean isReplaceMode() { - return replaceMode; - } -} diff --git a/src/org/apache/commons/compress/changes/ChangeSet.java b/src/org/apache/commons/compress/changes/ChangeSet.java deleted file mode 100644 index c0f8c61e4ba..00000000000 --- a/src/org/apache/commons/compress/changes/ChangeSet.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.changes; - -import java.io.InputStream; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * ChangeSet collects and performs changes to an archive. - * Putting delete changes in this ChangeSet from multiple threads can - * cause conflicts. - * - * @NotThreadSafe - */ -public final class ChangeSet { - - private final Set changes = new LinkedHashSet<>(); - - /** - * Deletes the file with the filename from the archive. - * - * @param filename - * the filename of the file to delete - */ - public void delete(final String filename) { - addDeletion(new Change(filename, Change.TYPE_DELETE)); - } - - /** - * Deletes the directory tree from the archive. - * - * @param dirName - * the name of the directory tree to delete - */ - public void deleteDir(final String dirName) { - addDeletion(new Change(dirName, Change.TYPE_DELETE_DIR)); - } - - /** - * Adds a new archive entry to the archive. - * - * @param pEntry - * the entry to add - * @param pInput - * the datastream to add - */ - public void add(final ArchiveEntry pEntry, final InputStream pInput) { - this.add(pEntry, pInput, true); - } - - /** - * Adds a new archive entry to the archive. - * If replace is set to true, this change will replace all other additions - * done in this ChangeSet and all existing entries in the original stream. - * - * @param pEntry - * the entry to add - * @param pInput - * the datastream to add - * @param replace - * indicates the this change should replace existing entries - */ - public void add(final ArchiveEntry pEntry, final InputStream pInput, final boolean replace) { - addAddition(new Change(pEntry, pInput, replace)); - } - - /** - * Adds an addition change. - * - * @param pChange - * the change which should result in an addition - */ - private void addAddition(final Change pChange) { - if (Change.TYPE_ADD != pChange.type() || - pChange.getInput() == null) { - return; - } - - if (!changes.isEmpty()) { - for (final Iterator it = changes.iterator(); it.hasNext();) { - final Change change = it.next(); - if (change.type() == Change.TYPE_ADD - && change.getEntry() != null) { - final ArchiveEntry entry = change.getEntry(); - - if(entry.equals(pChange.getEntry())) { - if(pChange.isReplaceMode()) { - it.remove(); - changes.add(pChange); - return; - } - // do not add this change - return; - } - } - } - } - changes.add(pChange); - } - - /** - * Adds an delete change. - * - * @param pChange - * the change which should result in a deletion - */ - private void addDeletion(final Change pChange) { - if ((Change.TYPE_DELETE != pChange.type() && - Change.TYPE_DELETE_DIR != pChange.type()) || - pChange.targetFile() == null) { - return; - } - final String source = pChange.targetFile(); - - if (source != null && !changes.isEmpty()) { - for (final Iterator it = changes.iterator(); it.hasNext();) { - final Change change = it.next(); - if (change.type() == Change.TYPE_ADD - && change.getEntry() != null) { - final String target = change.getEntry().getName(); - - if (target == null) { - continue; - } - - if (Change.TYPE_DELETE == pChange.type() && source.equals(target) || - (Change.TYPE_DELETE_DIR == pChange.type() && target.matches(source + "/.*"))) { - it.remove(); - } - } - } - } - changes.add(pChange); - } - - /** - * Returns the list of changes as a copy. Changes on this set - * are not reflected on this ChangeSet and vice versa. - * @return the changes as a copy - */ - Set getChanges() { - return new LinkedHashSet<>(changes); - } -} diff --git a/src/org/apache/commons/compress/changes/ChangeSetPerformer.java b/src/org/apache/commons/compress/changes/ChangeSetPerformer.java deleted file mode 100644 index bec6b642103..00000000000 --- a/src/org/apache/commons/compress/changes/ChangeSetPerformer.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.changes; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipFile; -import org.apache.commons.compress.utils.IOUtils; - -/** - * Performs ChangeSet operations on a stream. - * This class is thread safe and can be used multiple times. - * It operates on a copy of the ChangeSet. If the ChangeSet changes, - * a new Performer must be created. - * - * @ThreadSafe - * @Immutable - */ -public class ChangeSetPerformer { - private final Set changes; - - /** - * Constructs a ChangeSetPerformer with the changes from this ChangeSet - * @param changeSet the ChangeSet which operations are used for performing - */ - public ChangeSetPerformer(final ChangeSet changeSet) { - changes = changeSet.getChanges(); - } - - /** - * Performs all changes collected in this ChangeSet on the input stream and - * streams the result to the output stream. Perform may be called more than once. - * - * This method finishes the stream, no other entries should be added - * after that. - * - * @param in - * the InputStream to perform the changes on - * @param out - * the resulting OutputStream with all modifications - * @throws IOException - * if an read/write error occurs - * @return the results of this operation - */ - public ChangeSetResults perform(final ArchiveInputStream in, final ArchiveOutputStream out) - throws IOException { - return perform(new ArchiveInputStreamIterator(in), out); - } - - /** - * Performs all changes collected in this ChangeSet on the ZipFile and - * streams the result to the output stream. Perform may be called more than once. - * - * This method finishes the stream, no other entries should be added - * after that. - * - * @param in - * the ZipFile to perform the changes on - * @param out - * the resulting OutputStream with all modifications - * @throws IOException - * if an read/write error occurs - * @return the results of this operation - * @since 1.5 - */ - public ChangeSetResults perform(final ZipFile in, final ArchiveOutputStream out) - throws IOException { - return perform(new ZipFileIterator(in), out); - } - - /** - * Performs all changes collected in this ChangeSet on the input entries and - * streams the result to the output stream. - * - * This method finishes the stream, no other entries should be added - * after that. - * - * @param entryIterator - * the entries to perform the changes on - * @param out - * the resulting OutputStream with all modifications - * @throws IOException - * if an read/write error occurs - * @return the results of this operation - */ - private ChangeSetResults perform(final ArchiveEntryIterator entryIterator, - final ArchiveOutputStream out) - throws IOException { - final ChangeSetResults results = new ChangeSetResults(); - - final Set workingSet = new LinkedHashSet<>(changes); - - for (final Iterator it = workingSet.iterator(); it.hasNext();) { - final Change change = it.next(); - - if (change.type() == Change.TYPE_ADD && change.isReplaceMode()) { - copyStream(change.getInput(), out, change.getEntry()); - it.remove(); - results.addedFromChangeSet(change.getEntry().getName()); - } - } - - while (entryIterator.hasNext()) { - final ArchiveEntry entry = entryIterator.next(); - boolean copy = true; - - for (final Iterator it = workingSet.iterator(); it.hasNext();) { - final Change change = it.next(); - - final int type = change.type(); - final String name = entry.getName(); - if (type == Change.TYPE_DELETE && name != null) { - if (name.equals(change.targetFile())) { - copy = false; - it.remove(); - results.deleted(name); - break; - } - } else if (type == Change.TYPE_DELETE_DIR && name != null) { - // don't combine ifs to make future extensions more easy - if (name.startsWith(change.targetFile() + "/")) { // NOPMD - copy = false; - results.deleted(name); - break; - } - } - } - - if (copy - && !isDeletedLater(workingSet, entry) - && !results.hasBeenAdded(entry.getName())) { - copyStream(entryIterator.getInputStream(), out, entry); - results.addedFromStream(entry.getName()); - } - } - - // Adds files which hasn't been added from the original and do not have replace mode on - for (final Iterator it = workingSet.iterator(); it.hasNext();) { - final Change change = it.next(); - - if (change.type() == Change.TYPE_ADD && - !change.isReplaceMode() && - !results.hasBeenAdded(change.getEntry().getName())) { - copyStream(change.getInput(), out, change.getEntry()); - it.remove(); - results.addedFromChangeSet(change.getEntry().getName()); - } - } - out.finish(); - return results; - } - - /** - * Checks if an ArchiveEntry is deleted later in the ChangeSet. This is - * necessary if an file is added with this ChangeSet, but later became - * deleted in the same set. - * - * @param entry - * the entry to check - * @return true, if this entry has an deletion change later, false otherwise - */ - private boolean isDeletedLater(final Set workingSet, final ArchiveEntry entry) { - final String source = entry.getName(); - - if (!workingSet.isEmpty()) { - for (final Change change : workingSet) { - final int type = change.type(); - final String target = change.targetFile(); - if (type == Change.TYPE_DELETE && source.equals(target)) { - return true; - } - - if (type == Change.TYPE_DELETE_DIR && source.startsWith(target + "/")){ - return true; - } - } - } - return false; - } - - /** - * Copies the ArchiveEntry to the Output stream - * - * @param in - * the stream to read the data from - * @param out - * the stream to write the data to - * @param entry - * the entry to write - * @throws IOException - * if data cannot be read or written - */ - private void copyStream(final InputStream in, final ArchiveOutputStream out, - final ArchiveEntry entry) throws IOException { - out.putArchiveEntry(entry); - IOUtils.copy(in, out); - out.closeArchiveEntry(); - } - - /** - * Used in perform to abstract out getting entries and streams for - * those entries. - * - *

Iterator#hasNext is not allowed to throw exceptions that's - * why we can't use Iterator<ArchiveEntry> directly - - * otherwise we'd need to convert exceptions thrown in - * ArchiveInputStream#getNextEntry.

- */ - interface ArchiveEntryIterator { - boolean hasNext() throws IOException; - ArchiveEntry next(); - InputStream getInputStream() throws IOException; - } - - private static class ArchiveInputStreamIterator - implements ArchiveEntryIterator { - private final ArchiveInputStream in; - private ArchiveEntry next; - ArchiveInputStreamIterator(final ArchiveInputStream in) { - this.in = in; - } - @Override - public boolean hasNext() throws IOException { - return (next = in.getNextEntry()) != null; - } - @Override - public ArchiveEntry next() { - return next; - } - @Override - public InputStream getInputStream() { - return in; - } - } - - private static class ZipFileIterator - implements ArchiveEntryIterator { - private final ZipFile in; - private final Enumeration nestedEnum; - private ZipArchiveEntry current; - ZipFileIterator(final ZipFile in) { - this.in = in; - nestedEnum = in.getEntriesInPhysicalOrder(); - } - @Override - public boolean hasNext() { - return nestedEnum.hasMoreElements(); - } - @Override - public ArchiveEntry next() { - current = nestedEnum.nextElement(); - return current; - } - @Override - public InputStream getInputStream() throws IOException { - return in.getInputStream(current); - } - } -} diff --git a/src/org/apache/commons/compress/changes/ChangeSetResults.java b/src/org/apache/commons/compress/changes/ChangeSetResults.java deleted file mode 100644 index 788dccfaee4..00000000000 --- a/src/org/apache/commons/compress/changes/ChangeSetResults.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.changes; - -import java.util.ArrayList; -import java.util.List; - -/** - * Stores the results of an performed ChangeSet operation. - */ -public class ChangeSetResults { - private final List addedFromChangeSet = new ArrayList<>(); - private final List addedFromStream = new ArrayList<>(); - private final List deleted = new ArrayList<>(); - - /** - * Adds the filename of a recently deleted file to the result list. - * @param fileName the file which has been deleted - */ - void deleted(final String fileName) { - deleted.add(fileName); - } - - /** - * Adds the name of a file to the result list which has been - * copied from the source stream to the target stream. - * @param fileName the file name which has been added from the original stream - */ - void addedFromStream(final String fileName) { - addedFromStream.add(fileName); - } - - /** - * Adds the name of a file to the result list which has been - * copied from the changeset to the target stream - * @param fileName the name of the file - */ - void addedFromChangeSet(final String fileName) { - addedFromChangeSet.add(fileName); - } - - /** - * Returns a list of filenames which has been added from the changeset - * @return the list of filenames - */ - public List getAddedFromChangeSet() { - return addedFromChangeSet; - } - - /** - * Returns a list of filenames which has been added from the original stream - * @return the list of filenames - */ - public List getAddedFromStream() { - return addedFromStream; - } - - /** - * Returns a list of filenames which has been deleted - * @return the list of filenames - */ - public List getDeleted() { - return deleted; - } - - /** - * Checks if an filename already has been added to the result list - * @param filename the filename to check - * @return true, if this filename already has been added - */ - boolean hasBeenAdded(final String filename) { - return addedFromChangeSet.contains(filename) || addedFromStream.contains(filename); - } -} diff --git a/src/org/apache/commons/compress/changes/package.html b/src/org/apache/commons/compress/changes/package.html deleted file mode 100644 index 4ba3e87d090..00000000000 --- a/src/org/apache/commons/compress/changes/package.html +++ /dev/null @@ -1,27 +0,0 @@ - - - -

EXPERIMENTAL support for changesets that are applied to - archives.

- -

This API is considered unstable and may be modified or even - removed in future releases.

- - diff --git a/src/org/apache/commons/compress/compressors/CompressorException.java b/src/org/apache/commons/compress/compressors/CompressorException.java deleted file mode 100644 index 9af3e69699c..00000000000 --- a/src/org/apache/commons/compress/compressors/CompressorException.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors; - -/** - * Compressor related exception - */ -public class CompressorException extends Exception { - - /** Serial */ - private static final long serialVersionUID = -2932901310255908814L; - - /** - * Constructs a new exception with the specified detail message. The cause - * is not initialized. - * - * @param message - * the detail message - */ - public CompressorException(final String message) { - super(message); - } - - /** - * Constructs a new exception with the specified detail message and cause. - * - * @param message - * the detail message - * @param cause - * the cause - */ - public CompressorException(final String message, final Throwable cause) { - super(message, cause); - } -} diff --git a/src/org/apache/commons/compress/compressors/CompressorInputStream.java b/src/org/apache/commons/compress/compressors/CompressorInputStream.java deleted file mode 100644 index 67de705a274..00000000000 --- a/src/org/apache/commons/compress/compressors/CompressorInputStream.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors; - -import java.io.InputStream; - -public abstract class CompressorInputStream extends InputStream { - private long bytesRead = 0; - - /** - * Increments the counter of already read bytes. - * Doesn't increment if the EOF has been hit (read == -1) - * - * @param read the number of bytes read - * - * @since 1.1 - */ - protected void count(final int read) { - count((long) read); - } - - /** - * Increments the counter of already read bytes. - * Doesn't increment if the EOF has been hit (read == -1) - * - * @param read the number of bytes read - */ - protected void count(final long read) { - if (read != -1) { - bytesRead = bytesRead + read; - } - } - - /** - * Decrements the counter of already read bytes. - * - * @param pushedBack the number of bytes pushed back. - * @since 1.7 - */ - protected void pushedBackBytes(final long pushedBack) { - bytesRead -= pushedBack; - } - - /** - * Returns the current number of bytes read from this stream. - * @return the number of read bytes - * @deprecated this method may yield wrong results for large - * archives, use #getBytesRead instead - */ - @Deprecated - public int getCount() { - return (int) bytesRead; - } - - /** - * Returns the current number of bytes read from this stream. - * @return the number of read bytes - * - * @since 1.1 - */ - public long getBytesRead() { - return bytesRead; - } - - /** - * Returns the amount of raw or compressed bytes read by the stream. - * - *

This implementation invokes {@link #getBytesRead}.

- * - *

Provides half of {@link - * org.apache.commons.compress.utils.InputStreamStatistics} - * without forcing subclasses to implement the other half.

- * - * @return the amount of decompressed bytes returned by the stream - * @since 1.17 - */ - public long getUncompressedCount() { - return getBytesRead(); - } -} diff --git a/src/org/apache/commons/compress/compressors/CompressorOutputStream.java b/src/org/apache/commons/compress/compressors/CompressorOutputStream.java deleted file mode 100644 index 51eee9cee61..00000000000 --- a/src/org/apache/commons/compress/compressors/CompressorOutputStream.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors; - -import java.io.OutputStream; - -public abstract class CompressorOutputStream extends OutputStream { - // TODO -} diff --git a/src/org/apache/commons/compress/compressors/CompressorStreamFactory.java b/src/org/apache/commons/compress/compressors/CompressorStreamFactory.java deleted file mode 100644 index d730b9de41f..00000000000 --- a/src/org/apache/commons/compress/compressors/CompressorStreamFactory.java +++ /dev/null @@ -1,797 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.Locale; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; - -import org.apache.commons.compress.compressors.brotli.BrotliCompressorInputStream; -import org.apache.commons.compress.compressors.brotli.BrotliUtils; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; -import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream; -import org.apache.commons.compress.compressors.deflate.DeflateCompressorOutputStream; -import org.apache.commons.compress.compressors.deflate64.Deflate64CompressorInputStream; -import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; -import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; -import org.apache.commons.compress.compressors.lz4.BlockLZ4CompressorInputStream; -import org.apache.commons.compress.compressors.lz4.BlockLZ4CompressorOutputStream; -import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorInputStream; -import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorOutputStream; -import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream; -import org.apache.commons.compress.compressors.lzma.LZMACompressorOutputStream; -import org.apache.commons.compress.compressors.lzma.LZMAUtils; -import org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream; -import org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream; -import org.apache.commons.compress.compressors.snappy.FramedSnappyCompressorInputStream; -import org.apache.commons.compress.compressors.snappy.FramedSnappyCompressorOutputStream; -import org.apache.commons.compress.compressors.snappy.SnappyCompressorInputStream; -import org.apache.commons.compress.compressors.xz.XZCompressorInputStream; -import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream; -import org.apache.commons.compress.compressors.xz.XZUtils; -import org.apache.commons.compress.compressors.z.ZCompressorInputStream; -import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream; -import org.apache.commons.compress.compressors.zstandard.ZstdCompressorOutputStream; -import org.apache.commons.compress.compressors.zstandard.ZstdUtils; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.compress.utils.ServiceLoaderIterator; -import org.apache.commons.compress.utils.Sets; - -/** - *

- * Factory to create Compressor[In|Out]putStreams from names. To add other - * implementations you should extend CompressorStreamFactory and override the - * appropriate methods (and call their implementation from super of course). - *

- * - * Example (Compressing a file): - * - *
- * final OutputStream out = Files.newOutputStream(output.toPath());
- * CompressorOutputStream cos = new CompressorStreamFactory()
- *         .createCompressorOutputStream(CompressorStreamFactory.BZIP2, out);
- * IOUtils.copy(Files.newInputStream(input.toPath()), cos);
- * cos.close();
- * 
- * - * Example (Decompressing a file): - * - *
- * final InputStream is = Files.newInputStream(input.toPath());
- * CompressorInputStream in = new CompressorStreamFactory().createCompressorInputStream(CompressorStreamFactory.BZIP2,
- *         is);
- * IOUtils.copy(in, Files.newOutputStream(output.toPath()));
- * in.close();
- * 
- * - * @Immutable provided that the deprecated method setDecompressConcatenated is - * not used. - * @ThreadSafe even if the deprecated method setDecompressConcatenated is used - */ -public class CompressorStreamFactory implements CompressorStreamProvider { - - private static final CompressorStreamFactory SINGLETON = new CompressorStreamFactory(); - - - - /** - * Constant (value {@value}) used to identify the BROTLI compression - * algorithm. - * - * @since 1.14 - */ - public static final String BROTLI = "br"; - - /** - * Constant (value {@value}) used to identify the BZIP2 compression - * algorithm. - * - * @since 1.1 - */ - public static final String BZIP2 = "bzip2"; - - /** - * Constant (value {@value}) used to identify the GZIP compression - * algorithm. - * - * @since 1.1 - */ - public static final String GZIP = "gz"; - - /** - * Constant (value {@value}) used to identify the PACK200 compression - * algorithm. - * - * @since 1.3 - */ - public static final String PACK200 = "pack200"; - - /** - * Constant (value {@value}) used to identify the XZ compression method. - * - * @since 1.4 - */ - public static final String XZ = "xz"; - - /** - * Constant (value {@value}) used to identify the LZMA compression method. - * - * @since 1.6 - */ - public static final String LZMA = "lzma"; - - /** - * Constant (value {@value}) used to identify the "framed" Snappy - * compression method. - * - * @since 1.7 - */ - public static final String SNAPPY_FRAMED = "snappy-framed"; - - /** - * Constant (value {@value}) used to identify the "raw" Snappy compression - * method. Not supported as an output stream type. - * - * @since 1.7 - */ - public static final String SNAPPY_RAW = "snappy-raw"; - - /** - * Constant (value {@value}) used to identify the traditional Unix compress - * method. Not supported as an output stream type. - * - * @since 1.7 - */ - public static final String Z = "z"; - - /** - * Constant (value {@value}) used to identify the Deflate compress method. - * - * @since 1.9 - */ - public static final String DEFLATE = "deflate"; - - /** - * Constant (value {@value}) used to identify the Deflate64 compress method. - * - * @since 1.16 - */ - public static final String DEFLATE64 = "deflate64"; - - /** - * Constant (value {@value}) used to identify the block LZ4 - * compression method. - * - * @since 1.14 - */ - public static final String LZ4_BLOCK = "lz4-block"; - - /** - * Constant (value {@value}) used to identify the frame LZ4 - * compression method. - * - * @since 1.14 - */ - public static final String LZ4_FRAMED = "lz4-framed"; - - /** - * Constant (value {@value}) used to identify the Zstandard compression - * algorithm. Not supported as an output stream type. - * - * @since 1.16 - */ - public static final String ZSTANDARD = "zstd"; - - private static final String YOU_NEED_BROTLI_DEC = youNeed("Google Brotli Dec", "https://github.com/google/brotli/"); - private static final String YOU_NEED_XZ_JAVA = youNeed("XZ for Java", "https://tukaani.org/xz/java.html"); - private static final String YOU_NEED_ZSTD_JNI = youNeed("Zstd JNI", "https://github.com/luben/zstd-jni"); - - private static String youNeed(String name, String url) { - return " In addition to Apache Commons Compress you need the " + name + " library - see " + url; - } - - /** - * Constructs a new sorted map from input stream provider names to provider - * objects. - * - *

- * The map returned by this method will have one entry for each provider for - * which support is available in the current Java virtual machine. If two or - * more supported provider have the same name then the resulting map will - * contain just one of them; which one it will contain is not specified. - *

- * - *

- * The invocation of this method, and the subsequent use of the resulting - * map, may cause time-consuming disk or network I/O operations to occur. - * This method is provided for applications that need to enumerate all of - * the available providers, for example to allow user provider selection. - *

- * - *

- * This method may return different results at different times if new - * providers are dynamically made available to the current Java virtual - * machine. - *

- * - * @return An immutable, map from names to provider objects - * @since 1.13 - */ - public static SortedMap findAvailableCompressorInputStreamProviders() { - return AccessController.doPrivileged(new PrivilegedAction>() { - @Override - public SortedMap run() { - final TreeMap map = new TreeMap<>(); - putAll(SINGLETON.getInputStreamCompressorNames(), SINGLETON, map); - for (final CompressorStreamProvider provider : findCompressorStreamProviders()) { - putAll(provider.getInputStreamCompressorNames(), provider, map); - } - return map; - } - }); - } - - /** - * Constructs a new sorted map from output stream provider names to provider - * objects. - * - *

- * The map returned by this method will have one entry for each provider for - * which support is available in the current Java virtual machine. If two or - * more supported provider have the same name then the resulting map will - * contain just one of them; which one it will contain is not specified. - *

- * - *

- * The invocation of this method, and the subsequent use of the resulting - * map, may cause time-consuming disk or network I/O operations to occur. - * This method is provided for applications that need to enumerate all of - * the available providers, for example to allow user provider selection. - *

- * - *

- * This method may return different results at different times if new - * providers are dynamically made available to the current Java virtual - * machine. - *

- * - * @return An immutable, map from names to provider objects - * @since 1.13 - */ - public static SortedMap findAvailableCompressorOutputStreamProviders() { - return AccessController.doPrivileged(new PrivilegedAction>() { - @Override - public SortedMap run() { - final TreeMap map = new TreeMap<>(); - putAll(SINGLETON.getOutputStreamCompressorNames(), SINGLETON, map); - for (final CompressorStreamProvider provider : findCompressorStreamProviders()) { - putAll(provider.getOutputStreamCompressorNames(), provider, map); - } - return map; - } - - }); - } - private static ArrayList findCompressorStreamProviders() { - return Lists.newArrayList(serviceLoaderIterator()); - } - - public static String getBrotli() { - return BROTLI; - } - - public static String getBzip2() { - return BZIP2; - } - - public static String getDeflate() { - return DEFLATE; - } - - /** - * @since 1.16 - * @return the constant {@link #DEFLATE64} - */ - public static String getDeflate64() { - return DEFLATE64; - } - - public static String getGzip() { - return GZIP; - } - - public static String getLzma() { - return LZMA; - } - - public static String getPack200() { - return PACK200; - } - - public static CompressorStreamFactory getSingleton() { - return SINGLETON; - } - - public static String getSnappyFramed() { - return SNAPPY_FRAMED; - } - - public static String getSnappyRaw() { - return SNAPPY_RAW; - } - - public static String getXz() { - return XZ; - } - - public static String getZ() { - return Z; - } - - public static String getLZ4Framed() { - return LZ4_FRAMED; - } - - public static String getLZ4Block() { - return LZ4_BLOCK; - } - - public static String getZstandard() { - return ZSTANDARD; - } - - static void putAll(final Set names, final CompressorStreamProvider provider, - final TreeMap map) { - for (final String name : names) { - map.put(toKey(name), provider); - } - } - - private static Iterator serviceLoaderIterator() { - return new ServiceLoaderIterator<>(CompressorStreamProvider.class); - } - - private static String toKey(final String name) { - return name.toUpperCase(Locale.ROOT); - } - - /** - * If true, decompress until the end of the input. If false, stop after the - * first stream and leave the input position to point to the next byte after - * the stream - */ - private final Boolean decompressUntilEOF; - // This is Boolean so setDecompressConcatenated can determine whether it has - // been set by the ctor - // once the setDecompressConcatenated method has been removed, it can revert - // to boolean - - private SortedMap compressorInputStreamProviders; - - private SortedMap compressorOutputStreamProviders; - - /** - * If true, decompress until the end of the input. If false, stop after the - * first stream and leave the input position to point to the next byte after - * the stream - */ - private volatile boolean decompressConcatenated = false; - - private final int memoryLimitInKb; - /** - * Create an instance with the decompress Concatenated option set to false. - */ - public CompressorStreamFactory() { - this.decompressUntilEOF = null; - this.memoryLimitInKb = -1; - } - - /** - * Create an instance with the provided decompress Concatenated option. - * - * @param decompressUntilEOF - * if true, decompress until the end of the input; if false, stop - * after the first stream and leave the input position to point - * to the next byte after the stream. This setting applies to the - * gzip, bzip2 and xz formats only. - * - * @param memoryLimitInKb - * Some streams require allocation of potentially significant - * byte arrays/tables, and they can offer checks to prevent OOMs - * on corrupt files. Set the maximum allowed memory allocation in KBs. - * - * @since 1.14 - */ - public CompressorStreamFactory(final boolean decompressUntilEOF, final int memoryLimitInKb) { - this.decompressUntilEOF = decompressUntilEOF; - // Also copy to existing variable so can continue to use that as the - // current value - this.decompressConcatenated = decompressUntilEOF; - this.memoryLimitInKb = memoryLimitInKb; - } - - - /** - * Create an instance with the provided decompress Concatenated option. - * - * @param decompressUntilEOF - * if true, decompress until the end of the input; if false, stop - * after the first stream and leave the input position to point - * to the next byte after the stream. This setting applies to the - * gzip, bzip2 and xz formats only. - * @since 1.10 - */ - public CompressorStreamFactory(final boolean decompressUntilEOF) { - this(decompressUntilEOF, -1); - } - - /** - * Try to detect the type of compressor stream. - * - * @param in input stream - * @return type of compressor stream detected - * @throws CompressorException if no compressor stream type was detected - * or if something else went wrong - * @throws IllegalArgumentException if stream is null or does not support mark - * - * @since 1.14 - */ - public static String detect(final InputStream in) throws CompressorException { - if (in == null) { - throw new IllegalArgumentException("Stream must not be null."); - } - - if (!in.markSupported()) { - throw new IllegalArgumentException("Mark is not supported."); - } - - final byte[] signature = new byte[12]; - in.mark(signature.length); - int signatureLength = -1; - try { - signatureLength = IOUtils.readFully(in, signature); - in.reset(); - } catch (IOException e) { - throw new CompressorException("IOException while reading signature.", e); - } - - if (BZip2CompressorInputStream.matches(signature, signatureLength)) { - return BZIP2; - } - - if (GzipCompressorInputStream.matches(signature, signatureLength)) { - return GZIP; - } - - if (Pack200CompressorInputStream.matches(signature, signatureLength)) { - return PACK200; - } - - if (FramedSnappyCompressorInputStream.matches(signature, signatureLength)) { - return SNAPPY_FRAMED; - } - - if (ZCompressorInputStream.matches(signature, signatureLength)) { - return Z; - } - - if (DeflateCompressorInputStream.matches(signature, signatureLength)) { - return DEFLATE; - } - - if (XZUtils.matches(signature, signatureLength)) { - return XZ; - } - - if (LZMAUtils.matches(signature, signatureLength)) { - return LZMA; - } - - if (FramedLZ4CompressorInputStream.matches(signature, signatureLength)) { - return LZ4_FRAMED; - } - - if (ZstdUtils.matches(signature, signatureLength)) { - return ZSTANDARD; - } - - throw new CompressorException("No Compressor found for the stream signature."); - } - /** - * Create an compressor input stream from an input stream, autodetecting the - * compressor type from the first few bytes of the stream. The InputStream - * must support marks, like BufferedInputStream. - * - * @param in - * the input stream - * @return the compressor input stream - * @throws CompressorException - * if the compressor name is not known - * @throws IllegalArgumentException - * if the stream is null or does not support mark - * @since 1.1 - */ - public CompressorInputStream createCompressorInputStream(final InputStream in) throws CompressorException { - return createCompressorInputStream(detect(in), in); - } - - /** - * Creates a compressor input stream from a compressor name and an input - * stream. - * - * @param name - * of the compressor, i.e. {@value #GZIP}, {@value #BZIP2}, - * {@value #XZ}, {@value #LZMA}, {@value #PACK200}, - * {@value #SNAPPY_RAW}, {@value #SNAPPY_FRAMED}, {@value #Z}, - * {@value #LZ4_BLOCK}, {@value #LZ4_FRAMED}, {@value #ZSTANDARD}, - * {@value #DEFLATE64} - * or {@value #DEFLATE} - * @param in - * the input stream - * @return compressor input stream - * @throws CompressorException - * if the compressor name is not known or not available, - * or if there's an IOException or MemoryLimitException thrown - * during initialization - * @throws IllegalArgumentException - * if the name or input stream is null - */ - public CompressorInputStream createCompressorInputStream(final String name, final InputStream in) - throws CompressorException { - return createCompressorInputStream(name, in, decompressConcatenated); - } - - @Override - public CompressorInputStream createCompressorInputStream(final String name, final InputStream in, - final boolean actualDecompressConcatenated) throws CompressorException { - if (name == null || in == null) { - throw new IllegalArgumentException("Compressor name and stream must not be null."); - } - - try { - - if (GZIP.equalsIgnoreCase(name)) { - return new GzipCompressorInputStream(in, actualDecompressConcatenated); - } - - if (BZIP2.equalsIgnoreCase(name)) { - return new BZip2CompressorInputStream(in, actualDecompressConcatenated); - } - - if (BROTLI.equalsIgnoreCase(name)) { - if (!BrotliUtils.isBrotliCompressionAvailable()) { - throw new CompressorException("Brotli compression is not available." + YOU_NEED_BROTLI_DEC); - } - return new BrotliCompressorInputStream(in); - } - - if (XZ.equalsIgnoreCase(name)) { - if (!XZUtils.isXZCompressionAvailable()) { - throw new CompressorException("XZ compression is not available." + YOU_NEED_XZ_JAVA); - } - return new XZCompressorInputStream(in, actualDecompressConcatenated, memoryLimitInKb); - } - - if (ZSTANDARD.equalsIgnoreCase(name)) { - if (!ZstdUtils.isZstdCompressionAvailable()) { - throw new CompressorException("Zstandard compression is not available." + YOU_NEED_ZSTD_JNI); - } - return new ZstdCompressorInputStream(in); - } - - if (LZMA.equalsIgnoreCase(name)) { - if (!LZMAUtils.isLZMACompressionAvailable()) { - throw new CompressorException("LZMA compression is not available" + YOU_NEED_XZ_JAVA); - } - return new LZMACompressorInputStream(in, memoryLimitInKb); - } - - if (PACK200.equalsIgnoreCase(name)) { - return new Pack200CompressorInputStream(in); - } - - if (SNAPPY_RAW.equalsIgnoreCase(name)) { - return new SnappyCompressorInputStream(in); - } - - if (SNAPPY_FRAMED.equalsIgnoreCase(name)) { - return new FramedSnappyCompressorInputStream(in); - } - - if (Z.equalsIgnoreCase(name)) { - return new ZCompressorInputStream(in, memoryLimitInKb); - } - - if (DEFLATE.equalsIgnoreCase(name)) { - return new DeflateCompressorInputStream(in); - } - - if (DEFLATE64.equalsIgnoreCase(name)) { - return new Deflate64CompressorInputStream(in); - } - - if (LZ4_BLOCK.equalsIgnoreCase(name)) { - return new BlockLZ4CompressorInputStream(in); - } - - if (LZ4_FRAMED.equalsIgnoreCase(name)) { - return new FramedLZ4CompressorInputStream(in, actualDecompressConcatenated); - } - - } catch (final IOException e) { - throw new CompressorException("Could not create CompressorInputStream.", e); - } - final CompressorStreamProvider compressorStreamProvider = getCompressorInputStreamProviders().get(toKey(name)); - if (compressorStreamProvider != null) { - return compressorStreamProvider.createCompressorInputStream(name, in, actualDecompressConcatenated); - } - - throw new CompressorException("Compressor: " + name + " not found."); - } - - /** - * Creates an compressor output stream from an compressor name and an output - * stream. - * - * @param name - * the compressor name, i.e. {@value #GZIP}, {@value #BZIP2}, - * {@value #XZ}, {@value #PACK200}, {@value #SNAPPY_FRAMED}, - * {@value #LZ4_BLOCK}, {@value #LZ4_FRAMED}, {@value #ZSTANDARD} - * or {@value #DEFLATE} - * @param out - * the output stream - * @return the compressor output stream - * @throws CompressorException - * if the archiver name is not known - * @throws IllegalArgumentException - * if the archiver name or stream is null - */ - @Override - public CompressorOutputStream createCompressorOutputStream(final String name, final OutputStream out) - throws CompressorException { - if (name == null || out == null) { - throw new IllegalArgumentException("Compressor name and stream must not be null."); - } - - try { - - if (GZIP.equalsIgnoreCase(name)) { - return new GzipCompressorOutputStream(out); - } - - if (BZIP2.equalsIgnoreCase(name)) { - return new BZip2CompressorOutputStream(out); - } - - if (XZ.equalsIgnoreCase(name)) { - return new XZCompressorOutputStream(out); - } - - if (PACK200.equalsIgnoreCase(name)) { - return new Pack200CompressorOutputStream(out); - } - - if (LZMA.equalsIgnoreCase(name)) { - return new LZMACompressorOutputStream(out); - } - - if (DEFLATE.equalsIgnoreCase(name)) { - return new DeflateCompressorOutputStream(out); - } - - if (SNAPPY_FRAMED.equalsIgnoreCase(name)) { - return new FramedSnappyCompressorOutputStream(out); - } - - if (LZ4_BLOCK.equalsIgnoreCase(name)) { - return new BlockLZ4CompressorOutputStream(out); - } - - if (LZ4_FRAMED.equalsIgnoreCase(name)) { - return new FramedLZ4CompressorOutputStream(out); - } - - if (ZSTANDARD.equalsIgnoreCase(name)) { - return new ZstdCompressorOutputStream(out); - } - } catch (final IOException e) { - throw new CompressorException("Could not create CompressorOutputStream", e); - } - final CompressorStreamProvider compressorStreamProvider = getCompressorOutputStreamProviders().get(toKey(name)); - if (compressorStreamProvider != null) { - return compressorStreamProvider.createCompressorOutputStream(name, out); - } - throw new CompressorException("Compressor: " + name + " not found."); - } - - public SortedMap getCompressorInputStreamProviders() { - if (compressorInputStreamProviders == null) { - compressorInputStreamProviders = Collections - .unmodifiableSortedMap(findAvailableCompressorInputStreamProviders()); - } - return compressorInputStreamProviders; - } - - public SortedMap getCompressorOutputStreamProviders() { - if (compressorOutputStreamProviders == null) { - compressorOutputStreamProviders = Collections - .unmodifiableSortedMap(findAvailableCompressorOutputStreamProviders()); - } - return compressorOutputStreamProviders; - } - - // For Unit tests - boolean getDecompressConcatenated() { - return decompressConcatenated; - } - - public Boolean getDecompressUntilEOF() { - return decompressUntilEOF; - } - - @Override - public Set getInputStreamCompressorNames() { - return Sets.newHashSet(GZIP, BROTLI, BZIP2, XZ, LZMA, PACK200, DEFLATE, SNAPPY_RAW, SNAPPY_FRAMED, Z, LZ4_BLOCK, - LZ4_FRAMED, ZSTANDARD, DEFLATE64); - } - - @Override - public Set getOutputStreamCompressorNames() { - return Sets.newHashSet(GZIP, BZIP2, XZ, LZMA, PACK200, DEFLATE, SNAPPY_FRAMED, LZ4_BLOCK, LZ4_FRAMED, ZSTANDARD); - } - - /** - * Whether to decompress the full input or only the first stream in formats - * supporting multiple concatenated input streams. - * - *

- * This setting applies to the gzip, bzip2 and xz formats only. - *

- * - * @param decompressConcatenated - * if true, decompress until the end of the input; if false, stop - * after the first stream and leave the input position to point - * to the next byte after the stream - * @since 1.5 - * @deprecated 1.10 use the {@link #CompressorStreamFactory(boolean)} - * constructor instead - * @throws IllegalStateException - * if the constructor {@link #CompressorStreamFactory(boolean)} - * was used to create the factory - */ - @Deprecated - public void setDecompressConcatenated(final boolean decompressConcatenated) { - if (this.decompressUntilEOF != null) { - throw new IllegalStateException("Cannot override the setting defined by the constructor"); - } - this.decompressConcatenated = decompressConcatenated; - } - -} diff --git a/src/org/apache/commons/compress/compressors/CompressorStreamProvider.java b/src/org/apache/commons/compress/compressors/CompressorStreamProvider.java deleted file mode 100644 index b0c843123b8..00000000000 --- a/src/org/apache/commons/compress/compressors/CompressorStreamProvider.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Set; - -/** - * Creates Compressor {@link CompressorInputStream}s and - * {@link CompressorOutputStream}s. - * - * @since 1.13 - */ -public interface CompressorStreamProvider { - - /** - * Creates a compressor input stream from a compressor name and an input - * stream. - * - * @param name - * of the compressor, i.e. - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#GZIP}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#BZIP2}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#XZ}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#LZMA}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#PACK200}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#SNAPPY_RAW}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#SNAPPY_FRAMED}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#Z} - * or - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#DEFLATE} - * @param in - * the input stream - * @param decompressUntilEOF - * if true, decompress until the end of the input; if false, stop - * after the first stream and leave the input position to point - * to the next byte after the stream. This setting applies to the - * gzip, bzip2 and xz formats only. - * @return compressor input stream - * @throws CompressorException - * if the compressor name is not known - * @throws IllegalArgumentException - * if the name or input stream is null - */ - CompressorInputStream createCompressorInputStream(final String name, final InputStream in, - final boolean decompressUntilEOF) throws CompressorException; - - /** - * Creates a compressor output stream from an compressor name and an output - * stream. - * - * @param name - * the compressor name, i.e. - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#GZIP}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#BZIP2}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#XZ}, - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#PACK200} - * or - * {@value org.apache.commons.compress.compressors.CompressorStreamFactory#DEFLATE} - * @param out - * the output stream - * @return the compressor output stream - * @throws CompressorException - * if the archiver name is not known - * @throws IllegalArgumentException - * if the archiver name or stream is null - */ - CompressorOutputStream createCompressorOutputStream(final String name, final OutputStream out) - throws CompressorException; - - /** - * Gets all the input stream compressor names for this provider - * - * @return all the input compressor names for this provider - */ - Set getInputStreamCompressorNames(); - - /** - * Gets all the output stream compressor names for this provider - * - * @return all the output compressor names for this provider - */ - Set getOutputStreamCompressorNames(); - -} diff --git a/src/org/apache/commons/compress/compressors/FileNameUtil.java b/src/org/apache/commons/compress/compressors/FileNameUtil.java deleted file mode 100644 index f97bb8e4149..00000000000 --- a/src/org/apache/commons/compress/compressors/FileNameUtil.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -/** - * File name mapping code for the compression formats. - * @ThreadSafe - * @since 1.4 - */ -public class FileNameUtil { - - /** - * Map from common filename suffixes to the suffixes that identify compressed - * versions of those file types. For example: from ".tar" to ".tgz". - */ - private final Map compressSuffix = - new HashMap<>(); - - /** - * Map from common filename suffixes of compressed files to the - * corresponding suffixes of uncompressed files. For example: from - * ".tgz" to ".tar". - *

- * This map also contains format-specific suffixes like ".gz" and "-z". - * These suffixes are mapped to the empty string, as they should simply - * be removed from the filename when the file is uncompressed. - */ - private final Map uncompressSuffix; - - /** - * Length of the longest compressed suffix. - */ - private final int longestCompressedSuffix; - - /** - * Length of the shortest compressed suffix. - */ - private final int shortestCompressedSuffix; - - /** - * Length of the longest uncompressed suffix. - */ - private final int longestUncompressedSuffix; - - /** - * Length of the shortest uncompressed suffix longer than the - * empty string. - */ - private final int shortestUncompressedSuffix; - - /** - * The format's default extension. - */ - private final String defaultExtension; - - /** - * sets up the utility with a map of known compressed to - * uncompressed suffix mappings and the default extension of the - * format. - * - * @param uncompressSuffix Map from common filename suffixes of - * compressed files to the corresponding suffixes of uncompressed - * files. For example: from ".tgz" to ".tar". This map also - * contains format-specific suffixes like ".gz" and "-z". These - * suffixes are mapped to the empty string, as they should simply - * be removed from the filename when the file is uncompressed. - * - * @param defaultExtension the format's default extension like ".gz" - */ - public FileNameUtil(final Map uncompressSuffix, - final String defaultExtension) { - this.uncompressSuffix = Collections.unmodifiableMap(uncompressSuffix); - int lc = Integer.MIN_VALUE, sc = Integer.MAX_VALUE; - int lu = Integer.MIN_VALUE, su = Integer.MAX_VALUE; - for (final Map.Entry ent : uncompressSuffix.entrySet()) { - final int cl = ent.getKey().length(); - if (cl > lc) { - lc = cl; - } - if (cl < sc) { - sc = cl; - } - - final String u = ent.getValue(); - final int ul = u.length(); - if (ul > 0) { - if (!compressSuffix.containsKey(u)) { - compressSuffix.put(u, ent.getKey()); - } - if (ul > lu) { - lu = ul; - } - if (ul < su) { - su = ul; - } - } - } - longestCompressedSuffix = lc; - longestUncompressedSuffix = lu; - shortestCompressedSuffix = sc; - shortestUncompressedSuffix = su; - this.defaultExtension = defaultExtension; - } - - /** - * Detects common format suffixes in the given filename. - * - * @param filename name of a file - * @return {@code true} if the filename has a common format suffix, - * {@code false} otherwise - */ - public boolean isCompressedFilename(final String filename) { - final String lower = filename.toLowerCase(Locale.ENGLISH); - final int n = lower.length(); - for (int i = shortestCompressedSuffix; - i <= longestCompressedSuffix && i < n; i++) { - if (uncompressSuffix.containsKey(lower.substring(n - i))) { - return true; - } - } - return false; - } - - /** - * Maps the given name of a compressed file to the name that the - * file should have after uncompression. Commonly used file type specific - * suffixes like ".tgz" or ".svgz" are automatically detected and - * correctly mapped. For example the name "package.tgz" is mapped to - * "package.tar". And any filenames with the generic ".gz" suffix - * (or any other generic gzip suffix) is mapped to a name without that - * suffix. If no format suffix is detected, then the filename is returned - * unmapped. - * - * @param filename name of a file - * @return name of the corresponding uncompressed file - */ - public String getUncompressedFilename(final String filename) { - final String lower = filename.toLowerCase(Locale.ENGLISH); - final int n = lower.length(); - for (int i = shortestCompressedSuffix; - i <= longestCompressedSuffix && i < n; i++) { - final String suffix = uncompressSuffix.get(lower.substring(n - i)); - if (suffix != null) { - return filename.substring(0, n - i) + suffix; - } - } - return filename; - } - - /** - * Maps the given filename to the name that the file should have after - * compression. Common file types with custom suffixes for - * compressed versions are automatically detected and correctly mapped. - * For example the name "package.tar" is mapped to "package.tgz". If no - * custom mapping is applicable, then the default ".gz" suffix is appended - * to the filename. - * - * @param filename name of a file - * @return name of the corresponding compressed file - */ - public String getCompressedFilename(final String filename) { - final String lower = filename.toLowerCase(Locale.ENGLISH); - final int n = lower.length(); - for (int i = shortestUncompressedSuffix; - i <= longestUncompressedSuffix && i < n; i++) { - final String suffix = compressSuffix.get(lower.substring(n - i)); - if (suffix != null) { - return filename.substring(0, n - i) + suffix; - } - } - // No custom suffix found, just append the default - return filename + defaultExtension; - } - -} diff --git a/src/org/apache/commons/compress/compressors/brotli/BrotliCompressorInputStream.java b/src/org/apache/commons/compress/compressors/brotli/BrotliCompressorInputStream.java deleted file mode 100644 index 5674cb220c4..00000000000 --- a/src/org/apache/commons/compress/compressors/brotli/BrotliCompressorInputStream.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.compress.compressors.brotli; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; -import org.brotli.dec.BrotliInputStream; - -/** - * {@link CompressorInputStream} implementation to decode Brotli encoded stream. - * Library relies on Google brotli - * - * @since 1.14 - */ -public class BrotliCompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - private final CountingInputStream countingStream; - private final BrotliInputStream decIS; - - public BrotliCompressorInputStream(final InputStream in) throws IOException { - decIS = new BrotliInputStream(countingStream = new CountingInputStream(in)); - } - - @Override - public int available() throws IOException { - return decIS.available(); - } - - @Override - public void close() throws IOException { - decIS.close(); - } - - @Override - public int read(final byte[] b) throws IOException { - return decIS.read(b); - } - - @Override - public long skip(final long n) throws IOException { - return IOUtils.skip(decIS, n); - } - - @Override - public void mark(final int readlimit) { - decIS.mark(readlimit); - } - - @Override - public boolean markSupported() { - return decIS.markSupported(); - } - - @Override - public int read() throws IOException { - final int ret = decIS.read(); - count(ret == -1 ? 0 : 1); - return ret; - } - - @Override - public int read(final byte[] buf, final int off, final int len) throws IOException { - final int ret = decIS.read(buf, off, len); - count(ret); - return ret; - } - - @Override - public String toString() { - return decIS.toString(); - } - - @Override - public void reset() throws IOException { - decIS.reset(); - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return countingStream.getBytesRead(); - } -} diff --git a/src/org/apache/commons/compress/compressors/brotli/BrotliUtils.java b/src/org/apache/commons/compress/compressors/brotli/BrotliUtils.java deleted file mode 100644 index 15a21399d2e..00000000000 --- a/src/org/apache/commons/compress/compressors/brotli/BrotliUtils.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.brotli; - -/** - * Utility code for the Brotli compression format. - * @ThreadSafe - * @since 1.14 - */ -public class BrotliUtils { - - enum CachedAvailability { - DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE - } - - private static volatile CachedAvailability cachedBrotliAvailability; - - static { - cachedBrotliAvailability = CachedAvailability.DONT_CACHE; - try { - Class.forName("org.osgi.framework.BundleEvent"); - } catch (final Exception ex) { // NOSONAR - setCacheBrotliAvailablity(true); - } - } - - /** Private constructor to prevent instantiation of this utility class. */ - private BrotliUtils() { - } - - - /** - * Are the classes required to support Brotli compression available? - * @return true if the classes required to support Brotli compression are available - */ - public static boolean isBrotliCompressionAvailable() { - final CachedAvailability cachedResult = cachedBrotliAvailability; - if (cachedResult != CachedAvailability.DONT_CACHE) { - return cachedResult == CachedAvailability.CACHED_AVAILABLE; - } - return internalIsBrotliCompressionAvailable(); - } - - private static boolean internalIsBrotliCompressionAvailable() { - try { - Class.forName("org.brotli.dec.BrotliInputStream"); - return true; - } catch (NoClassDefFoundError | Exception error) { // NOSONAR - return false; - } - } - - /** - * Whether to cache the result of the Brotli for Java check. - * - *

This defaults to {@code false} in an OSGi environment and {@code true} otherwise.

- * @param doCache whether to cache the result - */ - public static void setCacheBrotliAvailablity(final boolean doCache) { - if (!doCache) { - cachedBrotliAvailability = CachedAvailability.DONT_CACHE; - } else if (cachedBrotliAvailability == CachedAvailability.DONT_CACHE) { - final boolean hasBrotli = internalIsBrotliCompressionAvailable(); - cachedBrotliAvailability = hasBrotli ? CachedAvailability.CACHED_AVAILABLE - : CachedAvailability.CACHED_UNAVAILABLE; - } - } - - // only exists to support unit tests - static CachedAvailability getCachedBrotliAvailability() { - return cachedBrotliAvailability; - } -} diff --git a/src/org/apache/commons/compress/compressors/brotli/package.html b/src/org/apache/commons/compress/compressors/brotli/package.html deleted file mode 100644 index 7654cf67327..00000000000 --- a/src/org/apache/commons/compress/compressors/brotli/package.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -

Provides stream class for decompressing streams using the - Brotli algorithm based - on Google's Brotli - decoder.

- - diff --git a/src/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java b/src/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java deleted file mode 100644 index 677bbbd1e93..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* - * This package is based on the work done by Keiron Liddle, Aftex Software - * to whom the Ant project is very grateful for his - * great code. - */ -package org.apache.commons.compress.compressors.bzip2; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteOrder; -import java.util.Arrays; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.BitInputStream; -import org.apache.commons.compress.utils.CloseShieldFilterInputStream; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * An input stream that decompresses from the BZip2 format to be read as any other stream. - * - * @NotThreadSafe - */ -public class BZip2CompressorInputStream extends CompressorInputStream - implements BZip2Constants, InputStreamStatistics { - - /** - * Index of the last char in the block, so the block size == last + 1. - */ - private int last; - - /** - * Index in zptr[] of original string after sorting. - */ - private int origPtr; - - /** - * always: in the range 0 .. 9. The current block size is 100000 * this - * number. - */ - private int blockSize100k; - - private boolean blockRandomised; - - private final CRC crc = new CRC(); - - private int nInUse; - - private BitInputStream bin; - private final boolean decompressConcatenated; - - private static final int EOF = 0; - private static final int START_BLOCK_STATE = 1; - private static final int RAND_PART_A_STATE = 2; - private static final int RAND_PART_B_STATE = 3; - private static final int RAND_PART_C_STATE = 4; - private static final int NO_RAND_PART_A_STATE = 5; - private static final int NO_RAND_PART_B_STATE = 6; - private static final int NO_RAND_PART_C_STATE = 7; - - private int currentState = START_BLOCK_STATE; - - private int storedBlockCRC, storedCombinedCRC; - private int computedBlockCRC, computedCombinedCRC; - - // Variables used by setup* methods exclusively - - private int su_count; - private int su_ch2; - private int su_chPrev; - private int su_i2; - private int su_j2; - private int su_rNToGo; - private int su_rTPos; - private int su_tPos; - private char su_z; - - /** - * All memory intensive stuff. This field is initialized by initBlock(). - */ - private BZip2CompressorInputStream.Data data; - - /** - * Constructs a new BZip2CompressorInputStream which decompresses bytes - * read from the specified stream. This doesn't suppprt decompressing - * concatenated .bz2 files. - * - * @param in the InputStream from which this object should be created - * @throws IOException - * if the stream content is malformed or an I/O error occurs. - * @throws NullPointerException - * if {@code in == null} - */ - public BZip2CompressorInputStream(final InputStream in) throws IOException { - this(in, false); - } - - /** - * Constructs a new BZip2CompressorInputStream which decompresses bytes - * read from the specified stream. - * - * @param in the InputStream from which this object should be created - * @param decompressConcatenated - * if true, decompress until the end of the input; - * if false, stop after the first .bz2 stream and - * leave the input position to point to the next - * byte after the .bz2 stream - * - * @throws IOException - * if {@code in == null}, the stream content is malformed, or an I/O error occurs. - */ - public BZip2CompressorInputStream(final InputStream in, final boolean decompressConcatenated) throws IOException { - this.bin = new BitInputStream(in == System.in ? new CloseShieldFilterInputStream(in) : in, - ByteOrder.BIG_ENDIAN); - this.decompressConcatenated = decompressConcatenated; - - init(true); - initBlock(); - } - - @Override - public int read() throws IOException { - if (this.bin != null) { - final int r = read0(); - count(r < 0 ? -1 : 1); - return r; - } - throw new IOException("stream closed"); - } - - /* - * (non-Javadoc) - * - * @see java.io.InputStream#read(byte[], int, int) - */ - @Override - public int read(final byte[] dest, final int offs, final int len) - throws IOException { - if (offs < 0) { - throw new IndexOutOfBoundsException("offs(" + offs + ") < 0."); - } - if (len < 0) { - throw new IndexOutOfBoundsException("len(" + len + ") < 0."); - } - if (offs + len > dest.length) { - throw new IndexOutOfBoundsException("offs(" + offs + ") + len(" - + len + ") > dest.length(" + dest.length + ")."); - } - if (this.bin == null) { - throw new IOException("stream closed"); - } - if (len == 0) { - return 0; - } - - final int hi = offs + len; - int destOffs = offs; - int b; - while (destOffs < hi && ((b = read0()) >= 0)) { - dest[destOffs++] = (byte) b; - count(1); - } - - return (destOffs == offs) ? -1 : (destOffs - offs); - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return bin.getBytesRead(); - } - - private void makeMaps() { - final boolean[] inUse = this.data.inUse; - final byte[] seqToUnseq = this.data.seqToUnseq; - - int nInUseShadow = 0; - - for (int i = 0; i < 256; i++) { - if (inUse[i]) { - seqToUnseq[nInUseShadow++] = (byte) i; - } - } - - this.nInUse = nInUseShadow; - } - - private int read0() throws IOException { - switch (currentState) { - case EOF: - return -1; - - case START_BLOCK_STATE: - return setupBlock(); - - case RAND_PART_A_STATE: - throw new IllegalStateException(); - - case RAND_PART_B_STATE: - return setupRandPartB(); - - case RAND_PART_C_STATE: - return setupRandPartC(); - - case NO_RAND_PART_A_STATE: - throw new IllegalStateException(); - - case NO_RAND_PART_B_STATE: - return setupNoRandPartB(); - - case NO_RAND_PART_C_STATE: - return setupNoRandPartC(); - - default: - throw new IllegalStateException(); - } - } - - private int readNextByte(BitInputStream in) throws IOException { - long b = in.readBits(8); - return (int) b; - } - - private boolean init(final boolean isFirstStream) throws IOException { - if (null == bin) { - throw new IOException("No InputStream"); - } - - if (!isFirstStream) { - bin.clearBitCache(); - } - - final int magic0 = readNextByte(this.bin); - if (magic0 == -1 && !isFirstStream) { - return false; - } - final int magic1 = readNextByte(this.bin); - final int magic2 = readNextByte(this.bin); - - if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h') { - throw new IOException(isFirstStream - ? "Stream is not in the BZip2 format" - : "Garbage after a valid BZip2 stream"); - } - - final int blockSize = readNextByte(this.bin); - if ((blockSize < '1') || (blockSize > '9')) { - throw new IOException("BZip2 block size is invalid"); - } - - this.blockSize100k = blockSize - '0'; - - this.computedCombinedCRC = 0; - - return true; - } - - private void initBlock() throws IOException { - BitInputStream bin = this.bin; - char magic0; - char magic1; - char magic2; - char magic3; - char magic4; - char magic5; - - while (true) { - // Get the block magic bytes. - magic0 = bsGetUByte(bin); - magic1 = bsGetUByte(bin); - magic2 = bsGetUByte(bin); - magic3 = bsGetUByte(bin); - magic4 = bsGetUByte(bin); - magic5 = bsGetUByte(bin); - - // If isn't end of stream magic, break out of the loop. - if (magic0 != 0x17 || magic1 != 0x72 || magic2 != 0x45 - || magic3 != 0x38 || magic4 != 0x50 || magic5 != 0x90) { - break; - } - - // End of stream was reached. Check the combined CRC and - // advance to the next .bz2 stream if decoding concatenated - // streams. - if (complete()) { - return; - } - } - - if (magic0 != 0x31 || // '1' - magic1 != 0x41 || // ')' - magic2 != 0x59 || // 'Y' - magic3 != 0x26 || // '&' - magic4 != 0x53 || // 'S' - magic5 != 0x59 // 'Y' - ) { - this.currentState = EOF; - throw new IOException("bad block header"); - } - this.storedBlockCRC = bsGetInt(bin); - this.blockRandomised = bsR(bin, 1) == 1; - - /** - * Allocate data here instead in constructor, so we do not allocate - * it if the input file is empty. - */ - if (this.data == null) { - this.data = new Data(this.blockSize100k); - } - - // currBlockNo++; - getAndMoveToFrontDecode(); - - this.crc.initialiseCRC(); - this.currentState = START_BLOCK_STATE; - } - - private void endBlock() throws IOException { - this.computedBlockCRC = this.crc.getFinalCRC(); - - // A bad CRC is considered a fatal error. - if (this.storedBlockCRC != this.computedBlockCRC) { - // make next blocks readable without error - // (repair feature, not yet documented, not tested) - this.computedCombinedCRC = (this.storedCombinedCRC << 1) - | (this.storedCombinedCRC >>> 31); - this.computedCombinedCRC ^= this.storedBlockCRC; - - throw new IOException("BZip2 CRC error"); - } - - this.computedCombinedCRC = (this.computedCombinedCRC << 1) - | (this.computedCombinedCRC >>> 31); - this.computedCombinedCRC ^= this.computedBlockCRC; - } - - private boolean complete() throws IOException { - this.storedCombinedCRC = bsGetInt(bin); - this.currentState = EOF; - this.data = null; - - if (this.storedCombinedCRC != this.computedCombinedCRC) { - throw new IOException("BZip2 CRC error"); - } - - // Look for the next .bz2 stream if decompressing - // concatenated files. - return !decompressConcatenated || !init(false); - } - - @Override - public void close() throws IOException { - final BitInputStream inShadow = this.bin; - if (inShadow != null) { - try { - inShadow.close(); - } finally { - this.data = null; - this.bin = null; - } - } - } - - /** - * read bits from the input stream - * @param n the number of bits to read, must not exceed 32? - * @return the requested bits combined into an int - * @throws IOException - */ - private static int bsR(BitInputStream bin, final int n) throws IOException { - long thech = bin.readBits(n); - if (thech < 0) { - throw new IOException("unexpected end of stream"); - } - return (int) thech; - } - - private static boolean bsGetBit(BitInputStream bin) throws IOException { - return bsR(bin, 1) != 0; - } - - private static char bsGetUByte(BitInputStream bin) throws IOException { - return (char) bsR(bin, 8); - } - - private static int bsGetInt(BitInputStream bin) throws IOException { - return bsR(bin, 32); - } - - private static void checkBounds(final int checkVal, final int limitExclusive, String name) - throws IOException { - if (checkVal < 0) { - throw new IOException("Corrupted input, " + name + " value negative"); - } - if (checkVal >= limitExclusive) { - throw new IOException("Corrupted input, " + name + " value too big"); - } - } - - /** - * Called by createHuffmanDecodingTables() exclusively. - */ - private static void hbCreateDecodeTables(final int[] limit, - final int[] base, final int[] perm, final char[] length, - final int minLen, final int maxLen, final int alphaSize) - throws IOException { - for (int i = minLen, pp = 0; i <= maxLen; i++) { - for (int j = 0; j < alphaSize; j++) { - if (length[j] == i) { - perm[pp++] = j; - } - } - } - - for (int i = MAX_CODE_LEN; --i > 0;) { - base[i] = 0; - limit[i] = 0; - } - - for (int i = 0; i < alphaSize; i++) { - final int l = length[i]; - checkBounds(l, MAX_ALPHA_SIZE, "length"); - base[l + 1]++; - } - - for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) { - b += base[i]; - base[i] = b; - } - - for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) { - final int nb = base[i + 1]; - vec += nb - b; - b = nb; - limit[i] = vec - 1; - vec <<= 1; - } - - for (int i = minLen + 1; i <= maxLen; i++) { - base[i] = ((limit[i - 1] + 1) << 1) - base[i]; - } - } - - private void recvDecodingTables() throws IOException { - final BitInputStream bin = this.bin; - final Data dataShadow = this.data; - final boolean[] inUse = dataShadow.inUse; - final byte[] pos = dataShadow.recvDecodingTables_pos; - final byte[] selector = dataShadow.selector; - final byte[] selectorMtf = dataShadow.selectorMtf; - - int inUse16 = 0; - - /* Receive the mapping table */ - for (int i = 0; i < 16; i++) { - if (bsGetBit(bin)) { - inUse16 |= 1 << i; - } - } - - Arrays.fill(inUse, false); - for (int i = 0; i < 16; i++) { - if ((inUse16 & (1 << i)) != 0) { - final int i16 = i << 4; - for (int j = 0; j < 16; j++) { - if (bsGetBit(bin)) { - inUse[i16 + j] = true; - } - } - } - } - - makeMaps(); - final int alphaSize = this.nInUse + 2; - /* Now the selectors */ - final int nGroups = bsR(bin, 3); - final int nSelectors = bsR(bin, 15); - checkBounds(alphaSize, MAX_ALPHA_SIZE + 1, "alphaSize"); - checkBounds(nGroups, N_GROUPS + 1, "nGroups"); - checkBounds(nSelectors, MAX_SELECTORS + 1, "nSelectors"); - - for (int i = 0; i < nSelectors; i++) { - int j = 0; - while (bsGetBit(bin)) { - j++; - } - selectorMtf[i] = (byte) j; - } - - /* Undo the MTF values for the selectors. */ - for (int v = nGroups; --v >= 0;) { - pos[v] = (byte) v; - } - - for (int i = 0; i < nSelectors; i++) { - int v = selectorMtf[i] & 0xff; - checkBounds(v, N_GROUPS, "selectorMtf"); - final byte tmp = pos[v]; - while (v > 0) { - // nearly all times v is zero, 4 in most other cases - pos[v] = pos[v - 1]; - v--; - } - pos[0] = tmp; - selector[i] = tmp; - } - - final char[][] len = dataShadow.temp_charArray2d; - - /* Now the coding tables */ - for (int t = 0; t < nGroups; t++) { - int curr = bsR(bin, 5); - final char[] len_t = len[t]; - for (int i = 0; i < alphaSize; i++) { - while (bsGetBit(bin)) { - curr += bsGetBit(bin) ? -1 : 1; - } - len_t[i] = (char) curr; - } - } - - // finally create the Huffman tables - createHuffmanDecodingTables(alphaSize, nGroups); - } - - /** - * Called by recvDecodingTables() exclusively. - */ - private void createHuffmanDecodingTables(final int alphaSize, - final int nGroups) throws IOException { - final Data dataShadow = this.data; - final char[][] len = dataShadow.temp_charArray2d; - final int[] minLens = dataShadow.minLens; - final int[][] limit = dataShadow.limit; - final int[][] base = dataShadow.base; - final int[][] perm = dataShadow.perm; - - for (int t = 0; t < nGroups; t++) { - int minLen = 32; - int maxLen = 0; - final char[] len_t = len[t]; - for (int i = alphaSize; --i >= 0;) { - final char lent = len_t[i]; - if (lent > maxLen) { - maxLen = lent; - } - if (lent < minLen) { - minLen = lent; - } - } - hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen, - maxLen, alphaSize); - minLens[t] = minLen; - } - } - - private void getAndMoveToFrontDecode() throws IOException { - final BitInputStream bin = this.bin; - this.origPtr = bsR(bin, 24); - recvDecodingTables(); - - final Data dataShadow = this.data; - final byte[] ll8 = dataShadow.ll8; - final int[] unzftab = dataShadow.unzftab; - final byte[] selector = dataShadow.selector; - final byte[] seqToUnseq = dataShadow.seqToUnseq; - final char[] yy = dataShadow.getAndMoveToFrontDecode_yy; - final int[] minLens = dataShadow.minLens; - final int[][] limit = dataShadow.limit; - final int[][] base = dataShadow.base; - final int[][] perm = dataShadow.perm; - final int limitLast = this.blockSize100k * 100000; - - /* - * Setting up the unzftab entries here is not strictly necessary, but it - * does save having to do it later in a separate pass, and so saves a - * block's worth of cache misses. - */ - for (int i = 256; --i >= 0;) { - yy[i] = (char) i; - unzftab[i] = 0; - } - - int groupNo = 0; - int groupPos = G_SIZE - 1; - final int eob = this.nInUse + 1; - int nextSym = getAndMoveToFrontDecode0(); - int lastShadow = -1; - int zt = selector[groupNo] & 0xff; - checkBounds(zt, N_GROUPS, "zt"); - int[] base_zt = base[zt]; - int[] limit_zt = limit[zt]; - int[] perm_zt = perm[zt]; - int minLens_zt = minLens[zt]; - - while (nextSym != eob) { - if ((nextSym == RUNA) || (nextSym == RUNB)) { - int s = -1; - - for (int n = 1; true; n <<= 1) { - if (nextSym == RUNA) { - s += n; - } else if (nextSym == RUNB) { - s += n << 1; - } else { - break; - } - - if (groupPos == 0) { - groupPos = G_SIZE - 1; - checkBounds(++groupNo, MAX_SELECTORS, "groupNo"); - zt = selector[groupNo] & 0xff; - checkBounds(zt, N_GROUPS, "zt"); - base_zt = base[zt]; - limit_zt = limit[zt]; - perm_zt = perm[zt]; - minLens_zt = minLens[zt]; - } else { - groupPos--; - } - - int zn = minLens_zt; - checkBounds(zn, MAX_ALPHA_SIZE, "zn"); - int zvec = bsR(bin, zn); - while(zvec > limit_zt[zn]) { - checkBounds(++zn, MAX_ALPHA_SIZE, "zn"); - zvec = (zvec << 1) | bsR(bin, 1); - } - final int tmp = zvec - base_zt[zn]; - checkBounds(tmp, MAX_ALPHA_SIZE, "zvec"); - nextSym = perm_zt[tmp]; - } - - final int yy0 = yy[0]; - checkBounds(yy0, 256, "yy"); - final byte ch = seqToUnseq[yy0]; - unzftab[ch & 0xff] += s + 1; - - final int from = ++lastShadow; - lastShadow += s; - Arrays.fill(ll8, from, lastShadow + 1, ch); - - if (lastShadow >= limitLast) { - throw new IOException("block overrun while expanding RLE in MTF, " - + lastShadow + " exceeds " + limitLast); - } - } else { - if (++lastShadow >= limitLast) { - throw new IOException("block overrun in MTF, " - + lastShadow + " exceeds " + limitLast); - } - checkBounds(nextSym, 256 + 1, "nextSym"); - - final char tmp = yy[nextSym - 1]; - checkBounds(tmp, 256, "yy"); - unzftab[seqToUnseq[tmp] & 0xff]++; - ll8[lastShadow] = seqToUnseq[tmp]; - - /* - * This loop is hammered during decompression, hence avoid - * native method call overhead of System.arraycopy for very - * small ranges to copy. - */ - if (nextSym <= 16) { - for (int j = nextSym - 1; j > 0;) { - yy[j] = yy[--j]; - } - } else { - System.arraycopy(yy, 0, yy, 1, nextSym - 1); - } - - yy[0] = tmp; - - if (groupPos == 0) { - groupPos = G_SIZE - 1; - checkBounds(++groupNo, MAX_SELECTORS, "groupNo"); - zt = selector[groupNo] & 0xff; - checkBounds(zt, N_GROUPS, "zt"); - base_zt = base[zt]; - limit_zt = limit[zt]; - perm_zt = perm[zt]; - minLens_zt = minLens[zt]; - } else { - groupPos--; - } - - int zn = minLens_zt; - checkBounds(zn, MAX_ALPHA_SIZE, "zn"); - int zvec = bsR(bin, zn); - while(zvec > limit_zt[zn]) { - checkBounds(++zn, MAX_ALPHA_SIZE, "zn"); - zvec = (zvec << 1) | bsR(bin, 1); - } - final int idx = zvec - base_zt[zn]; - checkBounds(idx, MAX_ALPHA_SIZE, "zvec"); - nextSym = perm_zt[idx]; - } - } - - this.last = lastShadow; - } - - private int getAndMoveToFrontDecode0() throws IOException { - final Data dataShadow = this.data; - final int zt = dataShadow.selector[0] & 0xff; - checkBounds(zt, N_GROUPS, "zt"); - final int[] limit_zt = dataShadow.limit[zt]; - int zn = dataShadow.minLens[zt]; - checkBounds(zn, MAX_ALPHA_SIZE, "zn"); - int zvec = bsR(bin, zn); - while (zvec > limit_zt[zn]) { - checkBounds(++zn, MAX_ALPHA_SIZE, "zn"); - zvec = (zvec << 1) | bsR(bin, 1); - } - final int tmp = zvec - dataShadow.base[zt][zn]; - checkBounds(tmp, MAX_ALPHA_SIZE, "zvec"); - - return dataShadow.perm[zt][tmp]; - } - - private int setupBlock() throws IOException { - if (currentState == EOF || this.data == null) { - return -1; - } - - final int[] cftab = this.data.cftab; - final int ttLen = this.last + 1; - final int[] tt = this.data.initTT(ttLen); - final byte[] ll8 = this.data.ll8; - cftab[0] = 0; - System.arraycopy(this.data.unzftab, 0, cftab, 1, 256); - - for (int i = 1, c = cftab[0]; i <= 256; i++) { - c += cftab[i]; - cftab[i] = c; - } - - for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) { - final int tmp = cftab[ll8[i] & 0xff]++; - checkBounds(tmp, ttLen, "tt index"); - tt[tmp] = i; - } - - if ((this.origPtr < 0) || (this.origPtr >= tt.length)) { - throw new IOException("stream corrupted"); - } - - this.su_tPos = tt[this.origPtr]; - this.su_count = 0; - this.su_i2 = 0; - this.su_ch2 = 256; /* not a char and not EOF */ - - if (this.blockRandomised) { - this.su_rNToGo = 0; - this.su_rTPos = 0; - return setupRandPartA(); - } - return setupNoRandPartA(); - } - - private int setupRandPartA() throws IOException { - if (this.su_i2 <= this.last) { - this.su_chPrev = this.su_ch2; - int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; - checkBounds(this.su_tPos, this.data.tt.length, "su_tPos"); - this.su_tPos = this.data.tt[this.su_tPos]; - if (this.su_rNToGo == 0) { - this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1; - if (++this.su_rTPos == 512) { - this.su_rTPos = 0; - } - } else { - this.su_rNToGo--; - } - this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0; - this.su_i2++; - this.currentState = RAND_PART_B_STATE; - this.crc.updateCRC(su_ch2Shadow); - return su_ch2Shadow; - } - endBlock(); - initBlock(); - return setupBlock(); - } - - private int setupNoRandPartA() throws IOException { - if (this.su_i2 <= this.last) { - this.su_chPrev = this.su_ch2; - final int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; - this.su_ch2 = su_ch2Shadow; - checkBounds(this.su_tPos, this.data.tt.length, "su_tPos"); - this.su_tPos = this.data.tt[this.su_tPos]; - this.su_i2++; - this.currentState = NO_RAND_PART_B_STATE; - this.crc.updateCRC(su_ch2Shadow); - return su_ch2Shadow; - } - this.currentState = NO_RAND_PART_A_STATE; - endBlock(); - initBlock(); - return setupBlock(); - } - - private int setupRandPartB() throws IOException { - if (this.su_ch2 != this.su_chPrev) { - this.currentState = RAND_PART_A_STATE; - this.su_count = 1; - return setupRandPartA(); - } else if (++this.su_count >= 4) { - this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); - checkBounds(this.su_tPos, this.data.tt.length, "su_tPos"); - this.su_tPos = this.data.tt[this.su_tPos]; - if (this.su_rNToGo == 0) { - this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1; - if (++this.su_rTPos == 512) { - this.su_rTPos = 0; - } - } else { - this.su_rNToGo--; - } - this.su_j2 = 0; - this.currentState = RAND_PART_C_STATE; - if (this.su_rNToGo == 1) { - this.su_z ^= 1; - } - return setupRandPartC(); - } else { - this.currentState = RAND_PART_A_STATE; - return setupRandPartA(); - } - } - - private int setupRandPartC() throws IOException { - if (this.su_j2 < this.su_z) { - this.crc.updateCRC(this.su_ch2); - this.su_j2++; - return this.su_ch2; - } - this.currentState = RAND_PART_A_STATE; - this.su_i2++; - this.su_count = 0; - return setupRandPartA(); - } - - private int setupNoRandPartB() throws IOException { - if (this.su_ch2 != this.su_chPrev) { - this.su_count = 1; - return setupNoRandPartA(); - } else if (++this.su_count >= 4) { - checkBounds(this.su_tPos, this.data.ll8.length, "su_tPos"); - this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); - this.su_tPos = this.data.tt[this.su_tPos]; - this.su_j2 = 0; - return setupNoRandPartC(); - } else { - return setupNoRandPartA(); - } - } - - private int setupNoRandPartC() throws IOException { - if (this.su_j2 < this.su_z) { - final int su_ch2Shadow = this.su_ch2; - this.crc.updateCRC(su_ch2Shadow); - this.su_j2++; - this.currentState = NO_RAND_PART_C_STATE; - return su_ch2Shadow; - } - this.su_i2++; - this.su_count = 0; - return setupNoRandPartA(); - } - - private static final class Data { - - // (with blockSize 900k) - final boolean[] inUse = new boolean[256]; // 256 byte - - final byte[] seqToUnseq = new byte[256]; // 256 byte - final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte - final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte - - /** - * Freq table collected to save a pass over the data during - * decompression. - */ - final int[] unzftab = new int[256]; // 1024 byte - - final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte - final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte - final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte - final int[] minLens = new int[N_GROUPS]; // 24 byte - - final int[] cftab = new int[257]; // 1028 byte - final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte - final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096 - // byte - final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte - // --------------- - // 60798 byte - - int[] tt; // 3600000 byte - byte[] ll8; // 900000 byte - - // --------------- - // 4560782 byte - // =============== - - Data(final int blockSize100k) { - this.ll8 = new byte[blockSize100k * BZip2Constants.BASEBLOCKSIZE]; - } - - /** - * Initializes the {@link #tt} array. - * - * This method is called when the required length of the array is known. - * I don't initialize it at construction time to avoid unneccessary - * memory allocation when compressing small files. - */ - int[] initTT(final int length) { - int[] ttShadow = this.tt; - - // tt.length should always be >= length, but theoretically - // it can happen, if the compressor mixed small and large - // blocks. Normally only the last block will be smaller - // than others. - if ((ttShadow == null) || (ttShadow.length < length)) { - this.tt = ttShadow = new int[length]; - } - - return ttShadow; - } - - } - - /** - * Checks if the signature matches what is expected for a bzip2 file. - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is a bzip2 compressed stream, false otherwise - * - * @since 1.1 - */ - public static boolean matches(final byte[] signature, final int length) { - return length >= 3 && signature[0] == 'B' && - signature[1] == 'Z' && signature[2] == 'h'; - } -} diff --git a/src/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java b/src/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java deleted file mode 100644 index ba2beb16469..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java +++ /dev/null @@ -1,1334 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.bzip2; - -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; - -/** - * An output stream that compresses into the BZip2 format into another stream. - * - *

- * The compression requires large amounts of memory. Thus you should call the - * {@link #close() close()} method as soon as possible, to force - * {@code BZip2CompressorOutputStream} to release the allocated memory. - *

- * - *

You can shrink the amount of allocated memory and maybe raise - * the compression speed by choosing a lower blocksize, which in turn - * may cause a lower compression ratio. You can avoid unnecessary - * memory allocation by avoiding using a blocksize which is bigger - * than the size of the input.

- * - *

You can compute the memory usage for compressing by the - * following formula:

- * - *
- * <code>400k + (9 * blocksize)</code>.
- * 
- * - *

To get the memory required for decompression by {@link - * BZip2CompressorInputStream} use

- * - *
- * <code>65k + (5 * blocksize)</code>.
- * 
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Memory usage by blocksize
Blocksize Compression
- * memory usage
Decompression
- * memory usage
100k1300k565k
200k2200k1065k
300k3100k1565k
400k4000k2065k
500k4900k2565k
600k5800k3065k
700k6700k3565k
800k7600k4065k
900k8500k4565k
- * - *

- * For decompression {@code BZip2CompressorInputStream} allocates less memory if the - * bzipped input is smaller than one block. - *

- * - *

- * Instances of this class are not threadsafe. - *

- * - *

- * TODO: Update to BZip2 1.0.1 - *

- * @NotThreadSafe - */ -public class BZip2CompressorOutputStream extends CompressorOutputStream - implements BZip2Constants { - - /** - * The minimum supported blocksize {@code == 1}. - */ - public static final int MIN_BLOCKSIZE = 1; - - /** - * The maximum supported blocksize {@code == 9}. - */ - public static final int MAX_BLOCKSIZE = 9; - - private static final int GREATER_ICOST = 15; - private static final int LESSER_ICOST = 0; - - private static void hbMakeCodeLengths(final byte[] len, final int[] freq, - final Data dat, final int alphaSize, - final int maxLen) { - /* - * Nodes and heap entries run from 1. Entry 0 for both the heap and - * nodes is a sentinel. - */ - final int[] heap = dat.heap; - final int[] weight = dat.weight; - final int[] parent = dat.parent; - - for (int i = alphaSize; --i >= 0;) { - weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - } - - for (boolean tooLong = true; tooLong;) { - tooLong = false; - - int nNodes = alphaSize; - int nHeap = 0; - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (int i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - - int zz = nHeap; - final int tmp = heap[zz]; - while (weight[tmp] < weight[heap[zz >> 1]]) { - heap[zz] = heap[zz >> 1]; - zz >>= 1; - } - heap[zz] = tmp; - } - - while (nHeap > 1) { - final int n1 = heap[1]; - heap[1] = heap[nHeap]; - nHeap--; - - int yy = 0; - int zz = 1; - int tmp = heap[1]; - - while (true) { - yy = zz << 1; - - if (yy > nHeap) { - break; - } - - if ((yy < nHeap) - && (weight[heap[yy + 1]] < weight[heap[yy]])) { - yy++; - } - - if (weight[tmp] < weight[heap[yy]]) { - break; - } - - heap[zz] = heap[yy]; - zz = yy; - } - - heap[zz] = tmp; - - final int n2 = heap[1]; - heap[1] = heap[nHeap]; - nHeap--; - - yy = 0; - zz = 1; - tmp = heap[1]; - - while (true) { - yy = zz << 1; - - if (yy > nHeap) { - break; - } - - if ((yy < nHeap) - && (weight[heap[yy + 1]] < weight[heap[yy]])) { - yy++; - } - - if (weight[tmp] < weight[heap[yy]]) { - break; - } - - heap[zz] = heap[yy]; - zz = yy; - } - - heap[zz] = tmp; - nNodes++; - parent[n1] = parent[n2] = nNodes; - - final int weight_n1 = weight[n1]; - final int weight_n2 = weight[n2]; - weight[nNodes] = ((weight_n1 & 0xffffff00) - + (weight_n2 & 0xffffff00)) - | (1 + (((weight_n1 & 0x000000ff) - > (weight_n2 & 0x000000ff)) - ? (weight_n1 & 0x000000ff) - : (weight_n2 & 0x000000ff))); - - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - - tmp = 0; - zz = nHeap; - tmp = heap[zz]; - final int weight_tmp = weight[tmp]; - while (weight_tmp < weight[heap[zz >> 1]]) { - heap[zz] = heap[zz >> 1]; - zz >>= 1; - } - heap[zz] = tmp; - - } - - for (int i = 1; i <= alphaSize; i++) { - int j = 0; - int k = i; - - for (int parent_k; (parent_k = parent[k]) >= 0;) { - k = parent_k; - j++; - } - - len[i - 1] = (byte) j; - if (j > maxLen) { - tooLong = true; - } - } - - if (tooLong) { - for (int i = 1; i < alphaSize; i++) { - int j = weight[i] >> 8; - j = 1 + (j >> 1); - weight[i] = j << 8; - } - } - } - } - - /** - * Index of the last char in the block, so the block size == last + 1. - */ - private int last; - - /** - * Always: in the range 0 .. 9. The current block size is 100000 * this - * number. - */ - private final int blockSize100k; - - private int bsBuff; - private int bsLive; - private final CRC crc = new CRC(); - - private int nInUse; - - private int nMTF; - - private int currentChar = -1; - private int runLength = 0; - - private int blockCRC; - private int combinedCRC; - private final int allowableBlockSize; - - /** - * All memory intensive stuff. - */ - private Data data; - private BlockSort blockSorter; - - private OutputStream out; - private volatile boolean closed; - - /** - * Chooses a blocksize based on the given length of the data to compress. - * - * @return The blocksize, between {@link #MIN_BLOCKSIZE} and - * {@link #MAX_BLOCKSIZE} both inclusive. For a negative - * {@code inputLength} this method returns {@code MAX_BLOCKSIZE} - * always. - * - * @param inputLength - * The length of the data which will be compressed by - * {@code BZip2CompressorOutputStream}. - */ - public static int chooseBlockSize(final long inputLength) { - return (inputLength > 0) ? (int) Math - .min((inputLength / 132000) + 1, 9) : MAX_BLOCKSIZE; - } - - /** - * Constructs a new {@code BZip2CompressorOutputStream} with a blocksize of 900k. - * - * @param out - * the destination stream. - * - * @throws IOException - * if an I/O error occurs in the specified stream. - * @throws NullPointerException - * if out == null. - */ - public BZip2CompressorOutputStream(final OutputStream out) - throws IOException { - this(out, MAX_BLOCKSIZE); - } - - /** - * Constructs a new {@code BZip2CompressorOutputStream} with specified blocksize. - * - * @param out - * the destination stream. - * @param blockSize - * the blockSize as 100k units. - * - * @throws IOException - * if an I/O error occurs in the specified stream. - * @throws IllegalArgumentException - * if (blockSize < 1) || (blockSize > 9). - * @throws NullPointerException - * if out == null. - * - * @see #MIN_BLOCKSIZE - * @see #MAX_BLOCKSIZE - */ - public BZip2CompressorOutputStream(final OutputStream out, final int blockSize) throws IOException { - if (blockSize < 1) { - throw new IllegalArgumentException("blockSize(" + blockSize + ") < 1"); - } - if (blockSize > 9) { - throw new IllegalArgumentException("blockSize(" + blockSize + ") > 9"); - } - - this.blockSize100k = blockSize; - this.out = out; - - /* 20 is just a paranoia constant */ - this.allowableBlockSize = (this.blockSize100k * BZip2Constants.BASEBLOCKSIZE) - 20; - init(); - } - - @Override - public void write(final int b) throws IOException { - if (!closed) { - write0(b); - } else { - throw new IOException("closed"); - } - } - - /** - * Writes the current byte to the buffer, run-length encoding it - * if it has been repeated at least four times (the first step - * RLEs sequences of four identical bytes). - * - *

Flushes the current block before writing data if it is - * full.

- * - *

"write to the buffer" means adding to data.buffer starting - * two steps "after" this.last - initially starting at index 1 - * (not 0) - and updating this.last to point to the last index - * written minus 1.

- */ - private void writeRun() throws IOException { - final int lastShadow = this.last; - - if (lastShadow < this.allowableBlockSize) { - final int currentCharShadow = this.currentChar; - final Data dataShadow = this.data; - dataShadow.inUse[currentCharShadow] = true; - final byte ch = (byte) currentCharShadow; - - int runLengthShadow = this.runLength; - this.crc.updateCRC(currentCharShadow, runLengthShadow); - - switch (runLengthShadow) { - case 1: - dataShadow.block[lastShadow + 2] = ch; - this.last = lastShadow + 1; - break; - - case 2: - dataShadow.block[lastShadow + 2] = ch; - dataShadow.block[lastShadow + 3] = ch; - this.last = lastShadow + 2; - break; - - case 3: { - final byte[] block = dataShadow.block; - block[lastShadow + 2] = ch; - block[lastShadow + 3] = ch; - block[lastShadow + 4] = ch; - this.last = lastShadow + 3; - } - break; - - default: { - runLengthShadow -= 4; - dataShadow.inUse[runLengthShadow] = true; - final byte[] block = dataShadow.block; - block[lastShadow + 2] = ch; - block[lastShadow + 3] = ch; - block[lastShadow + 4] = ch; - block[lastShadow + 5] = ch; - block[lastShadow + 6] = (byte) runLengthShadow; - this.last = lastShadow + 5; - } - break; - - } - } else { - endBlock(); - initBlock(); - writeRun(); - } - } - - /** - * Overriden to warn about an unclosed stream. - */ - @Override - protected void finalize() throws Throwable { - if (!closed) { - System.err.println("Unclosed BZip2CompressorOutputStream detected, will *not* close it"); - } - super.finalize(); - } - - - public void finish() throws IOException { - if (!closed) { - closed = true; - try { - if (this.runLength > 0) { - writeRun(); - } - this.currentChar = -1; - endBlock(); - endCompression(); - } finally { - this.out = null; - this.blockSorter = null; - this.data = null; - } - } - } - - @Override - public void close() throws IOException { - if (!closed) { - final OutputStream outShadow = this.out; - finish(); - outShadow.close(); - } - } - - @Override - public void flush() throws IOException { - final OutputStream outShadow = this.out; - if (outShadow != null) { - outShadow.flush(); - } - } - - /** - * Writes magic bytes like BZ on the first position of the stream - * and bytes indiciating the file-format, which is - * huffmanised, followed by a digit indicating blockSize100k. - * @throws IOException if the magic bytes could not been written - */ - private void init() throws IOException { - bsPutUByte('B'); - bsPutUByte('Z'); - - this.data = new Data(this.blockSize100k); - this.blockSorter = new BlockSort(this.data); - - // huffmanised magic bytes - bsPutUByte('h'); - bsPutUByte('0' + this.blockSize100k); - - this.combinedCRC = 0; - initBlock(); - } - - private void initBlock() { - // blockNo++; - this.crc.initialiseCRC(); - this.last = -1; - // ch = 0; - - final boolean[] inUse = this.data.inUse; - for (int i = 256; --i >= 0;) { - inUse[i] = false; - } - - } - - private void endBlock() throws IOException { - this.blockCRC = this.crc.getFinalCRC(); - this.combinedCRC = (this.combinedCRC << 1) | (this.combinedCRC >>> 31); - this.combinedCRC ^= this.blockCRC; - - // empty block at end of file - if (this.last == -1) { - return; - } - - /* sort the block and establish posn of original string */ - blockSort(); - - /* - * A 6-byte block header, the value chosen arbitrarily as 0x314159265359 - * :-). A 32 bit value does not really give a strong enough guarantee - * that the value will not appear by chance in the compressed - * datastream. Worst-case probability of this event, for a 900k block, - * is about 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 - * bits. For a compressed file of size 100Gb -- about 100000 blocks -- - * only a 48-bit marker will do. NB: normal compression/ decompression - * donot rely on these statistical properties. They are only important - * when trying to recover blocks from damaged files. - */ - bsPutUByte(0x31); - bsPutUByte(0x41); - bsPutUByte(0x59); - bsPutUByte(0x26); - bsPutUByte(0x53); - bsPutUByte(0x59); - - /* Now the block's CRC, so it is in a known place. */ - bsPutInt(this.blockCRC); - - /* Now a single bit indicating no randomisation. */ - bsW(1, 0); - - /* Finally, block's contents proper. */ - moveToFrontCodeAndSend(); - } - - private void endCompression() throws IOException { - /* - * Now another magic 48-bit number, 0x177245385090, to indicate the end - * of the last block. (sqrt(pi), if you want to know. I did want to use - * e, but it contains too much repetition -- 27 18 28 18 28 46 -- for me - * to feel statistically comfortable. Call me paranoid.) - */ - bsPutUByte(0x17); - bsPutUByte(0x72); - bsPutUByte(0x45); - bsPutUByte(0x38); - bsPutUByte(0x50); - bsPutUByte(0x90); - - bsPutInt(this.combinedCRC); - bsFinishedWithStream(); - } - - /** - * Returns the blocksize parameter specified at construction time. - * @return the blocksize parameter specified at construction time - */ - public final int getBlockSize() { - return this.blockSize100k; - } - - @Override - public void write(final byte[] buf, int offs, final int len) - throws IOException { - if (offs < 0) { - throw new IndexOutOfBoundsException("offs(" + offs + ") < 0."); - } - if (len < 0) { - throw new IndexOutOfBoundsException("len(" + len + ") < 0."); - } - if (offs + len > buf.length) { - throw new IndexOutOfBoundsException("offs(" + offs + ") + len(" - + len + ") > buf.length(" - + buf.length + ")."); - } - if (closed) { - throw new IOException("stream closed"); - } - - for (final int hi = offs + len; offs < hi;) { - write0(buf[offs++]); - } - } - - /** - * Keeps track of the last bytes written and implicitly performs - * run-length encoding as the first step of the bzip2 algorithm. - */ - private void write0(int b) throws IOException { - if (this.currentChar != -1) { - b &= 0xff; - if (this.currentChar == b) { - if (++this.runLength > 254) { - writeRun(); - this.currentChar = -1; - this.runLength = 0; - } - // else nothing to do - } else { - writeRun(); - this.runLength = 1; - this.currentChar = b; - } - } else { - this.currentChar = b & 0xff; - this.runLength++; - } - } - - private static void hbAssignCodes(final int[] code, final byte[] length, - final int minLen, final int maxLen, - final int alphaSize) { - int vec = 0; - for (int n = minLen; n <= maxLen; n++) { - for (int i = 0; i < alphaSize; i++) { - if ((length[i] & 0xff) == n) { - code[i] = vec; - vec++; - } - } - vec <<= 1; - } - } - - private void bsFinishedWithStream() throws IOException { - while (this.bsLive > 0) { - final int ch = this.bsBuff >> 24; - this.out.write(ch); // write 8-bit - this.bsBuff <<= 8; - this.bsLive -= 8; - } - } - - private void bsW(final int n, final int v) throws IOException { - final OutputStream outShadow = this.out; - int bsLiveShadow = this.bsLive; - int bsBuffShadow = this.bsBuff; - - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); // write 8-bit - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - - this.bsBuff = bsBuffShadow | (v << (32 - bsLiveShadow - n)); - this.bsLive = bsLiveShadow + n; - } - - private void bsPutUByte(final int c) throws IOException { - bsW(8, c); - } - - private void bsPutInt(final int u) throws IOException { - bsW(8, (u >> 24) & 0xff); - bsW(8, (u >> 16) & 0xff); - bsW(8, (u >> 8) & 0xff); - bsW(8, u & 0xff); - } - - private void sendMTFValues() throws IOException { - final byte[][] len = this.data.sendMTFValues_len; - final int alphaSize = this.nInUse + 2; - - for (int t = N_GROUPS; --t >= 0;) { - final byte[] len_t = len[t]; - for (int v = alphaSize; --v >= 0;) { - len_t[v] = GREATER_ICOST; - } - } - - /* Decide how many coding tables to use */ - // assert (this.nMTF > 0) : this.nMTF; - final int nGroups = (this.nMTF < 200) ? 2 : (this.nMTF < 600) ? 3 - : (this.nMTF < 1200) ? 4 : (this.nMTF < 2400) ? 5 : 6; - - /* Generate an initial set of coding tables */ - sendMTFValues0(nGroups, alphaSize); - - /* - * Iterate up to N_ITERS times to improve the tables. - */ - final int nSelectors = sendMTFValues1(nGroups, alphaSize); - - /* Compute MTF values for the selectors. */ - sendMTFValues2(nGroups, nSelectors); - - /* Assign actual codes for the tables. */ - sendMTFValues3(nGroups, alphaSize); - - /* Transmit the mapping table. */ - sendMTFValues4(); - - /* Now the selectors. */ - sendMTFValues5(nGroups, nSelectors); - - /* Now the coding tables. */ - sendMTFValues6(nGroups, alphaSize); - - /* And finally, the block data proper */ - sendMTFValues7(); - } - - private void sendMTFValues0(final int nGroups, final int alphaSize) { - final byte[][] len = this.data.sendMTFValues_len; - final int[] mtfFreq = this.data.mtfFreq; - - int remF = this.nMTF; - int gs = 0; - - for (int nPart = nGroups; nPart > 0; nPart--) { - final int tFreq = remF / nPart; - int ge = gs - 1; - int aFreq = 0; - - for (final int a = alphaSize - 1; (aFreq < tFreq) && (ge < a);) { - aFreq += mtfFreq[++ge]; - } - - if ((ge > gs) && (nPart != nGroups) && (nPart != 1) - && (((nGroups - nPart) & 1) != 0)) { - aFreq -= mtfFreq[ge--]; - } - - final byte[] len_np = len[nPart - 1]; - for (int v = alphaSize; --v >= 0;) { - if ((v >= gs) && (v <= ge)) { - len_np[v] = LESSER_ICOST; - } else { - len_np[v] = GREATER_ICOST; - } - } - - gs = ge + 1; - remF -= aFreq; - } - } - - private int sendMTFValues1(final int nGroups, final int alphaSize) { - final Data dataShadow = this.data; - final int[][] rfreq = dataShadow.sendMTFValues_rfreq; - final int[] fave = dataShadow.sendMTFValues_fave; - final short[] cost = dataShadow.sendMTFValues_cost; - final char[] sfmap = dataShadow.sfmap; - final byte[] selector = dataShadow.selector; - final byte[][] len = dataShadow.sendMTFValues_len; - final byte[] len_0 = len[0]; - final byte[] len_1 = len[1]; - final byte[] len_2 = len[2]; - final byte[] len_3 = len[3]; - final byte[] len_4 = len[4]; - final byte[] len_5 = len[5]; - final int nMTFShadow = this.nMTF; - - int nSelectors = 0; - - for (int iter = 0; iter < N_ITERS; iter++) { - for (int t = nGroups; --t >= 0;) { - fave[t] = 0; - final int[] rfreqt = rfreq[t]; - for (int i = alphaSize; --i >= 0;) { - rfreqt[i] = 0; - } - } - - nSelectors = 0; - - for (int gs = 0; gs < this.nMTF;) { - /* Set group start & end marks. */ - - /* - * Calculate the cost of this group as coded by each of the - * coding tables. - */ - - final int ge = Math.min(gs + G_SIZE - 1, nMTFShadow - 1); - - if (nGroups == N_GROUPS) { - // unrolled version of the else-block - - short cost0 = 0; - short cost1 = 0; - short cost2 = 0; - short cost3 = 0; - short cost4 = 0; - short cost5 = 0; - - for (int i = gs; i <= ge; i++) { - final int icv = sfmap[i]; - cost0 += len_0[icv] & 0xff; - cost1 += len_1[icv] & 0xff; - cost2 += len_2[icv] & 0xff; - cost3 += len_3[icv] & 0xff; - cost4 += len_4[icv] & 0xff; - cost5 += len_5[icv] & 0xff; - } - - cost[0] = cost0; - cost[1] = cost1; - cost[2] = cost2; - cost[3] = cost3; - cost[4] = cost4; - cost[5] = cost5; - - } else { - for (int t = nGroups; --t >= 0;) { - cost[t] = 0; - } - - for (int i = gs; i <= ge; i++) { - final int icv = sfmap[i]; - for (int t = nGroups; --t >= 0;) { - cost[t] += len[t][icv] & 0xff; - } - } - } - - /* - * Find the coding table which is best for this group, and - * record its identity in the selector table. - */ - int bt = -1; - for (int t = nGroups, bc = 999999999; --t >= 0;) { - final int cost_t = cost[t]; - if (cost_t < bc) { - bc = cost_t; - bt = t; - } - } - - fave[bt]++; - selector[nSelectors] = (byte) bt; - nSelectors++; - - /* - * Increment the symbol frequencies for the selected table. - */ - final int[] rfreq_bt = rfreq[bt]; - for (int i = gs; i <= ge; i++) { - rfreq_bt[sfmap[i]]++; - } - - gs = ge + 1; - } - - /* - * Recompute the tables based on the accumulated frequencies. - */ - for (int t = 0; t < nGroups; t++) { - hbMakeCodeLengths(len[t], rfreq[t], this.data, alphaSize, 20); - } - } - - return nSelectors; - } - - private void sendMTFValues2(final int nGroups, final int nSelectors) { - // assert (nGroups < 8) : nGroups; - - final Data dataShadow = this.data; - final byte[] pos = dataShadow.sendMTFValues2_pos; - - for (int i = nGroups; --i >= 0;) { - pos[i] = (byte) i; - } - - for (int i = 0; i < nSelectors; i++) { - final byte ll_i = dataShadow.selector[i]; - byte tmp = pos[0]; - int j = 0; - - while (ll_i != tmp) { - j++; - final byte tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - } - - pos[0] = tmp; - dataShadow.selectorMtf[i] = (byte) j; - } - } - - private void sendMTFValues3(final int nGroups, final int alphaSize) { - final int[][] code = this.data.sendMTFValues_code; - final byte[][] len = this.data.sendMTFValues_len; - - for (int t = 0; t < nGroups; t++) { - int minLen = 32; - int maxLen = 0; - final byte[] len_t = len[t]; - for (int i = alphaSize; --i >= 0;) { - final int l = len_t[i] & 0xff; - if (l > maxLen) { - maxLen = l; - } - if (l < minLen) { - minLen = l; - } - } - - // assert (maxLen <= 20) : maxLen; - // assert (minLen >= 1) : minLen; - - hbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize); - } - } - - private void sendMTFValues4() throws IOException { - final boolean[] inUse = this.data.inUse; - final boolean[] inUse16 = this.data.sentMTFValues4_inUse16; - - for (int i = 16; --i >= 0;) { - inUse16[i] = false; - final int i16 = i * 16; - for (int j = 16; --j >= 0;) { - if (inUse[i16 + j]) { - inUse16[i] = true; - } - } - } - - for (int i = 0; i < 16; i++) { - bsW(1, inUse16[i] ? 1 : 0); - } - - final OutputStream outShadow = this.out; - int bsLiveShadow = this.bsLive; - int bsBuffShadow = this.bsBuff; - - for (int i = 0; i < 16; i++) { - if (inUse16[i]) { - final int i16 = i * 16; - for (int j = 0; j < 16; j++) { - // inlined: bsW(1, inUse[i16 + j] ? 1 : 0); - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); // write 8-bit - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - if (inUse[i16 + j]) { - bsBuffShadow |= 1 << (32 - bsLiveShadow - 1); - } - bsLiveShadow++; - } - } - } - - this.bsBuff = bsBuffShadow; - this.bsLive = bsLiveShadow; - } - - private void sendMTFValues5(final int nGroups, final int nSelectors) - throws IOException { - bsW(3, nGroups); - bsW(15, nSelectors); - - final OutputStream outShadow = this.out; - final byte[] selectorMtf = this.data.selectorMtf; - - int bsLiveShadow = this.bsLive; - int bsBuffShadow = this.bsBuff; - - for (int i = 0; i < nSelectors; i++) { - for (int j = 0, hj = selectorMtf[i] & 0xff; j < hj; j++) { - // inlined: bsW(1, 1); - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - bsBuffShadow |= 1 << (32 - bsLiveShadow - 1); - bsLiveShadow++; - } - - // inlined: bsW(1, 0); - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - // bsBuffShadow |= 0 << (32 - bsLiveShadow - 1); - bsLiveShadow++; - } - - this.bsBuff = bsBuffShadow; - this.bsLive = bsLiveShadow; - } - - private void sendMTFValues6(final int nGroups, final int alphaSize) - throws IOException { - final byte[][] len = this.data.sendMTFValues_len; - final OutputStream outShadow = this.out; - - int bsLiveShadow = this.bsLive; - int bsBuffShadow = this.bsBuff; - - for (int t = 0; t < nGroups; t++) { - final byte[] len_t = len[t]; - int curr = len_t[0] & 0xff; - - // inlined: bsW(5, curr); - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); // write 8-bit - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - bsBuffShadow |= curr << (32 - bsLiveShadow - 5); - bsLiveShadow += 5; - - for (int i = 0; i < alphaSize; i++) { - final int lti = len_t[i] & 0xff; - while (curr < lti) { - // inlined: bsW(2, 2); - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); // write 8-bit - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - bsBuffShadow |= 2 << (32 - bsLiveShadow - 2); - bsLiveShadow += 2; - - curr++; /* 10 */ - } - - while (curr > lti) { - // inlined: bsW(2, 3); - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); // write 8-bit - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - bsBuffShadow |= 3 << (32 - bsLiveShadow - 2); - bsLiveShadow += 2; - - curr--; /* 11 */ - } - - // inlined: bsW(1, 0); - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); // write 8-bit - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - // bsBuffShadow |= 0 << (32 - bsLiveShadow - 1); - bsLiveShadow++; - } - } - - this.bsBuff = bsBuffShadow; - this.bsLive = bsLiveShadow; - } - - private void sendMTFValues7() throws IOException { - final Data dataShadow = this.data; - final byte[][] len = dataShadow.sendMTFValues_len; - final int[][] code = dataShadow.sendMTFValues_code; - final OutputStream outShadow = this.out; - final byte[] selector = dataShadow.selector; - final char[] sfmap = dataShadow.sfmap; - final int nMTFShadow = this.nMTF; - - int selCtr = 0; - - int bsLiveShadow = this.bsLive; - int bsBuffShadow = this.bsBuff; - - for (int gs = 0; gs < nMTFShadow;) { - final int ge = Math.min(gs + G_SIZE - 1, nMTFShadow - 1); - final int selector_selCtr = selector[selCtr] & 0xff; - final int[] code_selCtr = code[selector_selCtr]; - final byte[] len_selCtr = len[selector_selCtr]; - - while (gs <= ge) { - final int sfmap_i = sfmap[gs]; - - // - // inlined: bsW(len_selCtr[sfmap_i] & 0xff, - // code_selCtr[sfmap_i]); - // - while (bsLiveShadow >= 8) { - outShadow.write(bsBuffShadow >> 24); - bsBuffShadow <<= 8; - bsLiveShadow -= 8; - } - final int n = len_selCtr[sfmap_i] & 0xFF; - bsBuffShadow |= code_selCtr[sfmap_i] << (32 - bsLiveShadow - n); - bsLiveShadow += n; - - gs++; - } - - gs = ge + 1; - selCtr++; - } - - this.bsBuff = bsBuffShadow; - this.bsLive = bsLiveShadow; - } - - private void moveToFrontCodeAndSend() throws IOException { - bsW(24, this.data.origPtr); - generateMTFValues(); - sendMTFValues(); - } - - private void blockSort() { - blockSorter.blockSort(data, last); - } - - /* - * Performs Move-To-Front on the Burrows-Wheeler transformed - * buffer, storing the MTFed data in data.sfmap in RUNA/RUNB - * run-length-encoded form. - * - *

Keeps track of byte frequencies in data.mtfFreq at the same time.

- */ - private void generateMTFValues() { - final int lastShadow = this.last; - final Data dataShadow = this.data; - final boolean[] inUse = dataShadow.inUse; - final byte[] block = dataShadow.block; - final int[] fmap = dataShadow.fmap; - final char[] sfmap = dataShadow.sfmap; - final int[] mtfFreq = dataShadow.mtfFreq; - final byte[] unseqToSeq = dataShadow.unseqToSeq; - final byte[] yy = dataShadow.generateMTFValues_yy; - - // make maps - int nInUseShadow = 0; - for (int i = 0; i < 256; i++) { - if (inUse[i]) { - unseqToSeq[i] = (byte) nInUseShadow; - nInUseShadow++; - } - } - this.nInUse = nInUseShadow; - - final int eob = nInUseShadow + 1; - - for (int i = eob; i >= 0; i--) { - mtfFreq[i] = 0; - } - - for (int i = nInUseShadow; --i >= 0;) { - yy[i] = (byte) i; - } - - int wr = 0; - int zPend = 0; - - for (int i = 0; i <= lastShadow; i++) { - final byte ll_i = unseqToSeq[block[fmap[i]] & 0xff]; - byte tmp = yy[0]; - int j = 0; - - while (ll_i != tmp) { - j++; - final byte tmp2 = tmp; - tmp = yy[j]; - yy[j] = tmp2; - } - yy[0] = tmp; - - if (j == 0) { - zPend++; - } else { - if (zPend > 0) { - zPend--; - while (true) { - if ((zPend & 1) == 0) { - sfmap[wr] = RUNA; - wr++; - mtfFreq[RUNA]++; - } else { - sfmap[wr] = RUNB; - wr++; - mtfFreq[RUNB]++; - } - - if (zPend >= 2) { - zPend = (zPend - 2) >> 1; - } else { - break; - } - } - zPend = 0; - } - sfmap[wr] = (char) (j + 1); - wr++; - mtfFreq[j + 1]++; - } - } - - if (zPend > 0) { - zPend--; - while (true) { - if ((zPend & 1) == 0) { - sfmap[wr] = RUNA; - wr++; - mtfFreq[RUNA]++; - } else { - sfmap[wr] = RUNB; - wr++; - mtfFreq[RUNB]++; - } - - if (zPend >= 2) { - zPend = (zPend - 2) >> 1; - } else { - break; - } - } - } - - sfmap[wr] = (char) eob; - mtfFreq[eob]++; - this.nMTF = wr + 1; - } - - static final class Data { - - // with blockSize 900k - /* maps unsigned byte => "does it occur in block" */ - final boolean[] inUse = new boolean[256]; // 256 byte - final byte[] unseqToSeq = new byte[256]; // 256 byte - final int[] mtfFreq = new int[MAX_ALPHA_SIZE]; // 1032 byte - final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte - final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte - - final byte[] generateMTFValues_yy = new byte[256]; // 256 byte - final byte[][] sendMTFValues_len = new byte[N_GROUPS][MAX_ALPHA_SIZE]; // 1548 - // byte - final int[][] sendMTFValues_rfreq = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 - // byte - final int[] sendMTFValues_fave = new int[N_GROUPS]; // 24 byte - final short[] sendMTFValues_cost = new short[N_GROUPS]; // 12 byte - final int[][] sendMTFValues_code = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 - // byte - final byte[] sendMTFValues2_pos = new byte[N_GROUPS]; // 6 byte - final boolean[] sentMTFValues4_inUse16 = new boolean[16]; // 16 byte - - final int[] heap = new int[MAX_ALPHA_SIZE + 2]; // 1040 byte - final int[] weight = new int[MAX_ALPHA_SIZE * 2]; // 2064 byte - final int[] parent = new int[MAX_ALPHA_SIZE * 2]; // 2064 byte - - // ------------ - // 333408 byte - - /* holds the RLEd block of original data starting at index 1. - * After sorting the last byte added to the buffer is at index - * 0. */ - final byte[] block; // 900021 byte - /* maps index in Burrows-Wheeler transformed block => index of - * byte in original block */ - final int[] fmap; // 3600000 byte - final char[] sfmap; // 3600000 byte - // ------------ - // 8433529 byte - // ============ - - /** - * Index of original line in Burrows-Wheeler table. - * - *

This is the index in fmap that points to the last byte - * of the original data.

- */ - int origPtr; - - Data(final int blockSize100k) { - final int n = blockSize100k * BZip2Constants.BASEBLOCKSIZE; - this.block = new byte[(n + 1 + NUM_OVERSHOOT_BYTES)]; - this.fmap = new int[n]; - this.sfmap = new char[2 * n]; - } - - } - -} diff --git a/src/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java b/src/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java deleted file mode 100644 index 9a8b9c4c0c9..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.bzip2; - -/** - * Constants for both the compress and decompress BZip2 classes. - */ -interface BZip2Constants { - - int BASEBLOCKSIZE = 100000; - int MAX_ALPHA_SIZE = 258; - int MAX_CODE_LEN = 23; - int RUNA = 0; - int RUNB = 1; - int N_GROUPS = 6; - int G_SIZE = 50; - int N_ITERS = 4; - int MAX_SELECTORS = (2 + (900000 / G_SIZE)); - int NUM_OVERSHOOT_BYTES = 20; - -} \ No newline at end of file diff --git a/src/org/apache/commons/compress/compressors/bzip2/BZip2Utils.java b/src/org/apache/commons/compress/compressors/bzip2/BZip2Utils.java deleted file mode 100644 index 5582d981a0d..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/BZip2Utils.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.bzip2; - -import java.util.LinkedHashMap; -import java.util.Map; -import org.apache.commons.compress.compressors.FileNameUtil; - -/** - * Utility code for the BZip2 compression format. - * @ThreadSafe - * @since 1.1 - */ -public abstract class BZip2Utils { - - private static final FileNameUtil fileNameUtil; - - static { - final Map uncompressSuffix = - new LinkedHashMap<>(); - // backwards compatibilty: BZip2Utils never created the short - // tbz form, so .tar.bz2 has to be added explicitly - uncompressSuffix.put(".tar.bz2", ".tar"); - uncompressSuffix.put(".tbz2", ".tar"); - uncompressSuffix.put(".tbz", ".tar"); - uncompressSuffix.put(".bz2", ""); - uncompressSuffix.put(".bz", ""); - fileNameUtil = new FileNameUtil(uncompressSuffix, ".bz2"); - } - - /** Private constructor to prevent instantiation of this utility class. */ - private BZip2Utils() { - } - - /** - * Detects common bzip2 suffixes in the given filename. - * - * @param filename name of a file - * @return {@code true} if the filename has a common bzip2 suffix, - * {@code false} otherwise - */ - public static boolean isCompressedFilename(final String filename) { - return fileNameUtil.isCompressedFilename(filename); - } - - /** - * Maps the given name of a bzip2-compressed file to the name that the - * file should have after uncompression. Commonly used file type specific - * suffixes like ".tbz" or ".tbz2" are automatically detected and - * correctly mapped. For example the name "package.tbz2" is mapped to - * "package.tar". And any filenames with the generic ".bz2" suffix - * (or any other generic bzip2 suffix) is mapped to a name without that - * suffix. If no bzip2 suffix is detected, then the filename is returned - * unmapped. - * - * @param filename name of a file - * @return name of the corresponding uncompressed file - */ - public static String getUncompressedFilename(final String filename) { - return fileNameUtil.getUncompressedFilename(filename); - } - - /** - * Maps the given filename to the name that the file should have after - * compression with bzip2. Currently this method simply appends the suffix - * ".bz2" to the filename based on the standard behaviour of the "bzip2" - * program, but a future version may implement a more complex mapping if - * a new widely used naming pattern emerges. - * - * @param filename name of a file - * @return name of the corresponding compressed file - */ - public static String getCompressedFilename(final String filename) { - return fileNameUtil.getCompressedFilename(filename); - } - -} diff --git a/src/org/apache/commons/compress/compressors/bzip2/BlockSort.java b/src/org/apache/commons/compress/compressors/bzip2/BlockSort.java deleted file mode 100644 index 69819e3da68..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/BlockSort.java +++ /dev/null @@ -1,1082 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.bzip2; - -import java.util.BitSet; - -/** - * Encapsulates the Burrows-Wheeler sorting algorithm needed by {@link - * BZip2CompressorOutputStream}. - * - *

This class is based on a Java port of Julian Seward's - * blocksort.c in his libbzip2

- * - *

The Burrows-Wheeler transform is a reversible transform of the - * original data that is supposed to group similar bytes close to - * each other. The idea is to sort all permutations of the input and - * only keep the last byte of each permutation. E.g. for "Commons - * Compress" you'd get:

- * - *
- *  CompressCommons
- * Commons Compress
- * CompressCommons
- * essCommons Compr
- * mmons CompressCo
- * mons CompressCom
- * mpressCommons Co
- * ns CompressCommo
- * ommons CompressC
- * ompressCommons C
- * ons CompressComm
- * pressCommons Com
- * ressCommons Comp
- * s CompressCommon
- * sCommons Compres
- * ssCommons Compre
- * 
- * - *

Which results in a new text "ss romooCCmmpnse", in adition the - * index of the first line that contained the original text is kept - - * in this case it is 1. The idea is that in a long English text all - * permutations that start with "he" are likely suffixes of a "the" and - * thus they end in "t" leading to a larger block of "t"s that can - * better be compressed by the subsequent Move-to-Front, run-length - * und Huffman encoding steps.

- * - *

For more information see for example:

- * - * - * @NotThreadSafe - */ -class BlockSort { - - /* - * Some of the constructs used in the C code cannot be ported - * literally to Java - for example macros, unsigned types. Some - * code has been hand-tuned to improve performance. In order to - * avoid memory pressure some structures are reused for several - * blocks and some memory is even shared between sorting and the - * MTF stage even though either algorithm uses it for its own - * purpose. - * - * Comments preserved from the actual C code are prefixed with - * "LBZ2:". - */ - - /* - * 2012-05-20 Stefan Bodewig: - * - * This class seems to mix several revisions of libbzip2's code. - * The mainSort function and those used by it look closer to the - * 0.9.5 version but show some variations introduced later. At - * the same time the logic of Compress 1.4 to randomize the block - * on bad input has been dropped after libbzip2 0.9.0 and replaced - * by a fallback sorting algorithm. - * - * I've added the fallbackSort function of 1.0.6 and tried to - * integrate it with the existing code without touching too much. - * I've also removed the now unused randomization code. - */ - - /* - * LBZ2: If you are ever unlucky/improbable enough to get a stack - * overflow whilst sorting, increase the following constant and - * try again. In practice I have never seen the stack go above 27 - * elems, so the following limit seems very generous. - */ - private static final int QSORT_STACK_SIZE = 1000; - - private static final int FALLBACK_QSORT_STACK_SIZE = 100; - - private static final int STACK_SIZE = - QSORT_STACK_SIZE < FALLBACK_QSORT_STACK_SIZE - ? FALLBACK_QSORT_STACK_SIZE : QSORT_STACK_SIZE; - - /* - * Used when sorting. If too many long comparisons happen, we stop sorting, - * and use fallbackSort instead. - */ - private int workDone; - private int workLimit; - private boolean firstAttempt; - - private final int[] stack_ll = new int[STACK_SIZE]; // 4000 byte - private final int[] stack_hh = new int[STACK_SIZE]; // 4000 byte - private final int[] stack_dd = new int[QSORT_STACK_SIZE]; // 4000 byte - - private final int[] mainSort_runningOrder = new int[256]; // 1024 byte - private final int[] mainSort_copy = new int[256]; // 1024 byte - private final boolean[] mainSort_bigDone = new boolean[256]; // 256 byte - - private final int[] ftab = new int[65537]; // 262148 byte - - /** - * Array instance identical to Data's sfmap, both are used only - * temporarily and indepently, so we do not need to allocate - * additional memory. - */ - private final char[] quadrant; - - BlockSort(final BZip2CompressorOutputStream.Data data) { - this.quadrant = data.sfmap; - } - - void blockSort(final BZip2CompressorOutputStream.Data data, final int last) { - this.workLimit = WORK_FACTOR * last; - this.workDone = 0; - this.firstAttempt = true; - - if (last + 1 < 10000) { - fallbackSort(data, last); - } else { - mainSort(data, last); - - if (this.firstAttempt && (this.workDone > this.workLimit)) { - fallbackSort(data, last); - } - } - - final int[] fmap = data.fmap; - data.origPtr = -1; - for (int i = 0; i <= last; i++) { - if (fmap[i] == 0) { - data.origPtr = i; - break; - } - } - - // assert (data.origPtr != -1) : data.origPtr; - } - - /** - * Adapt fallbackSort to the expected interface of the rest of the - * code, in particular deal with the fact that block starts at - * offset 1 (in libbzip2 1.0.6 it starts at 0). - */ - final void fallbackSort(final BZip2CompressorOutputStream.Data data, - final int last) { - data.block[0] = data.block[last + 1]; - fallbackSort(data.fmap, data.block, last + 1); - for (int i = 0; i < last + 1; i++) { - --data.fmap[i]; - } - for (int i = 0; i < last + 1; i++) { - if (data.fmap[i] == -1) { - data.fmap[i] = last; - break; - } - } - } - -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -/*--- LBZ2: Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - - /* - * This is the fallback sorting algorithm libbzip2 1.0.6 uses for - * repetitive or very short inputs. - * - * The idea is inspired by Manber-Myers string suffix sorting - * algorithm. First a bucket sort places each permutation of the - * block into a bucket based on its first byte. Permutations are - * represented by pointers to their first character kept in - * (partially) sorted order inside the array ftab. - * - * The next step visits all buckets in order and performs a - * quicksort on all permutations of the bucket based on the index - * of the bucket the second byte of the permutation belongs to, - * thereby forming new buckets. When arrived here the - * permutations are sorted up to the second character and we have - * buckets of permutations that are identical up to two - * characters. - * - * Repeat the step of quicksorting each bucket, now based on the - * bucket holding the sequence of the third and forth character - * leading to four byte buckets. Repeat this doubling of bucket - * sizes until all buckets only contain single permutations or the - * bucket size exceeds the block size. - * - * I.e. - * - * "abraba" form three buckets for the chars "a", "b", and "r" in - * the first step with - * - * fmap = { 'a:' 5, 3, 0, 'b:' 4, 1, 'r', 2 } - * - * when looking at the bucket of "a"s the second characters are in - * the buckets that start with fmap-index 0 (rolled over), 3 and 3 - * respectively, forming two new buckets "aa" and "ab", so we get - * - * fmap = { 'aa:' 5, 'ab:' 3, 0, 'ba:' 4, 'br': 1, 'ra:' 2 } - * - * since the last bucket only contained a single item it didn't - * have to be sorted at all. - * - * There now is just one bucket with more than one permutation - * that remains to be sorted. For the permutation that starts - * with index 3 the third and forth char are in bucket 'aa' at - * index 0 and for the one starting at block index 0 they are in - * bucket 'ra' with sort index 5. The fully sorted order then becomes. - * - * fmap = { 5, 3, 0, 4, 1, 2 } - * - */ - - /** - * @param fmap points to the index of the starting point of a - * permutation inside the block of data in the current - * partially sorted order - * @param eclass points from the index of a character inside the - * block to the first index in fmap that contains the - * bucket of its suffix that is sorted in this step. - * @param lo lower boundary of the fmap-interval to be sorted - * @param hi upper boundary of the fmap-interval to be sorted - */ - private void fallbackSimpleSort(final int[] fmap, - final int[] eclass, - final int lo, - final int hi) { - if (lo == hi) { - return; - } - - int j; - if (hi - lo > 3) { - for (int i = hi - 4; i >= lo; i--) { - final int tmp = fmap[i]; - final int ec_tmp = eclass[tmp]; - for (j = i + 4; j <= hi && ec_tmp > eclass[fmap[j]]; - j += 4) { - fmap[j - 4] = fmap[j]; - } - fmap[j - 4] = tmp; - } - } - - for (int i = hi - 1; i >= lo; i--) { - final int tmp = fmap[i]; - final int ec_tmp = eclass[tmp]; - for (j = i + 1; j <= hi && ec_tmp > eclass[fmap[j]]; j++) { - fmap[j - 1] = fmap[j]; - } - fmap[j-1] = tmp; - } - } - - private static final int FALLBACK_QSORT_SMALL_THRESH = 10; - - /** - * swaps two values in fmap - */ - private void fswap(final int[] fmap, final int zz1, final int zz2) { - final int zztmp = fmap[zz1]; - fmap[zz1] = fmap[zz2]; - fmap[zz2] = zztmp; - } - - /** - * swaps two intervals starting at yyp1 and yyp2 of length yyn inside fmap. - */ - private void fvswap(final int[] fmap, int yyp1, int yyp2, int yyn) { - while (yyn > 0) { - fswap(fmap, yyp1, yyp2); - yyp1++; yyp2++; yyn--; - } - } - - private int fmin(final int a, final int b) { - return a < b ? a : b; - } - - private void fpush(final int sp, final int lz, final int hz) { - stack_ll[sp] = lz; - stack_hh[sp] = hz; - } - - private int[] fpop(final int sp) { - return new int[] { stack_ll[sp], stack_hh[sp] }; - } - - /** - * @param fmap points to the index of the starting point of a - * permutation inside the block of data in the current - * partially sorted order - * @param eclass points from the index of a character inside the - * block to the first index in fmap that contains the - * bucket of its suffix that is sorted in this step. - * @param loSt lower boundary of the fmap-interval to be sorted - * @param hiSt upper boundary of the fmap-interval to be sorted - */ - private void fallbackQSort3(final int[] fmap, - final int[] eclass, - final int loSt, - final int hiSt) { - int lo, unLo, ltLo, hi, unHi, gtHi, n; - - long r = 0; - int sp = 0; - fpush(sp++, loSt, hiSt); - - while (sp > 0) { - final int[] s = fpop(--sp); - lo = s[0]; hi = s[1]; - - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort(fmap, eclass, lo, hi); - continue; - } - - /* LBZ2: Random partitioning. Median of 3 sometimes fails to - avoid bad cases. Median of 9 seems to help but - looks rather expensive. This too seems to work but - is cheaper. Guidance for the magic constants - 7621 and 32768 is taken from Sedgewick's algorithms - book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - final long r3 = r % 3; - long med; - if (r3 == 0) { - med = eclass[fmap[lo]]; - } else if (r3 == 1) { - med = eclass[fmap[(lo + hi) >>> 1]]; - } else { - med = eclass[fmap[hi]]; - } - - unLo = ltLo = lo; - unHi = gtHi = hi; - - // looks like the ternary partition attributed to Wegner - // in the cited Sedgewick paper - while (true) { - while (true) { - if (unLo > unHi) { - break; - } - n = eclass[fmap[unLo]] - (int) med; - if (n == 0) { - fswap(fmap, unLo, ltLo); - ltLo++; unLo++; - continue; - } - if (n > 0) { - break; - } - unLo++; - } - while (true) { - if (unLo > unHi) { - break; - } - n = eclass[fmap[unHi]] - (int) med; - if (n == 0) { - fswap(fmap, unHi, gtHi); - gtHi--; unHi--; - continue; - } - if (n < 0) { - break; - } - unHi--; - } - if (unLo > unHi) { - break; - } - fswap(fmap, unLo, unHi); unLo++; unHi--; - } - - if (gtHi < ltLo) { - continue; - } - - n = fmin(ltLo - lo, unLo - ltLo); - fvswap(fmap, lo, unLo - n, n); - int m = fmin(hi - gtHi, gtHi - unHi); - fvswap(fmap, unHi + 1, hi - m + 1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush(sp++, lo, n); - fpush(sp++, m, hi); - } else { - fpush(sp++, m, hi); - fpush(sp++, lo, n); - } - } - } - - -/*---------------------------------------------*/ - - private int[] eclass; - - private int[] getEclass() { - if (eclass == null) { - eclass = new int[quadrant.length / 2]; - } - return eclass; - } - - /* - * The C code uses an array of ints (each int holding 32 flags) to - * represents the bucket-start flags (bhtab). It also contains - * optimizations to skip over 32 consecutively set or - * consecutively unset bits on word boundaries at once. For now - * I've chosen to use the simpler but potentially slower code - * using BitSet - also in the hope that using the BitSet#nextXXX - * methods may be fast enough. - */ - - /** - * @param fmap points to the index of the starting point of a - * permutation inside the block of data in the current - * partially sorted order - * @param block the original data - * @param nblock size of the block - * @param off offset of first byte to sort in block - */ - final void fallbackSort(final int[] fmap, final byte[] block, final int nblock) { - final int[] ftab = new int[257]; - int H, i, j, k, l, r, cc, cc1; - int nNotDone; - int nBhtab; - final int[] eclass = getEclass(); - - for (i = 0; i < nblock; i++) { - eclass[i] = 0; - } - /*-- - LBZ2: Initial 1-char radix sort to generate - initial fmap and initial BH bits. - --*/ - for (i = 0; i < nblock; i++) { - ftab[block[i] & 0xff]++; - } - for (i = 1; i < 257; i++) { - ftab[i] += ftab[i - 1]; - } - - for (i = 0; i < nblock; i++) { - j = block[i] & 0xff; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 64 + nblock; - final BitSet bhtab = new BitSet(nBhtab); - for (i = 0; i < 256; i++) { - bhtab.set(ftab[i]); - } - - /*-- - LBZ2: Inductively refine the buckets. Kind-of an - "exponential radix sort" (!), inspired by the - Manber-Myers suffix array construction algorithm. - --*/ - - /*-- LBZ2: set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - bhtab.set(nblock + 2 * i); - bhtab.clear(nblock + 2 * i + 1); - } - - /*-- LBZ2: the log(N) loop --*/ - H = 1; - while (true) { - - j = 0; - for (i = 0; i < nblock; i++) { - if (bhtab.get(i)) { - j = i; - } - k = fmap[i] - H; - if (k < 0) { - k += nblock; - } - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (true) { - - /*-- LBZ2: find the next non-singleton bucket --*/ - k = r + 1; - k = bhtab.nextClearBit(k); - l = k - 1; - if (l >= nblock) { - break; - } - k = bhtab.nextSetBit(k + 1); - r = k - 1; - if (r >= nblock) { - break; - } - - /*-- LBZ2: now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3(fmap, eclass, l, r); - - /*-- LBZ2: scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { - bhtab.set(i); - cc = cc1; - } - } - } - } - - H *= 2; - if (H > nblock || nNotDone == 0) { - break; - } - } - } - -/*---------------------------------------------*/ - - /* - * LBZ2: Knuth's increments seem to work better than Incerpi-Sedgewick here. - * Possibly because the number of elems to sort is usually small, typically - * <= 20. - */ - private static final int[] INCS = { 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, 797161, - 2391484 }; - - /** - * This is the most hammered method of this class. - * - *

- * This is the version using unrolled loops. Normally I never use such ones - * in Java code. The unrolling has shown a noticable performance improvement - * on JRE 1.4.2 (Linux i586 / HotSpot Client). Of course it depends on the - * JIT compiler of the vm. - *

- */ - private boolean mainSimpleSort(final BZip2CompressorOutputStream.Data dataShadow, - final int lo, final int hi, final int d, - final int lastShadow) { - final int bigN = hi - lo + 1; - if (bigN < 2) { - return this.firstAttempt && (this.workDone > this.workLimit); - } - - int hp = 0; - while (INCS[hp] < bigN) { - hp++; - } - - final int[] fmap = dataShadow.fmap; - final char[] quadrant = this.quadrant; - final byte[] block = dataShadow.block; - final int lastPlus1 = lastShadow + 1; - final boolean firstAttemptShadow = this.firstAttempt; - final int workLimitShadow = this.workLimit; - int workDoneShadow = this.workDone; - - // Following block contains unrolled code which could be shortened by - // coding it in additional loops. - - HP: while (--hp >= 0) { - final int h = INCS[hp]; - final int mj = lo + h - 1; - - for (int i = lo + h; i <= hi;) { - // copy - for (int k = 3; (i <= hi) && (--k >= 0); i++) { - final int v = fmap[i]; - final int vd = v + d; - int j = i; - - // for (int a; - // (j > mj) && mainGtU((a = fmap[j - h]) + d, vd, - // block, quadrant, lastShadow); - // j -= h) { - // fmap[j] = a; - // } - // - // unrolled version: - - // start inline mainGTU - boolean onceRunned = false; - int a = 0; - - HAMMER: while (true) { - if (onceRunned) { - fmap[j] = a; - if ((j -= h) <= mj) { //NOSONAR - break HAMMER; - } - } else { - onceRunned = true; - } - - a = fmap[j - h]; - int i1 = a + d; - int i2 = vd; - - // following could be done in a loop, but - // unrolled it for performance: - if (block[i1 + 1] == block[i2 + 1]) { - if (block[i1 + 2] == block[i2 + 2]) { - if (block[i1 + 3] == block[i2 + 3]) { - if (block[i1 + 4] == block[i2 + 4]) { - if (block[i1 + 5] == block[i2 + 5]) { - if (block[(i1 += 6)] == block[(i2 += 6)]) { //NOSONAR - int x = lastShadow; - X: while (x > 0) { - x -= 4; - - if (block[i1 + 1] == block[i2 + 1]) { - if (quadrant[i1] == quadrant[i2]) { - if (block[i1 + 2] == block[i2 + 2]) { - if (quadrant[i1 + 1] == quadrant[i2 + 1]) { - if (block[i1 + 3] == block[i2 + 3]) { - if (quadrant[i1 + 2] == quadrant[i2 + 2]) { - if (block[i1 + 4] == block[i2 + 4]) { - if (quadrant[i1 + 3] == quadrant[i2 + 3]) { - if ((i1 += 4) >= lastPlus1) { //NOSONAR - i1 -= lastPlus1; - } - if ((i2 += 4) >= lastPlus1) { //NOSONAR - i2 -= lastPlus1; - } - workDoneShadow++; - continue X; - } else if ((quadrant[i1 + 3] > quadrant[i2 + 3])) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 4] & 0xff) > (block[i2 + 4] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((quadrant[i1 + 2] > quadrant[i2 + 2])) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 3] & 0xff) > (block[i2 + 3] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((quadrant[i1 + 1] > quadrant[i2 + 1])) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 2] & 0xff) > (block[i2 + 2] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((quadrant[i1] > quadrant[i2])) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 1] & 0xff) > (block[i2 + 1] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - - } - break HAMMER; - } // while x > 0 - if ((block[i1] & 0xff) > (block[i2] & 0xff)) { - continue HAMMER; - } - break HAMMER; - } else if ((block[i1 + 5] & 0xff) > (block[i2 + 5] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 4] & 0xff) > (block[i2 + 4] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 3] & 0xff) > (block[i2 + 3] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 2] & 0xff) > (block[i2 + 2] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - } else if ((block[i1 + 1] & 0xff) > (block[i2 + 1] & 0xff)) { - continue HAMMER; - } else { - break HAMMER; - } - - } // HAMMER - // end inline mainGTU - - fmap[j] = v; - } - - if (firstAttemptShadow && (i <= hi) - && (workDoneShadow > workLimitShadow)) { - break HP; - } - } - } - - this.workDone = workDoneShadow; - return firstAttemptShadow && (workDoneShadow > workLimitShadow); - } - -/*-- - LBZ2: The following is an implementation of - an elegant 3-way quicksort for strings, - described in a paper "Fast Algorithms for - Sorting and Searching Strings", by Robert - Sedgewick and Jon L. Bentley. ---*/ - - private static void vswap(final int[] fmap, int p1, int p2, int n) { - n += p1; - while (p1 < n) { - final int t = fmap[p1]; - fmap[p1++] = fmap[p2]; - fmap[p2++] = t; - } - } - - private static byte med3(final byte a, final byte b, final byte c) { - return (a < b) ? (b < c ? b : a < c ? c : a) : (b > c ? b : a > c ? c - : a); - } - - private static final int SMALL_THRESH = 20; - private static final int DEPTH_THRESH = 10; - private static final int WORK_FACTOR = 30; - - /** - * Method "mainQSort3", file "blocksort.c", BZip2 1.0.2 - */ - private void mainQSort3(final BZip2CompressorOutputStream.Data dataShadow, - final int loSt, final int hiSt, final int dSt, - final int last) { - final int[] stack_ll = this.stack_ll; - final int[] stack_hh = this.stack_hh; - final int[] stack_dd = this.stack_dd; - final int[] fmap = dataShadow.fmap; - final byte[] block = dataShadow.block; - - stack_ll[0] = loSt; - stack_hh[0] = hiSt; - stack_dd[0] = dSt; - - for (int sp = 1; --sp >= 0;) { - final int lo = stack_ll[sp]; - final int hi = stack_hh[sp]; - final int d = stack_dd[sp]; - - if ((hi - lo < SMALL_THRESH) || (d > DEPTH_THRESH)) { - if (mainSimpleSort(dataShadow, lo, hi, d, last)) { - return; - } - } else { - final int d1 = d + 1; - final int med = med3(block[fmap[lo] + d1], - block[fmap[hi] + d1], block[fmap[(lo + hi) >>> 1] + d1]) & 0xff; - - int unLo = lo; - int unHi = hi; - int ltLo = lo; - int gtHi = hi; - - while (true) { - while (unLo <= unHi) { - final int n = (block[fmap[unLo] + d1] & 0xff) - - med; - if (n == 0) { - final int temp = fmap[unLo]; - fmap[unLo++] = fmap[ltLo]; - fmap[ltLo++] = temp; - } else if (n < 0) { - unLo++; - } else { - break; - } - } - - while (unLo <= unHi) { - final int n = (block[fmap[unHi] + d1] & 0xff) - - med; - if (n == 0) { - final int temp = fmap[unHi]; - fmap[unHi--] = fmap[gtHi]; - fmap[gtHi--] = temp; - } else if (n > 0) { - unHi--; - } else { - break; - } - } - - if (unLo <= unHi) { - final int temp = fmap[unLo]; - fmap[unLo++] = fmap[unHi]; - fmap[unHi--] = temp; - } else { - break; - } - } - - if (gtHi < ltLo) { - stack_ll[sp] = lo; - stack_hh[sp] = hi; - stack_dd[sp] = d1; - sp++; - } else { - int n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) - : (unLo - ltLo); - vswap(fmap, lo, unLo - n, n); - int m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) - : (gtHi - unHi); - vswap(fmap, unLo, hi - m + 1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - stack_ll[sp] = lo; - stack_hh[sp] = n; - stack_dd[sp] = d; - sp++; - - stack_ll[sp] = n + 1; - stack_hh[sp] = m - 1; - stack_dd[sp] = d1; - sp++; - - stack_ll[sp] = m; - stack_hh[sp] = hi; - stack_dd[sp] = d; - sp++; - } - } - } - } - - private static final int SETMASK = (1 << 21); - private static final int CLEARMASK = (~SETMASK); - - final void mainSort(final BZip2CompressorOutputStream.Data dataShadow, - final int lastShadow) { - final int[] runningOrder = this.mainSort_runningOrder; - final int[] copy = this.mainSort_copy; - final boolean[] bigDone = this.mainSort_bigDone; - final int[] ftab = this.ftab; - final byte[] block = dataShadow.block; - final int[] fmap = dataShadow.fmap; - final char[] quadrant = this.quadrant; - final int workLimitShadow = this.workLimit; - final boolean firstAttemptShadow = this.firstAttempt; - - // LBZ2: Set up the 2-byte frequency table - for (int i = 65537; --i >= 0;) { - ftab[i] = 0; - } - - /* - * In the various block-sized structures, live data runs from 0 to - * last+NUM_OVERSHOOT_BYTES inclusive. First, set up the overshoot area - * for block. - */ - for (int i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) { - block[lastShadow + i + 2] = block[(i % (lastShadow + 1)) + 1]; - } - for (int i = lastShadow + BZip2Constants.NUM_OVERSHOOT_BYTES +1; --i >= 0;) { - quadrant[i] = 0; - } - block[0] = block[lastShadow + 1]; - - // LBZ2: Complete the initial radix sort: - - int c1 = block[0] & 0xff; - for (int i = 0; i <= lastShadow; i++) { - final int c2 = block[i + 1] & 0xff; - ftab[(c1 << 8) + c2]++; - c1 = c2; - } - - for (int i = 1; i <= 65536; i++) { - ftab[i] += ftab[i - 1]; - } - - c1 = block[1] & 0xff; - for (int i = 0; i < lastShadow; i++) { - final int c2 = block[i + 2] & 0xff; - fmap[--ftab[(c1 << 8) + c2]] = i; - c1 = c2; - } - - fmap[--ftab[((block[lastShadow + 1] & 0xff) << 8) + (block[1] & 0xff)]] = lastShadow; - - /* - * LBZ2: Now ftab contains the first loc of every small bucket. Calculate the - * running order, from smallest to largest big bucket. - */ - for (int i = 256; --i >= 0;) { - bigDone[i] = false; - runningOrder[i] = i; - } - - // h = 364, 121, 40, 13, 4, 1 - for (int h = 364; h != 1;) { //NOSONAR - h /= 3; - for (int i = h; i <= 255; i++) { - final int vv = runningOrder[i]; - final int a = ftab[(vv + 1) << 8] - ftab[vv << 8]; - final int b = h - 1; - int j = i; - for (int ro = runningOrder[j - h]; (ftab[(ro + 1) << 8] - ftab[ro << 8]) > a; ro = runningOrder[j - - h]) { - runningOrder[j] = ro; - j -= h; - if (j <= b) { - break; - } - } - runningOrder[j] = vv; - } - } - - /* - * LBZ2: The main sorting loop. - */ - for (int i = 0; i <= 255; i++) { - /* - * LBZ2: Process big buckets, starting with the least full. - */ - final int ss = runningOrder[i]; - - // Step 1: - /* - * LBZ2: Complete the big bucket [ss] by quicksorting any unsorted small - * buckets [ss, j]. Hopefully previous pointer-scanning phases have - * already completed many of the small buckets [ss, j], so we don't - * have to sort them at all. - */ - for (int j = 0; j <= 255; j++) { - final int sb = (ss << 8) + j; - final int ftab_sb = ftab[sb]; - if ((ftab_sb & SETMASK) != SETMASK) { - final int lo = ftab_sb & CLEARMASK; - final int hi = (ftab[sb + 1] & CLEARMASK) - 1; - if (hi > lo) { - mainQSort3(dataShadow, lo, hi, 2, lastShadow); - if (firstAttemptShadow - && (this.workDone > workLimitShadow)) { - return; - } - } - ftab[sb] = ftab_sb | SETMASK; - } - } - - // Step 2: - // LBZ2: Now scan this big bucket so as to synthesise the - // sorted order for small buckets [t, ss] for all t != ss. - - for (int j = 0; j <= 255; j++) { - copy[j] = ftab[(j << 8) + ss] & CLEARMASK; - } - - for (int j = ftab[ss << 8] & CLEARMASK, hj = (ftab[(ss + 1) << 8] & CLEARMASK); j < hj; j++) { - final int fmap_j = fmap[j]; - c1 = block[fmap_j] & 0xff; - if (!bigDone[c1]) { - fmap[copy[c1]] = (fmap_j == 0) ? lastShadow : (fmap_j - 1); - copy[c1]++; - } - } - - for (int j = 256; --j >= 0;) { - ftab[(j << 8) + ss] |= SETMASK; - } - - // Step 3: - /* - * LBZ2: The ss big bucket is now done. Record this fact, and update the - * quadrant descriptors. Remember to update quadrants in the - * overshoot area too, if necessary. The "if (i < 255)" test merely - * skips this updating for the last bucket processed, since updating - * for the last bucket is pointless. - */ - bigDone[ss] = true; - - if (i < 255) { - final int bbStart = ftab[ss << 8] & CLEARMASK; - final int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart; - int shifts = 0; - - while ((bbSize >> shifts) > 65534) { - shifts++; - } - - for (int j = 0; j < bbSize; j++) { - final int a2update = fmap[bbStart + j]; - final char qVal = (char) (j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) { - quadrant[a2update + lastShadow + 1] = qVal; - } - } - } - - } - } - -} diff --git a/src/org/apache/commons/compress/compressors/bzip2/CRC.java b/src/org/apache/commons/compress/compressors/bzip2/CRC.java deleted file mode 100644 index a20ea7063d5..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/CRC.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.bzip2; - -/** - * A simple class the hold and calculate the CRC for sanity checking of the - * data. - * @NotThreadSafe - */ -class CRC { - private static final int crc32Table[] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, - 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, - 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, - 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, - 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, - 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, - 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, - 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, - 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, - 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, - 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, - 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, - 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, - 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, - 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, - 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, - 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, - 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, - 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, - 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, - 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, - 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, - 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, - 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, - 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, - 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, - 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, - 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, - 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, - 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, - 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, - 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, - 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, - 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, - 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, - 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, - 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, - 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, - 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, - 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, - 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, - 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, - 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 - }; - - CRC() { - initialiseCRC(); - } - - void initialiseCRC() { - globalCrc = 0xffffffff; - } - - int getFinalCRC() { - return ~globalCrc; - } - - int getGlobalCRC() { - return globalCrc; - } - - void setGlobalCRC(final int newCrc) { - globalCrc = newCrc; - } - - void updateCRC(final int inCh) { - int temp = (globalCrc >> 24) ^ inCh; - if (temp < 0) { - temp = 256 + temp; - } - globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp]; - } - - void updateCRC(final int inCh, int repeat) { - int globalCrcShadow = this.globalCrc; - while (repeat-- > 0) { - final int temp = (globalCrcShadow >> 24) ^ inCh; - globalCrcShadow = (globalCrcShadow << 8) ^ crc32Table[(temp >= 0) - ? temp - : (temp + 256)]; - } - this.globalCrc = globalCrcShadow; - } - - private int globalCrc; -} \ No newline at end of file diff --git a/src/org/apache/commons/compress/compressors/bzip2/Rand.java b/src/org/apache/commons/compress/compressors/bzip2/Rand.java deleted file mode 100644 index bb6ef80bae9..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/Rand.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.bzip2; - -/** - * Random numbers for both the compress and decompress BZip2 classes. - */ -final class Rand { - - private static final int[] RNUMS = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 - }; - - /** - * Return the random number at a specific index. - * - * @param i the index - * @return the random number - */ - static int rNums(final int i){ - return RNUMS[i]; - } -} \ No newline at end of file diff --git a/src/org/apache/commons/compress/compressors/bzip2/package.html b/src/org/apache/commons/compress/compressors/bzip2/package.html deleted file mode 100644 index fe27e6e6668..00000000000 --- a/src/org/apache/commons/compress/compressors/bzip2/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides stream classes for compressing and decompressing - streams using the BZip2 algorithm.

- - diff --git a/src/org/apache/commons/compress/compressors/deflate/DeflateCompressorInputStream.java b/src/org/apache/commons/compress/compressors/deflate/DeflateCompressorInputStream.java deleted file mode 100644 index 0e072844ab0..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate/DeflateCompressorInputStream.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.deflate; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * Deflate decompressor. - * @since 1.9 - */ -public class DeflateCompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - private static final int MAGIC_1 = 0x78; - private static final int MAGIC_2a = 0x01; - private static final int MAGIC_2b = 0x5e; - private static final int MAGIC_2c = 0x9c; - private static final int MAGIC_2d = 0xda; - - private final CountingInputStream countingStream; - private final InputStream in; - private final Inflater inflater; - - /** - * Creates a new input stream that decompresses Deflate-compressed data - * from the specified input stream. - * - * @param inputStream where to read the compressed data - * - */ - public DeflateCompressorInputStream(final InputStream inputStream) { - this(inputStream, new DeflateParameters()); - } - - /** - * Creates a new input stream that decompresses Deflate-compressed data - * from the specified input stream. - * - * @param inputStream where to read the compressed data - * @param parameters parameters - */ - public DeflateCompressorInputStream(final InputStream inputStream, - final DeflateParameters parameters) { - inflater = new Inflater(!parameters.withZlibHeader()); - in = new InflaterInputStream(countingStream = new CountingInputStream(inputStream), inflater); - } - - /** {@inheritDoc} */ - @Override - public int read() throws IOException { - final int ret = in.read(); - count(ret == -1 ? 0 : 1); - return ret; - } - - /** {@inheritDoc} */ - @Override - public int read(final byte[] buf, final int off, final int len) throws IOException { - final int ret = in.read(buf, off, len); - count(ret); - return ret; - } - - /** {@inheritDoc} */ - @Override - public long skip(final long n) throws IOException { - return IOUtils.skip(in, n); - } - - /** {@inheritDoc} */ - @Override - public int available() throws IOException { - return in.available(); - } - - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - try { - in.close(); - } finally { - inflater.end(); - } - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return countingStream.getBytesRead(); - } - - /** - * Checks if the signature matches what is expected for a zlib / deflated file - * with the zlib header. - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is zlib / deflate compressed with a header - * stream, false otherwise - * - * @since 1.10 - */ - public static boolean matches(final byte[] signature, final int length) { - return length > 3 && signature[0] == MAGIC_1 && ( - signature[1] == (byte) MAGIC_2a || - signature[1] == (byte) MAGIC_2b || - signature[1] == (byte) MAGIC_2c || - signature[1] == (byte) MAGIC_2d); - } -} diff --git a/src/org/apache/commons/compress/compressors/deflate/DeflateCompressorOutputStream.java b/src/org/apache/commons/compress/compressors/deflate/DeflateCompressorOutputStream.java deleted file mode 100644 index a315605636d..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate/DeflateCompressorOutputStream.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.deflate; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; - -/** - * Deflate compressor. - * @since 1.9 - */ -public class DeflateCompressorOutputStream extends CompressorOutputStream { - private final DeflaterOutputStream out; - private final Deflater deflater; - - /** - * Creates a Deflate compressed output stream with the default parameters. - * @param outputStream the stream to wrap - * @throws IOException on error - */ - public DeflateCompressorOutputStream(final OutputStream outputStream) throws IOException { - this(outputStream, new DeflateParameters()); - } - - /** - * Creates a Deflate compressed output stream with the specified parameters. - * @param outputStream the stream to wrap - * @param parameters the deflate parameters to apply - * @throws IOException on error - */ - public DeflateCompressorOutputStream(final OutputStream outputStream, - final DeflateParameters parameters) throws IOException { - this.deflater = new Deflater(parameters.getCompressionLevel(), !parameters.withZlibHeader()); - this.out = new DeflaterOutputStream(outputStream, deflater); - } - - @Override - public void write(final int b) throws IOException { - out.write(b); - } - - @Override - public void write(final byte[] buf, final int off, final int len) throws IOException { - out.write(buf, off, len); - } - - /** - * Flushes the encoder and calls outputStream.flush(). - * All buffered pending data will then be decompressible from - * the output stream. Calling this function very often may increase - * the compressed file size a lot. - */ - @Override - public void flush() throws IOException { - out.flush(); - } - - /** - * Finishes compression without closing the underlying stream. - *

No more data can be written to this stream after finishing.

- * @throws IOException on error - */ - public void finish() throws IOException { - out.finish(); - } - - @Override - public void close() throws IOException { - try { - out.close(); - } finally { - deflater.end(); - } - } -} diff --git a/src/org/apache/commons/compress/compressors/deflate/DeflateParameters.java b/src/org/apache/commons/compress/compressors/deflate/DeflateParameters.java deleted file mode 100644 index 7679942a276..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate/DeflateParameters.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.deflate; - -import java.util.zip.Deflater; - -/** - * Parameters for the Deflate compressor. - * @since 1.9 - */ -public class DeflateParameters { - - private boolean zlibHeader = true; - private int compressionLevel = Deflater.DEFAULT_COMPRESSION; - - /** - * Whether or not the zlib header shall be written (when - * compressing) or expected (when decompressing). - * @return true if zlib header shall be written - */ - public boolean withZlibHeader() { - return zlibHeader; - } - - /** - * Sets the zlib header presence parameter. - * - *

This affects whether or not the zlib header will be written - * (when compressing) or expected (when decompressing).

- * - * @param zlibHeader true if zlib header shall be written - */ - public void setWithZlibHeader(final boolean zlibHeader) { - this.zlibHeader = zlibHeader; - } - - /** - * The compression level. - * @see #setCompressionLevel - * @return the compression level - */ - public int getCompressionLevel() { - return compressionLevel; - } - - /** - * Sets the compression level. - * - * @param compressionLevel the compression level (between 0 and 9) - * @see Deflater#NO_COMPRESSION - * @see Deflater#BEST_SPEED - * @see Deflater#DEFAULT_COMPRESSION - * @see Deflater#BEST_COMPRESSION - */ - public void setCompressionLevel(final int compressionLevel) { - if (compressionLevel < -1 || compressionLevel > 9) { - throw new IllegalArgumentException("Invalid Deflate compression level: " + compressionLevel); - } - this.compressionLevel = compressionLevel; - } - -} diff --git a/src/org/apache/commons/compress/compressors/deflate/package.html b/src/org/apache/commons/compress/compressors/deflate/package.html deleted file mode 100644 index 4ddeb74873d..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides a stream classes that allow (de)compressing streams - using the DEFLATE algorithm.

- - diff --git a/src/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java b/src/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java deleted file mode 100644 index 883647b141b..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.compressors.deflate64; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.InputStreamStatistics; - -import static org.apache.commons.compress.utils.IOUtils.closeQuietly; - -/** - * Deflate64 decompressor. - * - * @since 1.16 - * @NotThreadSafe - */ -public class Deflate64CompressorInputStream extends CompressorInputStream implements InputStreamStatistics { - private InputStream originalStream; - private HuffmanDecoder decoder; - private long compressedBytesRead; - private final byte[] oneByte = new byte[1]; - - /** - * Constructs a Deflate64CompressorInputStream. - * - * @param in the stream to read from - */ - public Deflate64CompressorInputStream(InputStream in) { - this(new HuffmanDecoder(in)); - originalStream = in; - } - - Deflate64CompressorInputStream(HuffmanDecoder decoder) { - this.decoder = decoder; - } - - /** - * @throws java.io.EOFException if the underlying stream is exhausted before the end of defalted data was reached. - */ - @Override - public int read() throws IOException { - while (true) { - int r = read(oneByte); - switch (r) { - case 1: - return oneByte[0] & 0xFF; - case -1: - return -1; - case 0: - continue; - default: - throw new IllegalStateException("Invalid return value from read: " + r); - } - } - } - - /** - * @throws java.io.EOFException if the underlying stream is exhausted before the end of defalted data was reached. - */ - @Override - public int read(byte[] b, int off, int len) throws IOException { - int read = -1; - if (decoder != null) { - read = decoder.decode(b, off, len); - compressedBytesRead = decoder.getBytesRead(); - count(read); - if (read == -1) { - closeDecoder(); - } - } - return read; - } - - @Override - public int available() throws IOException { - return decoder != null ? decoder.available() : 0; - } - - @Override - public void close() throws IOException { - closeDecoder(); - if (originalStream != null) { - originalStream.close(); - originalStream = null; - } - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return compressedBytesRead; - } - - private void closeDecoder() { - closeQuietly(decoder); - decoder = null; - } -} diff --git a/src/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java b/src/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java deleted file mode 100644 index a6afa2cbcb8..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.compressors.deflate64; - -import org.apache.commons.compress.utils.BitInputStream; - -import java.io.Closeable; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteOrder; -import java.util.Arrays; - -import static org.apache.commons.compress.compressors.deflate64.HuffmanState.*; - -class HuffmanDecoder implements Closeable { - - /** - *
-     * --------------------------------------------------------------------
-     * idx  xtra  base     idx  xtra  base     idx  xtra  base
-     * --------------------------------------------------------------------
-     * 257   0     3       267   1   15,16     277   4   67-82
-     * 258   0     4       268   1   17,18     278   4   83-98
-     * 259   0     5       269   2   19-22     279   4   99-114
-     * 260   0     6       270   2   23-26     280   4   115-130
-     * 261   0     7       271   2   27-30     281   5   131-162
-     * 262   0     8       272   2   31-34     282   5   163-194
-     * 263   0     9       273   3   35-42     283   5   195-226
-     * 264   0     10      274   3   43-50     284   5   227-257
-     * 265   1     11,12   275   3   51-58     285   16  3
-     * 266   1     13,14   276   3   59-66
-     * --------------------------------------------------------------------
-     * 
- * value = (base of run length) << 5 | (number of extra bits to read) - */ - private static final short[] RUN_LENGTH_TABLE = { - 96, 128, 160, 192, 224, 256, 288, 320, 353, 417, 481, 545, 610, 738, 866, - 994, 1123, 1379, 1635, 1891, 2148, 2660, 3172, 3684, 4197, 5221, 6245, 7269, 112 - }; - - /** - *
-     * --------------------------------------------------------------------
-     * idx  xtra  dist     idx  xtra  dist       idx  xtra  dist
-     * --------------------------------------------------------------------
-     * 0    0     1        10   4     33-48      20    9   1025-1536
-     * 1    0     2        11   4     49-64      21    9   1537-2048
-     * 2    0     3        12   5     65-96      22   10   2049-3072
-     * 3    0     4        13   5     97-128     23   10   3073-4096
-     * 4    1     5,6      14   6     129-192    24   11   4097-6144
-     * 5    1     7,8      15   6     193-256    25   11   6145-8192
-     * 6    2     9-12     16   7     257-384    26   12   8193-12288
-     * 7    2     13-16    17   7     385-512    27   12   12289-16384
-     * 8    3     17-24    18   8     513-768    28   13   16385-24576
-     * 9    3     25-32    19   8     769-1024   29   13   24577-32768
-     * 30   14   32769-49152
-     * 31   14   49153-65536
-     * --------------------------------------------------------------------
-     * 
- * value = (base of distance) << 4 | (number of extra bits to read) - */ - private static final int[] DISTANCE_TABLE = { - 16, 32, 48, 64, 81, 113, 146, 210, 275, 403, // 0-9 - 532, 788, 1045, 1557, 2070, 3094, 4119, 6167, 8216, 12312, // 10-19 - 16409, 24601, 32794, 49178, 65563, 98331, 131100, 196636, 262173, 393245, // 20-29 - 524318, 786462 // 30-31 - }; - - /** - * When using dynamic huffman codes the order in which the values are stored - * follows the positioning below - */ - private static final int[] CODE_LENGTHS_ORDER = - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /** - * Huffman Fixed Literal / Distance tables for mode 1 - */ - private static final int[] FIXED_LITERALS; - private static final int[] FIXED_DISTANCE; - - static { - FIXED_LITERALS = new int[288]; - Arrays.fill(FIXED_LITERALS, 0, 144, 8); - Arrays.fill(FIXED_LITERALS, 144, 256, 9); - Arrays.fill(FIXED_LITERALS, 256, 280, 7); - Arrays.fill(FIXED_LITERALS, 280, 288, 8); - - FIXED_DISTANCE = new int[32]; - Arrays.fill(FIXED_DISTANCE, 5); - } - - private boolean finalBlock = false; - private DecoderState state; - private BitInputStream reader; - private final InputStream in; - - private final DecodingMemory memory = new DecodingMemory(); - - HuffmanDecoder(InputStream in) { - this.reader = new BitInputStream(in, ByteOrder.LITTLE_ENDIAN); - this.in = in; - state = new InitialState(); - } - - @Override - public void close() { - state = new InitialState(); - reader = null; - } - - public int decode(byte[] b) throws IOException { - return decode(b, 0, b.length); - } - - public int decode(byte[] b, int off, int len) throws IOException { - while (!finalBlock || state.hasData()) { - if (state.state() == INITIAL) { - finalBlock = readBits(1) == 1; - int mode = (int) readBits(2); - switch (mode) { - case 0: - switchToUncompressedState(); - break; - case 1: - state = new HuffmanCodes(FIXED_CODES, FIXED_LITERALS, FIXED_DISTANCE); - break; - case 2: - int[][] tables = readDynamicTables(); - state = new HuffmanCodes(DYNAMIC_CODES, tables[0], tables[1]); - break; - default: - throw new IllegalStateException("Unsupported compression: " + mode); - } - } else { - return state.read(b, off, len); - } - } - return -1; - } - - /** - * @since 1.17 - */ - long getBytesRead() { - return reader.getBytesRead(); - } - - private void switchToUncompressedState() throws IOException { - reader.alignWithByteBoundary(); - long bLen = readBits(16); - long bNLen = readBits(16); - if (((bLen ^ 0xFFFF) & 0xFFFF) != bNLen) { - //noinspection DuplicateStringLiteralInspection - throw new IllegalStateException("Illegal LEN / NLEN values"); - } - state = new UncompressedState(bLen); - } - - private int[][] readDynamicTables() throws IOException { - int[][] result = new int[2][]; - int literals = (int) (readBits(5) + 257); - result[0] = new int[literals]; - - int distances = (int) (readBits(5) + 1); - result[1] = new int[distances]; - - populateDynamicTables(reader, result[0], result[1]); - return result; - } - - int available() throws IOException { - return state.available(); - } - - private abstract static class DecoderState { - abstract HuffmanState state(); - - abstract int read(byte[] b, int off, int len) throws IOException; - - abstract boolean hasData(); - - abstract int available() throws IOException ; - } - - private class UncompressedState extends DecoderState { - private final long blockLength; - private long read; - - private UncompressedState(long blockLength) { - this.blockLength = blockLength; - } - - @Override - HuffmanState state() { - return read < blockLength ? STORED : INITIAL; - } - - @Override - int read(byte[] b, int off, int len) throws IOException { - // as len is an int and (blockLength - read) is >= 0 the min must fit into an int as well - int max = (int) Math.min(blockLength - read, len); - int readSoFar = 0; - while (readSoFar < max) { - int readNow; - if (reader.bitsCached() > 0) { - byte next = (byte) readBits(Byte.SIZE); - b[off + readSoFar] = memory.add(next); - readNow = 1; - } else { - readNow = in.read(b, off + readSoFar, max - readSoFar); - if (readNow == -1) { - throw new EOFException("Truncated Deflate64 Stream"); - } - memory.add(b, off + readSoFar, readNow); - } - read += readNow; - readSoFar += readNow; - } - return max; - } - - @Override - boolean hasData() { - return read < blockLength; - } - - @Override - int available() throws IOException { - return (int) Math.min(blockLength - read, reader.bitsAvailable() / Byte.SIZE); - } - } - - private class InitialState extends DecoderState { - @Override - HuffmanState state() { - return INITIAL; - } - - @Override - int read(byte[] b, int off, int len) throws IOException { - throw new IllegalStateException("Cannot read in this state"); - } - - @Override - boolean hasData() { - return false; - } - - @Override - int available() { - return 0; - } - } - - private class HuffmanCodes extends DecoderState { - private boolean endOfBlock = false; - private final HuffmanState state; - private final BinaryTreeNode lengthTree; - private final BinaryTreeNode distanceTree; - - private int runBufferPos = 0; - private byte[] runBuffer = new byte[0]; - private int runBufferLength = 0; - - HuffmanCodes(HuffmanState state, int[] lengths, int[] distance) { - this.state = state; - lengthTree = buildTree(lengths); - distanceTree = buildTree(distance); - } - - @Override - HuffmanState state() { - return endOfBlock ? INITIAL : state; - } - - @Override - int read(byte[] b, int off, int len) throws IOException { - return decodeNext(b, off, len); - } - - private int decodeNext(byte[] b, int off, int len) throws IOException { - if (endOfBlock) { - return -1; - } - int result = copyFromRunBuffer(b, off, len); - - while (result < len) { - int symbol = nextSymbol(reader, lengthTree); - if (symbol < 256) { - b[off + result++] = memory.add((byte) symbol); - } else if (symbol > 256) { - int runMask = RUN_LENGTH_TABLE[symbol - 257]; - int run = runMask >>> 5; - int runXtra = runMask & 0x1F; - run += readBits(runXtra); - - int distSym = nextSymbol(reader, distanceTree); - - int distMask = DISTANCE_TABLE[distSym]; - int dist = distMask >>> 4; - int distXtra = distMask & 0xF; - dist += readBits(distXtra); - - if (runBuffer.length < run) { - runBuffer = new byte[run]; - } - runBufferLength = run; - runBufferPos = 0; - memory.recordToBuffer(dist, run, runBuffer); - - result += copyFromRunBuffer(b, off + result, len - result); - } else { - endOfBlock = true; - return result; - } - } - - return result; - } - - private int copyFromRunBuffer(byte[] b, int off, int len) { - int bytesInBuffer = runBufferLength - runBufferPos; - int copiedBytes = 0; - if (bytesInBuffer > 0) { - copiedBytes = Math.min(len, bytesInBuffer); - System.arraycopy(runBuffer, runBufferPos, b, off, copiedBytes); - runBufferPos += copiedBytes; - } - return copiedBytes; - } - - @Override - boolean hasData() { - return !endOfBlock; - } - - @Override - int available() { - return runBufferLength - runBufferPos; - } - } - - private static int nextSymbol(BitInputStream reader, BinaryTreeNode tree) throws IOException { - BinaryTreeNode node = tree; - while (node != null && node.literal == -1) { - long bit = readBits(reader, 1); - node = bit == 0 ? node.leftNode : node.rightNode; - } - return node != null ? node.literal : -1; - } - - private static void populateDynamicTables(BitInputStream reader, int[] literals, int[] distances) throws IOException { - int codeLengths = (int) (readBits(reader, 4) + 4); - - int[] codeLengthValues = new int[19]; - for (int cLen = 0; cLen < codeLengths; cLen++) { - codeLengthValues[CODE_LENGTHS_ORDER[cLen]] = (int) readBits(reader, 3); - } - - BinaryTreeNode codeLengthTree = buildTree(codeLengthValues); - - final int[] auxBuffer = new int[literals.length + distances.length]; - - int value = -1; - int length = 0; - int off = 0; - while (off < auxBuffer.length) { - if (length > 0) { - auxBuffer[off++] = value; - length--; - } else { - int symbol = nextSymbol(reader, codeLengthTree); - if (symbol < 16) { - value = symbol; - auxBuffer[off++] = value; - } else if (symbol == 16) { - length = (int) (readBits(reader, 2) + 3); - } else if (symbol == 17) { - value = 0; - length = (int) (readBits(reader, 3) + 3); - } else if (symbol == 18) { - value = 0; - length = (int) (readBits(reader, 7) + 11); - } - } - } - - System.arraycopy(auxBuffer, 0, literals, 0, literals.length); - System.arraycopy(auxBuffer, literals.length, distances, 0, distances.length); - } - - private static class BinaryTreeNode { - private final int bits; - int literal = -1; - BinaryTreeNode leftNode; - BinaryTreeNode rightNode; - - private BinaryTreeNode(int bits) { - this.bits = bits; - } - - void leaf(int symbol) { - literal = symbol; - leftNode = null; - rightNode = null; - } - - BinaryTreeNode left() { - if (leftNode == null && literal == -1) { - leftNode = new BinaryTreeNode(bits + 1); - } - return leftNode; - } - - BinaryTreeNode right() { - if (rightNode == null && literal == -1) { - rightNode = new BinaryTreeNode(bits + 1); - } - return rightNode; - } - } - - private static BinaryTreeNode buildTree(int[] litTable) { - int[] literalCodes = getCodes(litTable); - - BinaryTreeNode root = new BinaryTreeNode(0); - - for (int i = 0; i < litTable.length; i++) { - int len = litTable[i]; - if (len != 0) { - BinaryTreeNode node = root; - int lit = literalCodes[len - 1]; - for (int p = len - 1; p >= 0; p--) { - int bit = lit & (1 << p); - node = bit == 0 ? node.left() : node.right(); - } - node.leaf(i); - literalCodes[len - 1]++; - } - } - return root; - } - - private static int[] getCodes(int[] litTable) { - int max = 0; - int[] blCount = new int[65]; - - for (int aLitTable : litTable) { - max = Math.max(max, aLitTable); - blCount[aLitTable]++; - } - blCount = Arrays.copyOf(blCount, max + 1); - - int code = 0; - int[] nextCode = new int[max + 1]; - for (int i = 0; i <= max; i++) { - code = (code + blCount[i]) << 1; - nextCode[i] = code; - } - - return nextCode; - } - - private static class DecodingMemory { - private final byte[] memory; - private final int mask; - private int wHead; - private boolean wrappedAround; - - private DecodingMemory() { - this(16); - } - - private DecodingMemory(int bits) { - memory = new byte[1 << bits]; - mask = memory.length - 1; - } - - byte add(byte b) { - memory[wHead] = b; - wHead = incCounter(wHead); - return b; - } - - void add(byte[] b, int off, int len) { - for (int i = off; i < off + len; i++) { - add(b[i]); - } - } - - void recordToBuffer(int distance, int length, byte[] buff) { - if (distance > memory.length) { - throw new IllegalStateException("Illegal distance parameter: " + distance); - } - int start = (wHead - distance) & mask; - if (!wrappedAround && start >= wHead) { - throw new IllegalStateException("Attempt to read beyond memory: dist=" + distance); - } - for (int i = 0, pos = start; i < length; i++, pos = incCounter(pos)) { - buff[i] = add(memory[pos]); - } - } - - private int incCounter(int counter) { - final int newCounter = (counter + 1) & mask; - if (!wrappedAround && newCounter < counter) { - wrappedAround = true; - } - return newCounter; - } - } - - private long readBits(int numBits) throws IOException { - return readBits(reader, numBits); - } - - private static long readBits(BitInputStream reader, int numBits) throws IOException { - long r = reader.readBits(numBits); - if (r == -1) { - throw new EOFException("Truncated Deflate64 Stream"); - } - return r; - } -} diff --git a/src/org/apache/commons/compress/compressors/deflate64/HuffmanState.java b/src/org/apache/commons/compress/compressors/deflate64/HuffmanState.java deleted file mode 100644 index b34bb7ed92f..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate64/HuffmanState.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.compressors.deflate64; - -enum HuffmanState { - INITIAL, - STORED, - DYNAMIC_CODES, - FIXED_CODES -} diff --git a/src/org/apache/commons/compress/compressors/deflate64/package.html b/src/org/apache/commons/compress/compressors/deflate64/package.html deleted file mode 100644 index 4a0cdd0ae9e..00000000000 --- a/src/org/apache/commons/compress/compressors/deflate64/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - -

Provides a stream that allows decompressing streams using the - DEFLATE64(tm) algorithm. DEFLATE64 is a trademark of PKWARE, - Inc.

- - diff --git a/src/org/apache/commons/compress/compressors/gzip/GzipCompressorInputStream.java b/src/org/apache/commons/compress/compressors/gzip/GzipCompressorInputStream.java deleted file mode 100644 index 9e05f8bcbdb..00000000000 --- a/src/org/apache/commons/compress/compressors/gzip/GzipCompressorInputStream.java +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.gzip; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.EOFException; -import java.io.InputStream; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.BufferedInputStream; -import java.util.zip.DataFormatException; -import java.util.zip.Deflater; -import java.util.zip.Inflater; -import java.util.zip.CRC32; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.ByteUtils; -import org.apache.commons.compress.utils.CharsetNames; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * Input stream that decompresses .gz files. - * - *

This supports decompressing concatenated .gz files which is important - * when decompressing standalone .gz files.

- * - *

- * {@link java.util.zip.GZIPInputStream} doesn't decompress concatenated .gz - * files: it stops after the first member and silently ignores the rest. - * It doesn't leave the read position to point to the beginning of the next - * member, which makes it difficult workaround the lack of concatenation - * support. - *

- * - *

- * Instead of using GZIPInputStream, this class has its own .gz - * container format decoder. The actual decompression is done with - * {@link java.util.zip.Inflater}. - *

- * - *

If you use the constructor {@code GzipCompressorInputStream(in)} - * or {@code GzipCompressorInputStream(in, false)} with some {@code - * InputStream} {@code in} then {@link #read} will return -1 as soon - * as the first internal member has been read completely. The stream - * {@code in} will be positioned at the start of the second gzip - * member if there is one.

- * - *

If you use the constructor {@code GzipCompressorInputStream(in, - * true)} with some {@code InputStream} {@code in} then {@link #read} - * will return -1 once the stream {@code in} has been exhausted. The - * data read from a stream constructed this way will consist of the - * concatenated data of all gzip members contained inside {@code - * in}.

- * - * @see "https://tools.ietf.org/html/rfc1952" - */ -public class GzipCompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - // Header flags - // private static final int FTEXT = 0x01; // Uninteresting for us - private static final int FHCRC = 0x02; - private static final int FEXTRA = 0x04; - private static final int FNAME = 0x08; - private static final int FCOMMENT = 0x10; - private static final int FRESERVED = 0xE0; - - private final CountingInputStream countingStream; - - // Compressed input stream, possibly wrapped in a - // BufferedInputStream, always wrapped in countingStream above - private final InputStream in; - - // True if decompressing multi member streams. - private final boolean decompressConcatenated; - - // Buffer to hold the input data - private final byte[] buf = new byte[8192]; - - // Amount of data in buf. - private int bufUsed; - - // Decompressor - private Inflater inf = new Inflater(true); - - // CRC32 from uncompressed data - private final CRC32 crc = new CRC32(); - - // True once everything has been decompressed - private boolean endReached = false; - - // used in no-arg read method - private final byte[] oneByte = new byte[1]; - - private final GzipParameters parameters = new GzipParameters(); - - /** - * Constructs a new input stream that decompresses gzip-compressed data - * from the specified input stream. - *

- * This is equivalent to - * GzipCompressorInputStream(inputStream, false) and thus - * will not decompress concatenated .gz files. - * - * @param inputStream the InputStream from which this object should - * be created of - * - * @throws IOException if the stream could not be created - */ - public GzipCompressorInputStream(final InputStream inputStream) - throws IOException { - this(inputStream, false); - } - - /** - * Constructs a new input stream that decompresses gzip-compressed data - * from the specified input stream. - *

- * If decompressConcatenated is {@code false}: - * This decompressor might read more input than it will actually use. - * If inputStream supports mark and - * reset, then the input position will be adjusted - * so that it is right after the last byte of the compressed stream. - * If mark isn't supported, the input position will be - * undefined. - * - * @param inputStream the InputStream from which this object should - * be created of - * @param decompressConcatenated - * if true, decompress until the end of the input; - * if false, stop after the first .gz member - * - * @throws IOException if the stream could not be created - */ - public GzipCompressorInputStream(final InputStream inputStream, - final boolean decompressConcatenated) - throws IOException { - countingStream = new CountingInputStream(inputStream); - // Mark support is strictly needed for concatenated files only, - // but it's simpler if it is always available. - if (countingStream.markSupported()) { - in = countingStream; - } else { - in = new BufferedInputStream(countingStream); - } - - this.decompressConcatenated = decompressConcatenated; - init(true); - } - - /** - * Provides the stream's meta data - may change with each stream - * when decompressing concatenated streams. - * @return the stream's meta data - * @since 1.8 - */ - public GzipParameters getMetaData() { - return parameters; - } - - private boolean init(final boolean isFirstMember) throws IOException { - assert isFirstMember || decompressConcatenated; - - // Check the magic bytes without a possibility of EOFException. - final int magic0 = in.read(); - final int magic1 = in.read(); - - // If end of input was reached after decompressing at least - // one .gz member, we have reached the end of the file successfully. - if (magic0 == -1 && !isFirstMember) { - return false; - } - - if (magic0 != 31 || magic1 != 139) { - throw new IOException(isFirstMember - ? "Input is not in the .gz format" - : "Garbage after a valid .gz stream"); - } - - // Parsing the rest of the header may throw EOFException. - final DataInput inData = new DataInputStream(in); - final int method = inData.readUnsignedByte(); - if (method != Deflater.DEFLATED) { - throw new IOException("Unsupported compression method " - + method + " in the .gz header"); - } - - final int flg = inData.readUnsignedByte(); - if ((flg & FRESERVED) != 0) { - throw new IOException( - "Reserved flags are set in the .gz header"); - } - - parameters.setModificationTime(ByteUtils.fromLittleEndian(inData, 4) * 1000); - switch (inData.readUnsignedByte()) { // extra flags - case 2: - parameters.setCompressionLevel(Deflater.BEST_COMPRESSION); - break; - case 4: - parameters.setCompressionLevel(Deflater.BEST_SPEED); - break; - default: - // ignored for now - break; - } - parameters.setOperatingSystem(inData.readUnsignedByte()); - - // Extra field, ignored - if ((flg & FEXTRA) != 0) { - int xlen = inData.readUnsignedByte(); - xlen |= inData.readUnsignedByte() << 8; - - // This isn't as efficient as calling in.skip would be, - // but it's lazier to handle unexpected end of input this way. - // Most files don't have an extra field anyway. - while (xlen-- > 0) { - inData.readUnsignedByte(); - } - } - - // Original file name - if ((flg & FNAME) != 0) { - parameters.setFilename(new String(readToNull(inData), - CharsetNames.ISO_8859_1)); - } - - // Comment - if ((flg & FCOMMENT) != 0) { - parameters.setComment(new String(readToNull(inData), - CharsetNames.ISO_8859_1)); - } - - // Header "CRC16" which is actually a truncated CRC32 (which isn't - // as good as real CRC16). I don't know if any encoder implementation - // sets this, so it's not worth trying to verify it. GNU gzip 1.4 - // doesn't support this field, but zlib seems to be able to at least - // skip over it. - if ((flg & FHCRC) != 0) { - inData.readShort(); - } - - // Reset - inf.reset(); - crc.reset(); - - return true; - } - - private static byte[] readToNull(final DataInput inData) throws IOException { - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - int b = 0; - while ((b = inData.readUnsignedByte()) != 0x00) { // NOPMD - bos.write(b); - } - return bos.toByteArray(); - } - - @Override - public int read() throws IOException { - return read(oneByte, 0, 1) == -1 ? -1 : oneByte[0] & 0xFF; - } - - /** - * {@inheritDoc} - * - * @since 1.1 - */ - @Override - public int read(final byte[] b, int off, int len) throws IOException { - if (endReached) { - return -1; - } - - int size = 0; - - while (len > 0) { - if (inf.needsInput()) { - // Remember the current position because we may need to - // rewind after reading too much input. - in.mark(buf.length); - - bufUsed = in.read(buf); - if (bufUsed == -1) { - throw new EOFException(); - } - - inf.setInput(buf, 0, bufUsed); - } - - int ret; - try { - ret = inf.inflate(b, off, len); - } catch (final DataFormatException e) { - throw new IOException("Gzip-compressed data is corrupt"); - } - - crc.update(b, off, ret); - off += ret; - len -= ret; - size += ret; - count(ret); - - if (inf.finished()) { - // We may have read too many bytes. Rewind the read - // position to match the actual amount used. - // - // NOTE: The "if" is there just in case. Since we used - // in.mark earlier, it should always skip enough. - in.reset(); - - final int skipAmount = bufUsed - inf.getRemaining(); - if (IOUtils.skip(in, skipAmount) != skipAmount) { - throw new IOException(); - } - - bufUsed = 0; - - final DataInput inData = new DataInputStream(in); - - // CRC32 - final long crcStored = ByteUtils.fromLittleEndian(inData, 4); - - if (crcStored != crc.getValue()) { - throw new IOException("Gzip-compressed data is corrupt " - + "(CRC32 error)"); - } - - // Uncompressed size modulo 2^32 (ISIZE in the spec) - final long isize = ByteUtils.fromLittleEndian(inData, 4); - - if (isize != (inf.getBytesWritten() & 0xffffffffL)) { - throw new IOException("Gzip-compressed data is corrupt" - + "(uncompressed size mismatch)"); - } - - // See if this is the end of the file. - if (!decompressConcatenated || !init(false)) { - inf.end(); - inf = null; - endReached = true; - return size == 0 ? -1 : size; - } - } - } - - return size; - } - - /** - * Checks if the signature matches what is expected for a .gz file. - * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true if this is a .gz stream, false otherwise - * - * @since 1.1 - */ - public static boolean matches(final byte[] signature, final int length) { - return length >= 2 && signature[0] == 31 && signature[1] == -117; - } - - /** - * Closes the input stream (unless it is System.in). - * - * @since 1.2 - */ - @Override - public void close() throws IOException { - if (inf != null) { - inf.end(); - inf = null; - } - - if (this.in != System.in) { - this.in.close(); - } - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return countingStream.getBytesRead(); - } -} diff --git a/src/org/apache/commons/compress/compressors/gzip/GzipCompressorOutputStream.java b/src/org/apache/commons/compress/compressors/gzip/GzipCompressorOutputStream.java deleted file mode 100644 index d3f40124df1..00000000000 --- a/src/org/apache/commons/compress/compressors/gzip/GzipCompressorOutputStream.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.gzip; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.zip.CRC32; -import java.util.zip.Deflater; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; -import org.apache.commons.compress.utils.CharsetNames; - -/** - * Compressed output stream using the gzip format. This implementation improves - * over the standard {@link GZIPOutputStream} class by allowing - * the configuration of the compression level and the header metadata (filename, - * comment, modification time, operating system and extra flags). - * - * @see GZIP File Format Specification - */ -public class GzipCompressorOutputStream extends CompressorOutputStream { - - /** Header flag indicating a file name follows the header */ - private static final int FNAME = 1 << 3; - - /** Header flag indicating a comment follows the header */ - private static final int FCOMMENT = 1 << 4; - - /** The underlying stream */ - private final OutputStream out; - - /** Deflater used to compress the data */ - private final Deflater deflater; - - /** The buffer receiving the compressed data from the deflater */ - private final byte[] deflateBuffer = new byte[512]; - - /** Indicates if the stream has been closed */ - private boolean closed; - - /** The checksum of the uncompressed data */ - private final CRC32 crc = new CRC32(); - - /** - * Creates a gzip compressed output stream with the default parameters. - * @param out the stream to compress to - * @throws IOException if writing fails - */ - public GzipCompressorOutputStream(final OutputStream out) throws IOException { - this(out, new GzipParameters()); - } - - /** - * Creates a gzip compressed output stream with the specified parameters. - * @param out the stream to compress to - * @param parameters the parameters to use - * @throws IOException if writing fails - * - * @since 1.7 - */ - public GzipCompressorOutputStream(final OutputStream out, final GzipParameters parameters) throws IOException { - this.out = out; - this.deflater = new Deflater(parameters.getCompressionLevel(), true); - - writeHeader(parameters); - } - - private void writeHeader(final GzipParameters parameters) throws IOException { - final String filename = parameters.getFilename(); - final String comment = parameters.getComment(); - - final ByteBuffer buffer = ByteBuffer.allocate(10); - buffer.order(ByteOrder.LITTLE_ENDIAN); - buffer.putShort((short) GZIPInputStream.GZIP_MAGIC); - buffer.put((byte) Deflater.DEFLATED); // compression method (8: deflate) - buffer.put((byte) ((filename != null ? FNAME : 0) | (comment != null ? FCOMMENT : 0))); // flags - buffer.putInt((int) (parameters.getModificationTime() / 1000)); - - // extra flags - final int compressionLevel = parameters.getCompressionLevel(); - if (compressionLevel == Deflater.BEST_COMPRESSION) { - buffer.put((byte) 2); - } else if (compressionLevel == Deflater.BEST_SPEED) { - buffer.put((byte) 4); - } else { - buffer.put((byte) 0); - } - - buffer.put((byte) parameters.getOperatingSystem()); - - out.write(buffer.array()); - - if (filename != null) { - out.write(filename.getBytes(CharsetNames.ISO_8859_1)); - out.write(0); - } - - if (comment != null) { - out.write(comment.getBytes(CharsetNames.ISO_8859_1)); - out.write(0); - } - } - - private void writeTrailer() throws IOException { - final ByteBuffer buffer = ByteBuffer.allocate(8); - buffer.order(ByteOrder.LITTLE_ENDIAN); - buffer.putInt((int) crc.getValue()); - buffer.putInt(deflater.getTotalIn()); - - out.write(buffer.array()); - } - - @Override - public void write(final int b) throws IOException { - write(new byte[]{(byte) (b & 0xff)}, 0, 1); - } - - /** - * {@inheritDoc} - * - * @since 1.1 - */ - @Override - public void write(final byte[] buffer) throws IOException { - write(buffer, 0, buffer.length); - } - - /** - * {@inheritDoc} - * - * @since 1.1 - */ - @Override - public void write(final byte[] buffer, final int offset, final int length) throws IOException { - if (deflater.finished()) { - throw new IOException("Cannot write more data, the end of the compressed data stream has been reached"); - - } else if (length > 0) { - deflater.setInput(buffer, offset, length); - - while (!deflater.needsInput()) { - deflate(); - } - - crc.update(buffer, offset, length); - } - } - - private void deflate() throws IOException { - final int length = deflater.deflate(deflateBuffer, 0, deflateBuffer.length); - if (length > 0) { - out.write(deflateBuffer, 0, length); - } - } - - /** - * Finishes writing compressed data to the underlying stream without closing it. - * - * @since 1.7 - * @throws IOException on error - */ - public void finish() throws IOException { - if (!deflater.finished()) { - deflater.finish(); - - while (!deflater.finished()) { - deflate(); - } - - writeTrailer(); - } - } - - /** - * {@inheritDoc} - * - * @since 1.7 - */ - @Override - public void flush() throws IOException { - out.flush(); - } - - @Override - public void close() throws IOException { - if (!closed) { - finish(); - deflater.end(); - out.close(); - closed = true; - } - } - -} diff --git a/src/org/apache/commons/compress/compressors/gzip/GzipParameters.java b/src/org/apache/commons/compress/compressors/gzip/GzipParameters.java deleted file mode 100644 index 3887a686eab..00000000000 --- a/src/org/apache/commons/compress/compressors/gzip/GzipParameters.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.gzip; - -import java.util.zip.Deflater; - -/** - * Parameters for the GZIP compressor. - * - * @since 1.7 - */ -public class GzipParameters { - - private int compressionLevel = Deflater.DEFAULT_COMPRESSION; - private long modificationTime; - private String filename; - private String comment; - private int operatingSystem = 255; // Unknown OS by default - - public int getCompressionLevel() { - return compressionLevel; - } - - /** - * Sets the compression level. - * - * @param compressionLevel the compression level (between 0 and 9) - * @see Deflater#NO_COMPRESSION - * @see Deflater#BEST_SPEED - * @see Deflater#DEFAULT_COMPRESSION - * @see Deflater#BEST_COMPRESSION - */ - public void setCompressionLevel(final int compressionLevel) { - if (compressionLevel < -1 || compressionLevel > 9) { - throw new IllegalArgumentException("Invalid gzip compression level: " + compressionLevel); - } - this.compressionLevel = compressionLevel; - } - - public long getModificationTime() { - return modificationTime; - } - - /** - * Sets the modification time of the compressed file. - * - * @param modificationTime the modification time, in milliseconds - */ - public void setModificationTime(final long modificationTime) { - this.modificationTime = modificationTime; - } - - public String getFilename() { - return filename; - } - - /** - * Sets the name of the compressed file. - * - * @param filename the name of the file without the directory path - */ - public void setFilename(final String filename) { - this.filename = filename; - } - - public String getComment() { - return comment; - } - - public void setComment(final String comment) { - this.comment = comment; - } - - public int getOperatingSystem() { - return operatingSystem; - } - - /** - * Sets the operating system on which the compression took place. - * The defined values are: - *

    - *
  • 0: FAT filesystem (MS-DOS, OS/2, NT/Win32)
  • - *
  • 1: Amiga
  • - *
  • 2: VMS (or OpenVMS)
  • - *
  • 3: Unix
  • - *
  • 4: VM/CMS
  • - *
  • 5: Atari TOS
  • - *
  • 6: HPFS filesystem (OS/2, NT)
  • - *
  • 7: Macintosh
  • - *
  • 8: Z-System
  • - *
  • 9: CP/M
  • - *
  • 10: TOPS-20
  • - *
  • 11: NTFS filesystem (NT)
  • - *
  • 12: QDOS
  • - *
  • 13: Acorn RISCOS
  • - *
  • 255: Unknown
  • - *
- * - * @param operatingSystem the code of the operating system - */ - public void setOperatingSystem(final int operatingSystem) { - this.operatingSystem = operatingSystem; - } -} diff --git a/src/org/apache/commons/compress/compressors/gzip/GzipUtils.java b/src/org/apache/commons/compress/compressors/gzip/GzipUtils.java deleted file mode 100644 index 0edf655717a..00000000000 --- a/src/org/apache/commons/compress/compressors/gzip/GzipUtils.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.gzip; - -import java.util.LinkedHashMap; -import java.util.Map; -import org.apache.commons.compress.compressors.FileNameUtil; - -/** - * Utility code for the gzip compression format. - * @ThreadSafe - */ -public class GzipUtils { - - private static final FileNameUtil fileNameUtil; - - static { - // using LinkedHashMap so .tgz is preferred over .taz as - // compressed extension of .tar as FileNameUtil will use the - // first one found - final Map uncompressSuffix = - new LinkedHashMap<>(); - uncompressSuffix.put(".tgz", ".tar"); - uncompressSuffix.put(".taz", ".tar"); - uncompressSuffix.put(".svgz", ".svg"); - uncompressSuffix.put(".cpgz", ".cpio"); - uncompressSuffix.put(".wmz", ".wmf"); - uncompressSuffix.put(".emz", ".emf"); - uncompressSuffix.put(".gz", ""); - uncompressSuffix.put(".z", ""); - uncompressSuffix.put("-gz", ""); - uncompressSuffix.put("-z", ""); - uncompressSuffix.put("_z", ""); - fileNameUtil = new FileNameUtil(uncompressSuffix, ".gz"); - } - - /** Private constructor to prevent instantiation of this utility class. */ - private GzipUtils() { - } - - /** - * Detects common gzip suffixes in the given filename. - * - * @param filename name of a file - * @return {@code true} if the filename has a common gzip suffix, - * {@code false} otherwise - */ - public static boolean isCompressedFilename(final String filename) { - return fileNameUtil.isCompressedFilename(filename); - } - - /** - * Maps the given name of a gzip-compressed file to the name that the - * file should have after uncompression. Commonly used file type specific - * suffixes like ".tgz" or ".svgz" are automatically detected and - * correctly mapped. For example the name "package.tgz" is mapped to - * "package.tar". And any filenames with the generic ".gz" suffix - * (or any other generic gzip suffix) is mapped to a name without that - * suffix. If no gzip suffix is detected, then the filename is returned - * unmapped. - * - * @param filename name of a file - * @return name of the corresponding uncompressed file - */ - public static String getUncompressedFilename(final String filename) { - return fileNameUtil.getUncompressedFilename(filename); - } - - /** - * Maps the given filename to the name that the file should have after - * compression with gzip. Common file types with custom suffixes for - * compressed versions are automatically detected and correctly mapped. - * For example the name "package.tar" is mapped to "package.tgz". If no - * custom mapping is applicable, then the default ".gz" suffix is appended - * to the filename. - * - * @param filename name of a file - * @return name of the corresponding compressed file - */ - public static String getCompressedFilename(final String filename) { - return fileNameUtil.getCompressedFilename(filename); - } - -} diff --git a/src/org/apache/commons/compress/compressors/gzip/package.html b/src/org/apache/commons/compress/compressors/gzip/package.html deleted file mode 100644 index e18b50f2fa0..00000000000 --- a/src/org/apache/commons/compress/compressors/gzip/package.html +++ /dev/null @@ -1,29 +0,0 @@ - - - -

Provides stream classes for compressing and decompressing - streams using the GZip algorithm.

- -

The classes in this package are wrappers around {@link - java.util.zip.GZIPInputStream java.util.zip.GZIPInputStream} and - {@link java.util.zip.GZIPOutputStream - java.util.zip.GZIPOutputStream}.

- - diff --git a/src/org/apache/commons/compress/compressors/lz4/BlockLZ4CompressorInputStream.java b/src/org/apache/commons/compress/compressors/lz4/BlockLZ4CompressorInputStream.java deleted file mode 100644 index a52dc6015cc..00000000000 --- a/src/org/apache/commons/compress/compressors/lz4/BlockLZ4CompressorInputStream.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz4; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.compressors.lz77support.AbstractLZ77CompressorInputStream; -import org.apache.commons.compress.utils.ByteUtils; - -/** - * CompressorInputStream for the LZ4 block format. - * - * @see LZ4 Block Format Description - * @since 1.14 - * @NotThreadSafe - */ -public class BlockLZ4CompressorInputStream extends AbstractLZ77CompressorInputStream { - - static final int WINDOW_SIZE = 1 << 16; - static final int SIZE_BITS = 4; - static final int BACK_REFERENCE_SIZE_MASK = (1 << SIZE_BITS) - 1; - static final int LITERAL_SIZE_MASK = BACK_REFERENCE_SIZE_MASK << SIZE_BITS; - - /** Back-Reference-size part of the block starting byte. */ - private int nextBackReferenceSize; - - /** Current state of the stream */ - private State state = State.NO_BLOCK; - - /** - * Creates a new LZ4 input stream. - * - * @param is - * An InputStream to read compressed data from - * - * @throws IOException if reading fails - */ - public BlockLZ4CompressorInputStream(final InputStream is) throws IOException { - super(is, WINDOW_SIZE); - } - - /** - * {@inheritDoc} - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - switch (state) { - case EOF: - return -1; - case NO_BLOCK: // NOSONAR - fallthrough intended - readSizes(); - /*FALLTHROUGH*/ - case IN_LITERAL: - int litLen = readLiteral(b, off, len); - if (!hasMoreDataInBlock()) { - state = State.LOOKING_FOR_BACK_REFERENCE; - } - return litLen > 0 ? litLen : read(b, off, len); - case LOOKING_FOR_BACK_REFERENCE: // NOSONAR - fallthrough intended - if (!initializeBackReference()) { - state = State.EOF; - return -1; - } - /*FALLTHROUGH*/ - case IN_BACK_REFERENCE: - int backReferenceLen = readBackReference(b, off, len); - if (!hasMoreDataInBlock()) { - state = State.NO_BLOCK; - } - return backReferenceLen > 0 ? backReferenceLen : read(b, off, len); - default: - throw new IOException("Unknown stream state " + state); - } - } - - private void readSizes() throws IOException { - int nextBlock = readOneByte(); - if (nextBlock == -1) { - throw new IOException("Premature end of stream while looking for next block"); - } - nextBackReferenceSize = nextBlock & BACK_REFERENCE_SIZE_MASK; - long literalSizePart = (nextBlock & LITERAL_SIZE_MASK) >> SIZE_BITS; - if (literalSizePart == BACK_REFERENCE_SIZE_MASK) { - literalSizePart += readSizeBytes(); - } - startLiteral(literalSizePart); - state = State.IN_LITERAL; - } - - private long readSizeBytes() throws IOException { - long accum = 0; - int nextByte; - do { - nextByte = readOneByte(); - if (nextByte == -1) { - throw new IOException("Premature end of stream while parsing length"); - } - accum += nextByte; - } while (nextByte == 255); - return accum; - } - - /** - * @return false if there is no more back-reference - this means this is the - * last block of the stream. - */ - private boolean initializeBackReference() throws IOException { - int backReferenceOffset = 0; - try { - backReferenceOffset = (int) ByteUtils.fromLittleEndian(supplier, 2); - } catch (IOException ex) { - if (nextBackReferenceSize == 0) { // the last block has no back-reference - return false; - } - throw ex; - } - long backReferenceSize = nextBackReferenceSize; - if (nextBackReferenceSize == BACK_REFERENCE_SIZE_MASK) { - backReferenceSize += readSizeBytes(); - } - // minimal match length 4 is encoded as 0 - startBackReference(backReferenceOffset, backReferenceSize + 4); - state = State.IN_BACK_REFERENCE; - return true; - } - - private enum State { - NO_BLOCK, IN_LITERAL, LOOKING_FOR_BACK_REFERENCE, IN_BACK_REFERENCE, EOF - } -} diff --git a/src/org/apache/commons/compress/compressors/lz4/BlockLZ4CompressorOutputStream.java b/src/org/apache/commons/compress/compressors/lz4/BlockLZ4CompressorOutputStream.java deleted file mode 100644 index 2cce3a1ea6c..00000000000 --- a/src/org/apache/commons/compress/compressors/lz4/BlockLZ4CompressorOutputStream.java +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz4; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; - -import org.apache.commons.compress.compressors.CompressorOutputStream; -import org.apache.commons.compress.compressors.lz77support.LZ77Compressor; -import org.apache.commons.compress.compressors.lz77support.Parameters; -import org.apache.commons.compress.utils.ByteUtils; - -/** - * CompressorOutputStream for the LZ4 block format. - * - * @see LZ4 Block Format Description - * @since 1.14 - * @NotThreadSafe - */ -public class BlockLZ4CompressorOutputStream extends CompressorOutputStream { - - private static final int MIN_BACK_REFERENCE_LENGTH = 4; - private static final int MIN_OFFSET_OF_LAST_BACK_REFERENCE = 12; - - /* - - The LZ4 block format has a few properties that make it less - straight-forward than one would hope: - - * literal blocks and back-references must come in pairs (except - for the very last literal block), so consecutive literal - blocks created by the compressor must be merged into a single - block. - - * the start of a literal/back-reference pair contains the length - of the back-reference (at least some part of it) so we can't - start writing the literal before we know how long the next - back-reference is going to be. - - * there are special rules for the final blocks - - > There are specific parsing rules to respect in order to remain - > compatible with assumptions made by the decoder : - > - > 1. The last 5 bytes are always literals - > - > 2. The last match must start at least 12 bytes before end of - > block. Consequently, a block with less than 13 bytes cannot be - > compressed. - - which means any back-reference may need to get rewritten as a - literal block unless we know the next block is at least of - length 5 and the sum of this block's length and offset and the - next block's length is at least twelve. - - */ - - private final LZ77Compressor compressor; - private final OutputStream os; - - // used in one-arg write method - private final byte[] oneByte = new byte[1]; - - private boolean finished = false; - - private Deque pairs = new LinkedList<>(); - // keeps track of the last window-size bytes (64k) in order to be - // able to expand back-references when needed - private Deque expandedBlocks = new LinkedList<>(); - - /** - * Creates a new LZ4 output stream. - * - * @param os - * An OutputStream to read compressed data from - * - * @throws IOException if reading fails - */ - public BlockLZ4CompressorOutputStream(final OutputStream os) throws IOException { - this(os, createParameterBuilder().build()); - } - - /** - * Creates a new LZ4 output stream. - * - * @param os - * An OutputStream to read compressed data from - * @param params - * The parameters to use for LZ77 compression. - * - * @throws IOException if reading fails - */ - public BlockLZ4CompressorOutputStream(final OutputStream os, Parameters params) throws IOException { - this.os = os; - compressor = new LZ77Compressor(params, - new LZ77Compressor.Callback() { - @Override - public void accept(LZ77Compressor.Block block) throws IOException { - switch (block.getType()) { - case LITERAL: - addLiteralBlock((LZ77Compressor.LiteralBlock) block); - break; - case BACK_REFERENCE: - addBackReference((LZ77Compressor.BackReference) block); - break; - case EOD: - writeFinalLiteralBlock(); - break; - } - } - }); - } - - @Override - public void write(int b) throws IOException { - oneByte[0] = (byte) (b & 0xff); - write(oneByte); - } - - @Override - public void write(byte[] data, int off, int len) throws IOException { - compressor.compress(data, off, len); - } - - @Override - public void close() throws IOException { - finish(); - os.close(); - } - - /** - * Compresses all remaining data and writes it to the stream, - * doesn't close the underlying stream. - * @throws IOException if an error occurs - */ - public void finish() throws IOException { - if (!finished) { - compressor.finish(); - finished = true; - } - } - - /** - * Adds some initial data to fill the window with. - * - * @param data the data to fill the window with. - * @param off offset of real data into the array - * @param len amount of data - * @throws IllegalStateException if the stream has already started to write data - * @see LZ77Compressor#prefill - */ - public void prefill(byte[] data, int off, int len) { - if (len > 0) { - byte[] b = Arrays.copyOfRange(data, off, off + len); - compressor.prefill(b); - recordLiteral(b); - } - } - - private void addLiteralBlock(LZ77Compressor.LiteralBlock block) throws IOException { - Pair last = writeBlocksAndReturnUnfinishedPair(block.getLength()); - recordLiteral(last.addLiteral(block)); - clearUnusedBlocksAndPairs(); - } - - private void addBackReference(LZ77Compressor.BackReference block) throws IOException { - Pair last = writeBlocksAndReturnUnfinishedPair(block.getLength()); - last.setBackReference(block); - recordBackReference(block); - clearUnusedBlocksAndPairs(); - } - - private Pair writeBlocksAndReturnUnfinishedPair(int length) throws IOException { - writeWritablePairs(length); - Pair last = pairs.peekLast(); - if (last == null || last.hasBackReference()) { - last = new Pair(); - pairs.addLast(last); - } - return last; - } - - private void recordLiteral(byte[] b) { - expandedBlocks.addFirst(b); - } - - private void clearUnusedBlocksAndPairs() { - clearUnusedBlocks(); - clearUnusedPairs(); - } - - private void clearUnusedBlocks() { - int blockLengths = 0; - int blocksToKeep = 0; - for (byte[] b : expandedBlocks) { - blocksToKeep++; - blockLengths += b.length; - if (blockLengths >= BlockLZ4CompressorInputStream.WINDOW_SIZE) { - break; - } - } - final int size = expandedBlocks.size(); - for (int i = blocksToKeep; i < size; i++) { - expandedBlocks.removeLast(); - } - } - - private void recordBackReference(LZ77Compressor.BackReference block) { - expandedBlocks.addFirst(expand(block.getOffset(), block.getLength())); - } - - private byte[] expand(final int offset, final int length) { - byte[] expanded = new byte[length]; - if (offset == 1) { // surprisingly common special case - byte[] block = expandedBlocks.peekFirst(); - byte b = block[block.length - 1]; - if (b != 0) { // the fresh array contains 0s anyway - Arrays.fill(expanded, b); - } - } else { - expandFromList(expanded, offset, length); - } - return expanded; - } - - private void expandFromList(final byte[] expanded, int offset, int length) { - int offsetRemaining = offset; - int lengthRemaining = length; - int writeOffset = 0; - while (lengthRemaining > 0) { - // find block that contains offsetRemaining - byte[] block = null; - int copyLen, copyOffset; - if (offsetRemaining > 0) { - int blockOffset = 0; - for (byte[] b : expandedBlocks) { - if (b.length + blockOffset >= offsetRemaining) { - block = b; - break; - } - blockOffset += b.length; - } - if (block == null) { - // should not be possible - throw new IllegalStateException("failed to find a block containing offset " + offset); - } - copyOffset = blockOffset + block.length - offsetRemaining; - copyLen = Math.min(lengthRemaining, block.length - copyOffset); - } else { - // offsetRemaining is negative or 0 and points into the expanded bytes - block = expanded; - copyOffset = -offsetRemaining; - copyLen = Math.min(lengthRemaining, writeOffset + offsetRemaining); - } - System.arraycopy(block, copyOffset, expanded, writeOffset, copyLen); - offsetRemaining -= copyLen; - lengthRemaining -= copyLen; - writeOffset += copyLen; - } - } - - private void clearUnusedPairs() { - int pairLengths = 0; - int pairsToKeep = 0; - for (Iterator it = pairs.descendingIterator(); it.hasNext(); ) { - Pair p = it.next(); - pairsToKeep++; - pairLengths += p.length(); - if (pairLengths >= BlockLZ4CompressorInputStream.WINDOW_SIZE) { - break; - } - } - final int size = pairs.size(); - for (int i = pairsToKeep; i < size; i++) { - Pair p = pairs.peekFirst(); - if (p.hasBeenWritten()) { - pairs.removeFirst(); - } else { - break; - } - } - } - - private void writeFinalLiteralBlock() throws IOException { - rewriteLastPairs(); - for (Pair p : pairs) { - if (!p.hasBeenWritten()) { - p.writeTo(os); - } - } - pairs.clear(); - } - - private void writeWritablePairs(int lengthOfBlocksAfterLastPair) throws IOException { - int unwrittenLength = lengthOfBlocksAfterLastPair; - for (Iterator it = pairs.descendingIterator(); it.hasNext(); ) { - Pair p = it.next(); - if (p.hasBeenWritten()) { - break; - } - unwrittenLength += p.length(); - } - for (Pair p : pairs) { - if (p.hasBeenWritten()) { - continue; - } - unwrittenLength -= p.length(); - if (p.canBeWritten(unwrittenLength)) { - p.writeTo(os); - } else { - break; - } - } - } - - private void rewriteLastPairs() { - LinkedList lastPairs = new LinkedList<>(); - LinkedList pairLength = new LinkedList<>(); - int offset = 0; - for (Iterator it = pairs.descendingIterator(); it.hasNext(); ) { - Pair p = it.next(); - if (p.hasBeenWritten()) { - break; - } - int len = p.length(); - pairLength.addFirst(len); - lastPairs.addFirst(p); - offset += len; - if (offset >= MIN_OFFSET_OF_LAST_BACK_REFERENCE) { - break; - } - } - for (Pair p : lastPairs) { - pairs.remove(p); - } - // lastPairs may contain between one and four Pairs: - // * the last pair may be a one byte literal - // * all other Pairs contain a back-reference which must be four bytes long at minimum - // we could merge them all into a single literal block but - // this may harm compression. For example compressing - // "bla.tar" from our tests yields a last block containing a - // back-reference of length > 2k and we'd end up with a last - // literal of that size rather than a 2k back-reference and a - // 12 byte literal at the end. - - // Instead we merge all but the first of lastPairs into a new - // literal-only Pair "replacement" and look at the - // back-reference in the first of lastPairs and see if we can - // split it. We can split it if it is longer than 16 - - // replacement.length (i.e. the minimal length of four is kept - // while making sure the last literal is at least twelve bytes - // long). If we can't split it, we expand the first of the pairs - // as well. - - // this is not optimal, we could get better compression - // results with more complex approaches as the last literal - // only needs to be five bytes long if the previous - // back-reference has an offset big enough - - final int lastPairsSize = lastPairs.size(); - int toExpand = 0; - for (int i = 1; i < lastPairsSize; i++) { - toExpand += pairLength.get(i); - } - Pair replacement = new Pair(); - if (toExpand > 0) { - replacement.prependLiteral(expand(toExpand, toExpand)); - } - Pair splitCandidate = lastPairs.get(0); - int stillNeeded = MIN_OFFSET_OF_LAST_BACK_REFERENCE - toExpand; - int brLen = splitCandidate.hasBackReference() ? splitCandidate.backReferenceLength() : 0; - if (splitCandidate.hasBackReference() && brLen >= MIN_BACK_REFERENCE_LENGTH + stillNeeded) { - replacement.prependLiteral(expand(toExpand + stillNeeded, stillNeeded)); - pairs.add(splitCandidate.splitWithNewBackReferenceLengthOf(brLen - stillNeeded)); - } else { - if (splitCandidate.hasBackReference()) { - replacement.prependLiteral(expand(toExpand + brLen, brLen)); - } - splitCandidate.prependTo(replacement); - } - pairs.add(replacement); - } - - /** - * Returns a builder correctly configured for the LZ4 algorithm. - * @return a builder correctly configured for the LZ4 algorithm - */ - public static Parameters.Builder createParameterBuilder() { - int maxLen = BlockLZ4CompressorInputStream.WINDOW_SIZE - 1; - return Parameters.builder(BlockLZ4CompressorInputStream.WINDOW_SIZE) - .withMinBackReferenceLength(MIN_BACK_REFERENCE_LENGTH) - .withMaxBackReferenceLength(maxLen) - .withMaxOffset(maxLen) - .withMaxLiteralLength(maxLen); - } - - final static class Pair { - private final Deque literals = new LinkedList<>(); - private int brOffset, brLength; - private boolean written; - - private void prependLiteral(byte[] data) { - literals.addFirst(data); - } - byte[] addLiteral(LZ77Compressor.LiteralBlock block) { - byte[] copy = Arrays.copyOfRange(block.getData(), block.getOffset(), - block.getOffset() + block.getLength()); - literals.add(copy); - return copy; - } - void setBackReference(LZ77Compressor.BackReference block) { - if (hasBackReference()) { - throw new IllegalStateException(); - } - brOffset = block.getOffset(); - brLength = block.getLength(); - } - boolean hasBackReference() { - return brOffset > 0; - } - boolean canBeWritten(int lengthOfBlocksAfterThisPair) { - return hasBackReference() - && lengthOfBlocksAfterThisPair >= MIN_OFFSET_OF_LAST_BACK_REFERENCE + MIN_BACK_REFERENCE_LENGTH; - } - int length() { - return literalLength() + brLength; - } - private boolean hasBeenWritten() { - return written; - } - void writeTo(OutputStream out) throws IOException { - int litLength = literalLength(); - out.write(lengths(litLength, brLength)); - if (litLength >= BlockLZ4CompressorInputStream.BACK_REFERENCE_SIZE_MASK) { - writeLength(litLength - BlockLZ4CompressorInputStream.BACK_REFERENCE_SIZE_MASK, out); - } - for (byte[] b : literals) { - out.write(b); - } - if (hasBackReference()) { - ByteUtils.toLittleEndian(out, brOffset, 2); - if (brLength - MIN_BACK_REFERENCE_LENGTH >= BlockLZ4CompressorInputStream.BACK_REFERENCE_SIZE_MASK) { - writeLength(brLength - MIN_BACK_REFERENCE_LENGTH - - BlockLZ4CompressorInputStream.BACK_REFERENCE_SIZE_MASK, out); - } - } - written = true; - } - private int literalLength() { - int length = 0; - for (byte[] b : literals) { - length += b.length; - } - return length; - } - private static int lengths(int litLength, int brLength) { - int l = litLength < 15 ? litLength : 15; - int br = brLength < 4 ? 0 : (brLength < 19 ? brLength - 4 : 15); - return (l << BlockLZ4CompressorInputStream.SIZE_BITS) | br; - } - private static void writeLength(int length, OutputStream out) throws IOException { - while (length >= 255) { - out.write(255); - length -= 255; - } - out.write(length); - } - private int backReferenceLength() { - return brLength; - } - private void prependTo(Pair other) { - Iterator listBackwards = literals.descendingIterator(); - while (listBackwards.hasNext()) { - other.prependLiteral(listBackwards.next()); - } - } - private Pair splitWithNewBackReferenceLengthOf(int newBackReferenceLength) { - Pair p = new Pair(); - p.literals.addAll(literals); - p.brOffset = brOffset; - p.brLength = newBackReferenceLength; - return p; - } - } -} diff --git a/src/org/apache/commons/compress/compressors/lz4/FramedLZ4CompressorInputStream.java b/src/org/apache/commons/compress/compressors/lz4/FramedLZ4CompressorInputStream.java deleted file mode 100644 index c4c4f492a96..00000000000 --- a/src/org/apache/commons/compress/compressors/lz4/FramedLZ4CompressorInputStream.java +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz4; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.BoundedInputStream; -import org.apache.commons.compress.utils.ByteUtils; -import org.apache.commons.compress.utils.ChecksumCalculatingInputStream; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * CompressorInputStream for the LZ4 frame format. - * - *

Based on the "spec" in the version "1.5.1 (31/03/2015)"

- * - * @see LZ4 Frame Format Description - * @since 1.14 - * @NotThreadSafe - */ -public class FramedLZ4CompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - // used by FramedLZ4CompressorOutputStream as well - static final byte[] LZ4_SIGNATURE = new byte[] { //NOSONAR - 4, 0x22, 0x4d, 0x18 - }; - private static final byte[] SKIPPABLE_FRAME_TRAILER = new byte[] { - 0x2a, 0x4d, 0x18 - }; - private static final byte SKIPPABLE_FRAME_PREFIX_BYTE_MASK = 0x50; - - static final int VERSION_MASK = 0xC0; - static final int SUPPORTED_VERSION = 0x40; - static final int BLOCK_INDEPENDENCE_MASK = 0x20; - static final int BLOCK_CHECKSUM_MASK = 0x10; - static final int CONTENT_SIZE_MASK = 0x08; - static final int CONTENT_CHECKSUM_MASK = 0x04; - static final int BLOCK_MAX_SIZE_MASK = 0x70; - static final int UNCOMPRESSED_FLAG_MASK = 0x80000000; - - // used in no-arg read method - private final byte[] oneByte = new byte[1]; - - private final ByteUtils.ByteSupplier supplier = new ByteUtils.ByteSupplier() { - @Override - public int getAsByte() throws IOException { - return readOneByte(); - } - }; - - private final CountingInputStream in; - private final boolean decompressConcatenated; - - private boolean expectBlockChecksum; - private boolean expectBlockDependency; - private boolean expectContentSize; - private boolean expectContentChecksum; - - private InputStream currentBlock; - private boolean endReached, inUncompressed; - - // used for frame header checksum and content checksum, if present - private final XXHash32 contentHash = new XXHash32(); - - // used for block checksum, if present - private final XXHash32 blockHash = new XXHash32(); - - // only created if the frame doesn't set the block independence flag - private byte[] blockDependencyBuffer; - - /** - * Creates a new input stream that decompresses streams compressed - * using the LZ4 frame format and stops after decompressing the - * first frame. - * @param in the InputStream from which to read the compressed data - * @throws IOException if reading fails - */ - public FramedLZ4CompressorInputStream(InputStream in) throws IOException { - this(in, false); - } - - /** - * Creates a new input stream that decompresses streams compressed - * using the LZ4 frame format. - * @param in the InputStream from which to read the compressed data - * @param decompressConcatenated if true, decompress until the end - * of the input; if false, stop after the first LZ4 frame - * and leave the input position to point to the next byte - * after the frame stream - * @throws IOException if reading fails - */ - public FramedLZ4CompressorInputStream(InputStream in, boolean decompressConcatenated) throws IOException { - this.in = new CountingInputStream(in); - this.decompressConcatenated = decompressConcatenated; - init(true); - } - - /** {@inheritDoc} */ - @Override - public int read() throws IOException { - return read(oneByte, 0, 1) == -1 ? -1 : oneByte[0] & 0xFF; - } - - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - if (currentBlock != null) { - currentBlock.close(); - currentBlock = null; - } - in.close(); - } - - /** {@inheritDoc} */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (endReached) { - return -1; - } - int r = readOnce(b, off, len); - if (r == -1) { - nextBlock(); - if (!endReached) { - r = readOnce(b, off, len); - } - } - if (r != -1) { - if (expectBlockDependency) { - appendToBlockDependencyBuffer(b, off, r); - } - if (expectContentChecksum) { - contentHash.update(b, off, r); - } - } - return r; - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return in.getBytesRead(); - } - - private void init(boolean firstFrame) throws IOException { - if (readSignature(firstFrame)) { - readFrameDescriptor(); - nextBlock(); - } - } - - private boolean readSignature(boolean firstFrame) throws IOException { - String garbageMessage = firstFrame ? "Not a LZ4 frame stream" : "LZ4 frame stream followed by garbage"; - final byte[] b = new byte[4]; - int read = IOUtils.readFully(in, b); - count(read); - if (0 == read && !firstFrame) { - // good LZ4 frame and nothing after it - endReached = true; - return false; - } - if (4 != read) { - throw new IOException(garbageMessage); - } - - read = skipSkippableFrame(b); - if (0 == read && !firstFrame) { - // good LZ4 frame with only some skippable frames after it - endReached = true; - return false; - } - if (4 != read || !matches(b, 4)) { - throw new IOException(garbageMessage); - } - return true; - } - - private void readFrameDescriptor() throws IOException { - int flags = readOneByte(); - if (flags == -1) { - throw new IOException("Premature end of stream while reading frame flags"); - } - contentHash.update(flags); - if ((flags & VERSION_MASK) != SUPPORTED_VERSION) { - throw new IOException("Unsupported version " + (flags >> 6)); - } - expectBlockDependency = (flags & BLOCK_INDEPENDENCE_MASK) == 0; - if (expectBlockDependency) { - if (blockDependencyBuffer == null) { - blockDependencyBuffer = new byte[BlockLZ4CompressorInputStream.WINDOW_SIZE]; - } - } else { - blockDependencyBuffer = null; - } - expectBlockChecksum = (flags & BLOCK_CHECKSUM_MASK) != 0; - expectContentSize = (flags & CONTENT_SIZE_MASK) != 0; - expectContentChecksum = (flags & CONTENT_CHECKSUM_MASK) != 0; - int bdByte = readOneByte(); - if (bdByte == -1) { // max size is irrelevant for this implementation - throw new IOException("Premature end of stream while reading frame BD byte"); - } - contentHash.update(bdByte); - if (expectContentSize) { // for now we don't care, contains the uncompressed size - byte[] contentSize = new byte[8]; - int skipped = IOUtils.readFully(in, contentSize); - count(skipped); - if (8 != skipped) { - throw new IOException("Premature end of stream while reading content size"); - } - contentHash.update(contentSize, 0, contentSize.length); - } - int headerHash = readOneByte(); - if (headerHash == -1) { // partial hash of header. - throw new IOException("Premature end of stream while reading frame header checksum"); - } - int expectedHash = (int) ((contentHash.getValue() >> 8) & 0xff); - contentHash.reset(); - if (headerHash != expectedHash) { - throw new IOException("frame header checksum mismatch."); - } - } - - private void nextBlock() throws IOException { - maybeFinishCurrentBlock(); - long len = ByteUtils.fromLittleEndian(supplier, 4); - boolean uncompressed = (len & UNCOMPRESSED_FLAG_MASK) != 0; - int realLen = (int) (len & (~UNCOMPRESSED_FLAG_MASK)); - if (realLen == 0) { - verifyContentChecksum(); - if (!decompressConcatenated) { - endReached = true; - } else { - init(false); - } - return; - } - InputStream capped = new BoundedInputStream(in, realLen); - if (expectBlockChecksum) { - capped = new ChecksumCalculatingInputStream(blockHash, capped); - } - if (uncompressed) { - inUncompressed = true; - currentBlock = capped; - } else { - inUncompressed = false; - BlockLZ4CompressorInputStream s = new BlockLZ4CompressorInputStream(capped); - if (expectBlockDependency) { - s.prefill(blockDependencyBuffer); - } - currentBlock = s; - } - } - - private void maybeFinishCurrentBlock() throws IOException { - if (currentBlock != null) { - currentBlock.close(); - currentBlock = null; - if (expectBlockChecksum) { - verifyChecksum(blockHash, "block"); - blockHash.reset(); - } - } - } - - private void verifyContentChecksum() throws IOException { - if (expectContentChecksum) { - verifyChecksum(contentHash, "content"); - } - contentHash.reset(); - } - - private void verifyChecksum(XXHash32 hash, String kind) throws IOException { - byte[] checksum = new byte[4]; - int read = IOUtils.readFully(in, checksum); - count(read); - if (4 != read) { - throw new IOException("Premature end of stream while reading " + kind + " checksum"); - } - long expectedHash = hash.getValue(); - if (expectedHash != ByteUtils.fromLittleEndian(checksum)) { - throw new IOException(kind + " checksum mismatch."); - } - } - - private int readOneByte() throws IOException { - final int b = in.read(); - if (b != -1) { - count(1); - return b & 0xFF; - } - return -1; - } - - private int readOnce(byte[] b, int off, int len) throws IOException { - if (inUncompressed) { - int cnt = currentBlock.read(b, off, len); - count(cnt); - return cnt; - } - BlockLZ4CompressorInputStream l = (BlockLZ4CompressorInputStream) currentBlock; - long before = l.getBytesRead(); - int cnt = currentBlock.read(b, off, len); - count(l.getBytesRead() - before); - return cnt; - } - - private static boolean isSkippableFrameSignature(byte[] b) { - if ((b[0] & SKIPPABLE_FRAME_PREFIX_BYTE_MASK) != SKIPPABLE_FRAME_PREFIX_BYTE_MASK) { - return false; - } - for (int i = 1; i < 4; i++) { - if (b[i] != SKIPPABLE_FRAME_TRAILER[i - 1]) { - return false; - } - } - return true; - } - - /** - * Skips over the contents of a skippable frame as well as - * skippable frames following it. - * - *

It then tries to read four more bytes which are supposed to - * hold an LZ4 signature and returns the number of bytes read - * while storing the bytes in the given array.

- */ - private int skipSkippableFrame(byte[] b) throws IOException { - int read = 4; - while (read == 4 && isSkippableFrameSignature(b)) { - long len = ByteUtils.fromLittleEndian(supplier, 4); - long skipped = IOUtils.skip(in, len); - count(skipped); - if (len != skipped) { - throw new IOException("Premature end of stream while skipping frame"); - } - read = IOUtils.readFully(in, b); - count(read); - } - return read; - } - - private void appendToBlockDependencyBuffer(final byte[] b, final int off, int len) { - len = Math.min(len, blockDependencyBuffer.length); - if (len > 0) { - int keep = blockDependencyBuffer.length - len; - if (keep > 0) { - // move last keep bytes towards the start of the buffer - System.arraycopy(blockDependencyBuffer, len, blockDependencyBuffer, 0, keep); - } - // append new data - System.arraycopy(b, off, blockDependencyBuffer, keep, len); - } - } - - /** - * Checks if the signature matches what is expected for a .lz4 file. - * - *

.lz4 files start with a four byte signature.

- * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true if this is a .sz stream, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - - if (length < LZ4_SIGNATURE.length) { - return false; - } - - byte[] shortenedSig = signature; - if (signature.length > LZ4_SIGNATURE.length) { - shortenedSig = new byte[LZ4_SIGNATURE.length]; - System.arraycopy(signature, 0, shortenedSig, 0, LZ4_SIGNATURE.length); - } - - return Arrays.equals(shortenedSig, LZ4_SIGNATURE); - } -} diff --git a/src/org/apache/commons/compress/compressors/lz4/FramedLZ4CompressorOutputStream.java b/src/org/apache/commons/compress/compressors/lz4/FramedLZ4CompressorOutputStream.java deleted file mode 100644 index 0b11eff234c..00000000000 --- a/src/org/apache/commons/compress/compressors/lz4/FramedLZ4CompressorOutputStream.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz4; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; -import org.apache.commons.compress.utils.ByteUtils; - -/** - * CompressorOutputStream for the LZ4 frame format. - * - *

Based on the "spec" in the version "1.5.1 (31/03/2015)"

- * - * @see LZ4 Frame Format Description - * @since 1.14 - * @NotThreadSafe - */ -public class FramedLZ4CompressorOutputStream extends CompressorOutputStream { - - private static final byte[] END_MARK = new byte[4]; - - // used in one-arg write method - private final byte[] oneByte = new byte[1]; - - private final byte[] blockData; - private final OutputStream out; - private final Parameters params; - private boolean finished = false; - private int currentIndex = 0; - - // used for frame header checksum and content checksum, if requested - private final XXHash32 contentHash = new XXHash32(); - // used for block checksum, if requested - private final XXHash32 blockHash; - - // only created if the config requires block dependency - private byte[] blockDependencyBuffer; - private int collectedBlockDependencyBytes; - - /** - * The block sizes supported by the format. - */ - public enum BlockSize { - /** Block size of 64K */ - K64(64 * 1024, 4), - /** Block size of 256K */ - K256(256 * 1024, 5), - /** Block size of 1M */ - M1(1024 * 1024, 6), - /** Block size of 4M */ - M4(4096 * 1024, 7); - - private final int size, index; - BlockSize(int size, int index) { - this.size = size; - this.index = index; - } - int getSize() { - return size; - } - int getIndex() { - return index; - } - } - - /** - * Parameters of the LZ4 frame format. - */ - public static class Parameters { - private final BlockSize blockSize; - private final boolean withContentChecksum, withBlockChecksum, withBlockDependency; - private final org.apache.commons.compress.compressors.lz77support.Parameters lz77params; - - /** - * The default parameters of 4M block size, enabled content - * checksum, disabled block checksums and independent blocks. - * - *

This matches the defaults of the lz4 command line utility.

- */ - public static final Parameters DEFAULT = new Parameters(BlockSize.M4, true, false, false); - - /** - * Sets up custom a custom block size for the LZ4 stream but - * otherwise uses the defaults of enabled content checksum, - * disabled block checksums and independent blocks. - * @param blockSize the size of a single block. - */ - public Parameters(BlockSize blockSize) { - this(blockSize, true, false, false); - } - /** - * Sets up custom a custom block size for the LZ4 stream but - * otherwise uses the defaults of enabled content checksum, - * disabled block checksums and independent blocks. - * @param blockSize the size of a single block. - * @param lz77params parameters used to fine-tune compression, - * in particular to balance compression ratio vs compression - * speed. - */ - public Parameters(BlockSize blockSize, - org.apache.commons.compress.compressors.lz77support.Parameters lz77params) { - this(blockSize, true, false, false, lz77params); - } - /** - * Sets up custom parameters for the LZ4 stream. - * @param blockSize the size of a single block. - * @param withContentChecksum whether to write a content checksum - * @param withBlockChecksum whether to write a block checksum. - * Note that block checksums are not supported by the lz4 - * command line utility - * @param withBlockDependency whether a block may depend on - * the content of a previous block. Enabling this may improve - * compression ratio but makes it impossible to decompress the - * output in parallel. - */ - public Parameters(BlockSize blockSize, boolean withContentChecksum, boolean withBlockChecksum, - boolean withBlockDependency) { - this(blockSize, withContentChecksum, withBlockChecksum, withBlockDependency, - BlockLZ4CompressorOutputStream.createParameterBuilder().build()); - } - - /** - * Sets up custom parameters for the LZ4 stream. - * @param blockSize the size of a single block. - * @param withContentChecksum whether to write a content checksum - * @param withBlockChecksum whether to write a block checksum. - * Note that block checksums are not supported by the lz4 - * command line utility - * @param withBlockDependency whether a block may depend on - * the content of a previous block. Enabling this may improve - * compression ratio but makes it impossible to decompress the - * output in parallel. - * @param lz77params parameters used to fine-tune compression, - * in particular to balance compression ratio vs compression - * speed. - */ - public Parameters(BlockSize blockSize, boolean withContentChecksum, boolean withBlockChecksum, - boolean withBlockDependency, - org.apache.commons.compress.compressors.lz77support.Parameters lz77params) { - this.blockSize = blockSize; - this.withContentChecksum = withContentChecksum; - this.withBlockChecksum = withBlockChecksum; - this.withBlockDependency = withBlockDependency; - this.lz77params = lz77params; - } - - @Override - public String toString() { - return "LZ4 Parameters with BlockSize " + blockSize + ", withContentChecksum " + withContentChecksum - + ", withBlockChecksum " + withBlockChecksum + ", withBlockDependency " + withBlockDependency; - } - } - - /** - * Constructs a new output stream that compresses data using the - * LZ4 frame format using the default block size of 4MB. - * @param out the OutputStream to which to write the compressed data - * @throws IOException if writing the signature fails - */ - public FramedLZ4CompressorOutputStream(OutputStream out) throws IOException { - this(out, Parameters.DEFAULT); - } - - /** - * Constructs a new output stream that compresses data using the - * LZ4 frame format using the given block size. - * @param out the OutputStream to which to write the compressed data - * @param params the parameters to use - * @throws IOException if writing the signature fails - */ - public FramedLZ4CompressorOutputStream(OutputStream out, Parameters params) throws IOException { - this.params = params; - blockData = new byte[params.blockSize.getSize()]; - this.out = out; - blockHash = params.withBlockChecksum ? new XXHash32() : null; - out.write(FramedLZ4CompressorInputStream.LZ4_SIGNATURE); - writeFrameDescriptor(); - blockDependencyBuffer = params.withBlockDependency - ? new byte[BlockLZ4CompressorInputStream.WINDOW_SIZE] - : null; - } - - @Override - public void write(int b) throws IOException { - oneByte[0] = (byte) (b & 0xff); - write(oneByte); - } - - @Override - public void write(byte[] data, int off, int len) throws IOException { - if (params.withContentChecksum) { - contentHash.update(data, off, len); - } - if (currentIndex + len > blockData.length) { - flushBlock(); - while (len > blockData.length) { - System.arraycopy(data, off, blockData, 0, blockData.length); - off += blockData.length; - len -= blockData.length; - currentIndex = blockData.length; - flushBlock(); - } - } - System.arraycopy(data, off, blockData, currentIndex, len); - currentIndex += len; - } - - @Override - public void close() throws IOException { - finish(); - out.close(); - } - - /** - * Compresses all remaining data and writes it to the stream, - * doesn't close the underlying stream. - * @throws IOException if an error occurs - */ - public void finish() throws IOException { - if (!finished) { - if (currentIndex > 0) { - flushBlock(); - } - writeTrailer(); - finished = true; - } - } - - private void writeFrameDescriptor() throws IOException { - int flags = FramedLZ4CompressorInputStream.SUPPORTED_VERSION; - if (!params.withBlockDependency) { - flags |= FramedLZ4CompressorInputStream.BLOCK_INDEPENDENCE_MASK; - } - if (params.withContentChecksum) { - flags |= FramedLZ4CompressorInputStream.CONTENT_CHECKSUM_MASK; - } - if (params.withBlockChecksum) { - flags |= FramedLZ4CompressorInputStream.BLOCK_CHECKSUM_MASK; - } - out.write(flags); - contentHash.update(flags); - int bd = (params.blockSize.getIndex() << 4) & FramedLZ4CompressorInputStream.BLOCK_MAX_SIZE_MASK; - out.write(bd); - contentHash.update(bd); - out.write((int) ((contentHash.getValue() >> 8) & 0xff)); - contentHash.reset(); - } - - private void flushBlock() throws IOException { - final boolean withBlockDependency = params.withBlockDependency; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (BlockLZ4CompressorOutputStream o = new BlockLZ4CompressorOutputStream(baos, params.lz77params)) { - if (withBlockDependency) { - o.prefill(blockDependencyBuffer, blockDependencyBuffer.length - collectedBlockDependencyBytes, - collectedBlockDependencyBytes); - } - o.write(blockData, 0, currentIndex); - } - if (withBlockDependency) { - appendToBlockDependencyBuffer(blockData, 0, currentIndex); - } - byte[] b = baos.toByteArray(); - if (b.length > currentIndex) { // compression increased size, maybe beyond blocksize - ByteUtils.toLittleEndian(out, currentIndex | FramedLZ4CompressorInputStream.UNCOMPRESSED_FLAG_MASK, - 4); - out.write(blockData, 0, currentIndex); - if (params.withBlockChecksum) { - blockHash.update(blockData, 0, currentIndex); - } - } else { - ByteUtils.toLittleEndian(out, b.length, 4); - out.write(b); - if (params.withBlockChecksum) { - blockHash.update(b, 0, b.length); - } - } - if (params.withBlockChecksum) { - ByteUtils.toLittleEndian(out, blockHash.getValue(), 4); - blockHash.reset(); - } - currentIndex = 0; - } - - private void writeTrailer() throws IOException { - out.write(END_MARK); - if (params.withContentChecksum) { - ByteUtils.toLittleEndian(out, contentHash.getValue(), 4); - } - } - - private void appendToBlockDependencyBuffer(final byte[] b, final int off, int len) { - len = Math.min(len, blockDependencyBuffer.length); - if (len > 0) { - int keep = blockDependencyBuffer.length - len; - if (keep > 0) { - // move last keep bytes towards the start of the buffer - System.arraycopy(blockDependencyBuffer, len, blockDependencyBuffer, 0, keep); - } - // append new data - System.arraycopy(b, off, blockDependencyBuffer, keep, len); - collectedBlockDependencyBytes = Math.min(collectedBlockDependencyBytes + len, - blockDependencyBuffer.length); - } - } - -} - diff --git a/src/org/apache/commons/compress/compressors/lz4/XXHash32.java b/src/org/apache/commons/compress/compressors/lz4/XXHash32.java deleted file mode 100644 index 23d29b5f470..00000000000 --- a/src/org/apache/commons/compress/compressors/lz4/XXHash32.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz4; - -import static java.lang.Integer.rotateLeft; - -import java.util.zip.Checksum; - -import static org.apache.commons.compress.utils.ByteUtils.fromLittleEndian; - -/** - * Implementation of the xxhash32 hash algorithm. - * - * @see xxHash - * @NotThreadSafe - * @since 1.14 - */ -public class XXHash32 implements Checksum { - - private static final int BUF_SIZE = 16; - private static final int ROTATE_BITS = 13; - - private static final int PRIME1 = (int) 2654435761L; - private static final int PRIME2 = (int) 2246822519L; - private static final int PRIME3 = (int) 3266489917L; - private static final int PRIME4 = 668265263; - private static final int PRIME5 = 374761393; - - private final byte[] oneByte = new byte[1]; - private final int[] state = new int[4]; - // Note: the code used to use ByteBuffer but the manual method is 50% faster - // See: https://git-wip-us.apache.org/repos/asf/commons-compress/diff/2f56fb5c - private final byte[] buffer = new byte[BUF_SIZE]; - private final int seed; - - private int totalLen; - private int pos; - - /** - * Creates an XXHash32 instance with a seed of 0. - */ - public XXHash32() { - this(0); - } - - /** - * Creates an XXHash32 instance. - * @param seed the seed to use - */ - public XXHash32(int seed) { - this.seed = seed; - initializeState(); - } - - @Override - public void reset() { - initializeState(); - totalLen = 0; - pos = 0; - } - - @Override - public void update(int b) { - oneByte[0] = (byte) (b & 0xff); - update(oneByte, 0, 1); - } - - @Override - public void update(byte[] b, int off, final int len) { - if (len <= 0) { - return; - } - totalLen += len; - - final int end = off + len; - - if (pos + len < BUF_SIZE) { - System.arraycopy(b, off, buffer, pos, len); - pos += len; - return; - } - - if (pos > 0) { - final int size = BUF_SIZE - pos; - System.arraycopy(b, off, buffer, pos, size); - process(buffer, 0); - off += size; - } - - final int limit = end - BUF_SIZE; - while (off <= limit) { - process(b, off); - off += BUF_SIZE; - } - - if (off < end) { - pos = end - off; - System.arraycopy(b, off, buffer, 0, pos); - } - } - - @Override - public long getValue() { - int hash; - if (totalLen > BUF_SIZE) { - hash = - rotateLeft(state[0], 1) + - rotateLeft(state[1], 7) + - rotateLeft(state[2], 12) + - rotateLeft(state[3], 18); - } else { - hash = state[2] + PRIME5; - } - hash += totalLen; - - int idx = 0; - final int limit = pos - 4; - for (; idx <= limit; idx += 4) { - hash = rotateLeft(hash + getInt(buffer, idx) * PRIME3, 17) * PRIME4; - } - while (idx < pos) { - hash = rotateLeft(hash + (buffer[idx++] & 0xff) * PRIME5, 11) * PRIME1; - } - - hash ^= hash >>> 15; - hash *= PRIME2; - hash ^= hash >>> 13; - hash *= PRIME3; - hash ^= hash >>> 16; - return hash & 0xffffffffL; - } - - private static int getInt(byte[] buffer, int idx) { - return (int) (fromLittleEndian(buffer, idx, 4) & 0xffffffffL); - } - - private void initializeState() { - state[0] = seed + PRIME1 + PRIME2; - state[1] = seed + PRIME2; - state[2] = seed; - state[3] = seed - PRIME1; - } - - private void process(byte[] b, int offset) { - // local shadows for performance - int s0 = state[0]; - int s1 = state[1]; - int s2 = state[2]; - int s3 = state[3]; - - s0 = rotateLeft(s0 + getInt(b, offset) * PRIME2, ROTATE_BITS) * PRIME1; - s1 = rotateLeft(s1 + getInt(b, offset + 4) * PRIME2, ROTATE_BITS) * PRIME1; - s2 = rotateLeft(s2 + getInt(b, offset + 8) * PRIME2, ROTATE_BITS) * PRIME1; - s3 = rotateLeft(s3 + getInt(b, offset + 12) * PRIME2, ROTATE_BITS) * PRIME1; - - state[0] = s0; - state[1] = s1; - state[2] = s2; - state[3] = s3; - - pos = 0; - } -} diff --git a/src/org/apache/commons/compress/compressors/lz4/package.html b/src/org/apache/commons/compress/compressors/lz4/package.html deleted file mode 100644 index 54de62bc3a0..00000000000 --- a/src/org/apache/commons/compress/compressors/lz4/package.html +++ /dev/null @@ -1,37 +0,0 @@ - - - -

Provides stream classes for the - LZ4 - algorithm.

- -

The block LZ4 format which only contains the compressed data is - supported by the BlockLZ4Compressor*putStream - classes while the frame format is implemented - by FramedLZ4Compressor*putStream. The - implementation in Commons Compress is based on the - specifications "Last revised: 2015-03-26" for the block format - and version "1.5.1 (31/03/2015)" for the frame format.

- -

Only the frame format can be auto-detected this means you have - to speficy the format explicitly if you want to read a block LZ4 - stream via CompressorStreamFactory.

- - diff --git a/src/org/apache/commons/compress/compressors/lz77support/AbstractLZ77CompressorInputStream.java b/src/org/apache/commons/compress/compressors/lz77support/AbstractLZ77CompressorInputStream.java deleted file mode 100644 index 8a1371af93d..00000000000 --- a/src/org/apache/commons/compress/compressors/lz77support/AbstractLZ77CompressorInputStream.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz77support; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.ByteUtils; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * Encapsulates code common to LZ77 decompressors. - * - *

Assumes the stream consists of blocks of literal data and - * back-references (called copies) in any order. Of course the first - * block must be a literal block for the scheme to work - unless the - * {@link #prefill prefill} method has been used to provide initial - * data that is never returned by {@link #read read} but only used for - * back-references.

- * - *

Subclasses must override the three-arg {@link #read read} method - * as the no-arg version delegates to it and the default - * implementation delegates to the no-arg version, leading to infinite - * mutual recursion and a {@code StackOverflowError} otherwise.

- * - *

The contract for subclasses' {@code read} implementation is:

- *
    - * - *
  • keep track of the current state of the stream. Is it inside a - * literal block or a back-reference or in-between blocks?
  • - * - *
  • Use {@link #readOneByte} to access the underlying stream - * directly.
  • - * - *
  • If a new literal block starts, use {@link #startLiteral} to - * tell this class about it and read the literal data using {@link - * #readLiteral} until it returns {@code 0}. {@link - * #hasMoreDataInBlock} will return {@code false} before the next - * call to {@link #readLiteral} would return {@code 0}.
  • - * - *
  • If a new back-reference starts, use {@link #startBackReference} to - * tell this class about it and read the literal data using {@link - * #readBackReference} until it returns {@code 0}. {@link - * #hasMoreDataInBlock} will return {@code false} before the next - * call to {@link #readBackReference} would return {@code 0}.
  • - * - *
  • If the end of the stream has been reached, return {@code -1} - * as this class' methods will never do so themselves.
  • - * - *
- * - *

{@link #readOneByte} and {@link #readLiteral} update the counter - * for bytes read.

- * - * @since 1.14 - */ -public abstract class AbstractLZ77CompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - /** Size of the window - must be bigger than the biggest offset expected. */ - private final int windowSize; - - /** - * Buffer to write decompressed bytes to for back-references, will - * be three times windowSize big. - * - *

Three times so we can slide the whole buffer a windowSize to - * the left once we've read twice windowSize and still have enough - * data inside of it to satisfy back-references.

- */ - private final byte[] buf; - - /** One behind the index of the last byte in the buffer that was written, i.e. the next position to write to */ - private int writeIndex; - - /** Index of the next byte to be read. */ - private int readIndex; - - /** The underlying stream to read compressed data from */ - private final CountingInputStream in; - - /** Number of bytes still to be read from the current literal or back-reference. */ - private long bytesRemaining; - - /** Offset of the current back-reference. */ - private int backReferenceOffset; - - /** uncompressed size */ - private int size = 0; - - // used in no-arg read method - private final byte[] oneByte = new byte[1]; - - /** - * Supplier that delegates to {@link #readOneByte}. - */ - protected final ByteUtils.ByteSupplier supplier = new ByteUtils.ByteSupplier() { - @Override - public int getAsByte() throws IOException { - return readOneByte(); - } - }; - - /** - * Creates a new LZ77 input stream. - * - * @param is - * An InputStream to read compressed data from - * @param windowSize - * Size of the window kept for back-references, must be bigger than the biggest offset expected. - * - * @throws IOException if reading fails - */ - public AbstractLZ77CompressorInputStream(final InputStream is, int windowSize) throws IOException { - this.in = new CountingInputStream(is); - this.windowSize = windowSize; - buf = new byte[3 * windowSize]; - writeIndex = readIndex = 0; - bytesRemaining = 0; - } - - /** {@inheritDoc} */ - @Override - public int read() throws IOException { - return read(oneByte, 0, 1) == -1 ? -1 : oneByte[0] & 0xFF; - } - - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - in.close(); - } - - /** {@inheritDoc} */ - @Override - public int available() { - return writeIndex - readIndex; - } - - /** - * Get the uncompressed size of the stream - * - * @return the uncompressed size - */ - public int getSize() { - return size; - } - - /** - * Adds some initial data to fill the window with. - * - *

This is used if the stream has been cut into blocks and - * back-references of one block may refer to data of the previous - * block(s). One such example is the LZ4 frame format using block - * dependency.

- * - * @param data the data to fill the window with. - * @throws IllegalStateException if the stream has already started to read data - */ - public void prefill(byte[] data) { - if (writeIndex != 0) { - throw new IllegalStateException("the stream has already been read from, can't prefill anymore"); - } - // we don't need more data than the big offset could refer to, so cap it - int len = Math.min(windowSize, data.length); - // we need the last data as we are dealing with *back*-references - System.arraycopy(data, data.length - len, buf, 0, len); - writeIndex += len; - readIndex += len; - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return in.getBytesRead(); - } - - /** - * Used by subclasses to signal the next block contains the given - * amount of literal data. - * @param length the length of the block - */ - protected final void startLiteral(long length) { - bytesRemaining = length; - } - - /** - * Is there still data remaining inside the current block? - * @return true if there is still data remaining inside the current block. - */ - protected final boolean hasMoreDataInBlock() { - return bytesRemaining > 0; - } - - /** - * Reads data from the current literal block. - * @param b buffer to write data to - * @param off offset to start writing to - * @param len maximum amount of data to read - * @return number of bytes read, may be 0. Will never return -1 as - * EOF-detection is the responsibility of the subclass - * @throws IOException if the underlying stream throws or signals - * an EOF before the amount of data promised for the block have - * been read - */ - protected final int readLiteral(final byte[] b, final int off, final int len) throws IOException { - final int avail = available(); - if (len > avail) { - tryToReadLiteral(len - avail); - } - return readFromBuffer(b, off, len); - } - - private void tryToReadLiteral(int bytesToRead) throws IOException { - // min of "what is still inside the literal", "what does the user want" and "how muc can fit into the buffer" - final int reallyTryToRead = Math.min((int) Math.min(bytesToRead, bytesRemaining), - buf.length - writeIndex); - final int bytesRead = reallyTryToRead > 0 - ? IOUtils.readFully(in, buf, writeIndex, reallyTryToRead) - : 0 /* happens for bytesRemaining == 0 */; - count(bytesRead); - if (reallyTryToRead != bytesRead) { - throw new IOException("Premature end of stream reading literal"); - } - writeIndex += reallyTryToRead; - bytesRemaining -= reallyTryToRead; - } - - private int readFromBuffer(final byte[] b, final int off, final int len) { - final int readable = Math.min(len, available()); - if (readable > 0) { - System.arraycopy(buf, readIndex, b, off, readable); - readIndex += readable; - if (readIndex > 2 * windowSize) { - slideBuffer(); - } - } - size += readable; - return readable; - } - - private void slideBuffer() { - System.arraycopy(buf, windowSize, buf, 0, windowSize * 2); - writeIndex -= windowSize; - readIndex -= windowSize; - } - - /** - * Used by subclasses to signal the next block contains a back-reference with the given coordinates. - * @param offset the offset of the back-reference - * @param length the length of the back-reference - */ - protected final void startBackReference(int offset, long length) { - backReferenceOffset = offset; - bytesRemaining = length; - } - - /** - * Reads data from the current back-reference. - * @param b buffer to write data to - * @param off offset to start writing to - * @param len maximum amount of data to read - * @return number of bytes read, may be 0. Will never return -1 as - * EOF-detection is the responsibility of the subclass - */ - protected final int readBackReference(final byte[] b, final int off, final int len) { - final int avail = available(); - if (len > avail) { - tryToCopy(len - avail); - } - return readFromBuffer(b, off, len); - } - - private void tryToCopy(int bytesToCopy) { - // this will fit into the buffer without sliding and not - // require more than is available inside the back-reference - int copy = Math.min((int) Math.min(bytesToCopy, bytesRemaining), - buf.length - writeIndex); - if (copy == 0) { - // NOP - } else if (backReferenceOffset == 1) { // pretty common special case - final byte last = buf[writeIndex - 1]; - Arrays.fill(buf, writeIndex, writeIndex + copy, last); - writeIndex += copy; - } else if (copy < backReferenceOffset) { - System.arraycopy(buf, writeIndex - backReferenceOffset, buf, writeIndex, copy); - writeIndex += copy; - } else { - // back-reference overlaps with the bytes created from it - // like go back two bytes and then copy six (by copying - // the last two bytes three time). - final int fullRots = copy / backReferenceOffset; - for (int i = 0; i < fullRots; i++) { - System.arraycopy(buf, writeIndex - backReferenceOffset, buf, writeIndex, backReferenceOffset); - writeIndex += backReferenceOffset; - } - - final int pad = copy - (backReferenceOffset * fullRots); - if (pad > 0) { - System.arraycopy(buf, writeIndex - backReferenceOffset, buf, writeIndex, pad); - writeIndex += pad; - } - } - bytesRemaining -= copy; - } - - /** - * Reads a single byte from the real input stream and ensures the data is accounted for. - * - * @return the byte read as value between 0 and 255 or -1 if EOF has been reached. - * @throws IOException if the underlying stream throws - */ - protected final int readOneByte() throws IOException { - final int b = in.read(); - if (b != -1) { - count(1); - return b & 0xFF; - } - return -1; - } -} diff --git a/src/org/apache/commons/compress/compressors/lz77support/LZ77Compressor.java b/src/org/apache/commons/compress/compressors/lz77support/LZ77Compressor.java deleted file mode 100644 index 27fec8d3c3b..00000000000 --- a/src/org/apache/commons/compress/compressors/lz77support/LZ77Compressor.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz77support; - -import java.io.IOException; -import java.util.Arrays; - -/** - * Helper class for compression algorithms that use the ideas of LZ77. - * - *

Most LZ77 derived algorithms split input data into blocks of - * uncompressed data (called literal blocks) and back-references - * (pairs of offsets and lengths) that state "add length - * bytes that are the same as those already written starting - * offset bytes before the current position. The details - * of how those blocks and back-references are encoded are quite - * different between the algorithms and some algorithms perform - * additional steps (Huffman encoding in the case of DEFLATE for - * example).

- * - *

This class attempts to extract the core logic - finding - * back-references - so it can be re-used. It follows the algorithm - * explained in section 4 of RFC 1951 (DEFLATE) and currently doesn't - * implement the "lazy match" optimization. The three-byte hash - * function used in this class is the same as the one used by zlib and - * InfoZIP's ZIP implementation of DEFLATE. The whole class is - * strongly inspired by InfoZIP's implementation.

- * - *

LZ77 is used vaguely here (as well as many other places that - * talk about it :-), LZSS would likely be closer to the truth but - * LZ77 has become the synonym for a whole family of algorithms.

- * - *

The API consists of a compressor that is fed bytes - * and emits {@link Block}s to a registered callback where the blocks - * represent either {@link LiteralBlock literal blocks}, {@link - * BackReference back-references} or {@link EOD end of data - * markers}. In order to ensure the callback receives all information, - * the {@code #finish} method must be used once all data has been fed - * into the compressor.

- * - *

Several parameters influence the outcome of the "compression":

- *
- * - *
windowSize
the size of the sliding - * window, must be a power of two - this determines the maximum - * offset a back-reference can take. The compressor maintains a - * buffer of twice of windowSize - real world values are - * in the area of 32k.
- * - *
minBackReferenceLength
- *
Minimal length of a back-reference found. A true minimum of 3 is - * hard-coded inside of this implemention but bigger lengths can be - * configured.
- * - *
maxBackReferenceLength
- *
Maximal length of a back-reference found.
- * - *
maxOffset
- *
Maximal offset of a back-reference.
- * - *
maxLiteralLength
- *
Maximal length of a literal block.
- *
- * - * @see "https://tools.ietf.org/html/rfc1951#section-4" - * @since 1.14 - * @NotThreadSafe - */ -public class LZ77Compressor { - - /** - * Base class representing blocks the compressor may emit. - * - *

This class is not supposed to be subclassed by classes - * outside of Commons Compress so it is considered internal and - * changed that would break subclasses may get introduced with - * future releases.

- */ - public static abstract class Block { - /** Enumeration of the block types the compressor may emit. */ - public enum BlockType { - LITERAL, BACK_REFERENCE, EOD - } - public abstract BlockType getType(); - } - - /** - * Represents a literal block of data. - * - *

For performance reasons this encapsulates the real data, not - * a copy of it. Don't modify the data and process it inside of - * {@link Callback#accept} immediately as it will get overwritten - * sooner or later.

- */ - public static final class LiteralBlock extends Block { - private final byte[] data; - private final int offset, length; - public LiteralBlock(byte[] data, int offset, int length) { - this.data = data; - this.offset = offset; - this.length = length; - } - /** - * The literal data. - * - *

This returns a life view of the actual data in order to - * avoid copying, modify the array at your own risk.

- * @return the data - */ - public byte[] getData() { - return data; - } - /** - * Offset into data where the literal block starts. - * @return the offset - */ - public int getOffset() { - return offset; - } - /** - * Length of literal block. - * @return the length - */ - public int getLength() { - return length; - } - @Override - public BlockType getType() { - return BlockType.LITERAL; - } - @Override - public String toString() { - return "LiteralBlock starting at " + offset + " with length " + length; - } - } - - /** - * Represents a back-reference. - */ - public static final class BackReference extends Block { - private final int offset, length; - public BackReference(int offset, int length) { - this.offset = offset; - this.length = length; - } - /** - * Provides the offset of the back-reference. - * @return the offset - */ - public int getOffset() { - return offset; - } - /** - * Provides the length of the back-reference. - * @return the length - */ - public int getLength() { - return length; - } - @Override - public BlockType getType() { - return BlockType.BACK_REFERENCE; - } - @Override - public String toString() { - return "BackReference with offset " + offset + " and length " + length; - } - } - - /** A simple "we are done" marker. */ - public static final class EOD extends Block { - @Override - public BlockType getType() { - return BlockType.EOD; - } - } - - private static final Block THE_EOD = new EOD(); - - /** - * Callback invoked while the compressor processes data. - * - *

The callback is invoked on the same thread that receives the - * bytes to compress and may be invoked multiple times during the - * execution of {@link #compress} or {@link #finish}.

- */ - public interface Callback { - /** - * Consumes a block. - * @param b the block to consume - * @throws IOException in case of an error - */ - void accept(Block b) throws IOException; - } - - static final int NUMBER_OF_BYTES_IN_HASH = 3; - private static final int NO_MATCH = -1; - - private final Parameters params; - private final Callback callback; - - // the sliding window, twice as big as "windowSize" parameter - private final byte[] window; - // the head of hash-chain - indexed by hash-code, points to the - // location inside of window of the latest sequence of bytes with - // the given hash. - private final int[] head; - // for each window-location points to the latest earlier location - // with the same hash. Only stores values for the latest - // "windowSize" elements, the index is "window location modulo - // windowSize". - private final int[] prev; - - // bit mask used when indexing into prev - private final int wMask; - - private boolean initialized = false; - // the position inside of window that shall be encoded right now - private int currentPosition; - // the number of bytes available to compress including the one at - // currentPosition - private int lookahead = 0; - // the hash of the three bytes stating at the current position - private int insertHash = 0; - // the position inside of the window where the current literal - // block starts (in case we are inside of a literal block). - private int blockStart = 0; - // position of the current match - private int matchStart = NO_MATCH; - // number of missed insertString calls for the up to three last - // bytes of the last match that can only be performed once more - // data has been read - private int missedInserts = 0; - - /** - * Initializes a compressor with parameters and a callback. - * @param params the parameters - * @param callback the callback - * @throws NullPointerException if either parameter is null - */ - public LZ77Compressor(Parameters params, Callback callback) { - if (params == null) { - throw new NullPointerException("params must not be null"); - } - if (callback == null) { - throw new NullPointerException("callback must not be null"); - } - this.params = params; - this.callback = callback; - - final int wSize = params.getWindowSize(); - window = new byte[wSize * 2]; - wMask = wSize - 1; - head = new int[HASH_SIZE]; - Arrays.fill(head, NO_MATCH); - prev = new int[wSize]; - } - - /** - * Feeds bytes into the compressor which in turn may emit zero or - * more blocks to the callback during the execution of this - * method. - * @param data the data to compress - must not be null - * @throws IOException if the callback throws an exception - */ - public void compress(byte[] data) throws IOException { - compress(data, 0, data.length); - } - - /** - * Feeds bytes into the compressor which in turn may emit zero or - * more blocks to the callback during the execution of this - * method. - * @param data the data to compress - must not be null - * @param off the start offset of the data - * @param len the number of bytes to compress - * @throws IOException if the callback throws an exception - */ - public void compress(byte[] data, int off, int len) throws IOException { - final int wSize = params.getWindowSize(); - while (len > wSize) { // chop into windowSize sized chunks - doCompress(data, off, wSize); - off += wSize; - len -= wSize; - } - if (len > 0) { - doCompress(data, off, len); - } - } - - /** - * Tells the compressor to process all remaining data and signal - * end of data to the callback. - * - *

The compressor will in turn emit at least one block ({@link - * EOD}) but potentially multiple blocks to the callback during - * the execution of this method.

- * @throws IOException if the callback throws an exception - */ - public void finish() throws IOException { - if (blockStart != currentPosition || lookahead > 0) { - currentPosition += lookahead; - flushLiteralBlock(); - } - callback.accept(THE_EOD); - } - - /** - * Adds some initial data to fill the window with. - * - *

This is used if the stream has been cut into blocks and - * back-references of one block may refer to data of the previous - * block(s). One such example is the LZ4 frame format using block - * dependency.

- * - * @param data the data to fill the window with. - * @throws IllegalStateException if the compressor has already started to accept data - */ - public void prefill(byte[] data) { - if (currentPosition != 0 || lookahead != 0) { - throw new IllegalStateException("the compressor has already started to accept data, can't prefill anymore"); - } - - // don't need more than windowSize for back-references - final int len = Math.min(params.getWindowSize(), data.length); - System.arraycopy(data, data.length - len, window, 0, len); - - if (len >= NUMBER_OF_BYTES_IN_HASH) { - initialize(); - final int stop = len - NUMBER_OF_BYTES_IN_HASH + 1; - for (int i = 0; i < stop; i++) { - insertString(i); - } - missedInserts = NUMBER_OF_BYTES_IN_HASH - 1; - } else { // not enough data to hash anything - missedInserts = len; - } - blockStart = currentPosition = len; - } - - // we use a 15 bit hashcode as calculated in updateHash - private static final int HASH_SIZE = 1 << 15; - private static final int HASH_MASK = HASH_SIZE - 1; - private static final int H_SHIFT = 5; - - /** - * Assumes we are calculating the hash for three consecutive bytes - * as a rolling hash, i.e. for bytes ABCD if H is the hash of ABC - * the new hash for BCD is nextHash(H, D). - * - *

The hash is shifted by five bits on each update so all - * effects of A have been swapped after the third update.

- */ - private int nextHash(int oldHash, byte nextByte) { - final int nextVal = nextByte & 0xFF; - return ((oldHash << H_SHIFT) ^ nextVal) & HASH_MASK; - } - - // performs the actual algorithm with the pre-condition len <= windowSize - private void doCompress(byte[] data, int off, int len) throws IOException { - int spaceLeft = window.length - currentPosition - lookahead; - if (len > spaceLeft) { - slide(); - } - System.arraycopy(data, off, window, currentPosition + lookahead, len); - lookahead += len; - if (!initialized && lookahead >= params.getMinBackReferenceLength()) { - initialize(); - } - if (initialized) { - compress(); - } - } - - private void slide() throws IOException { - final int wSize = params.getWindowSize(); - if (blockStart != currentPosition && blockStart < wSize) { - flushLiteralBlock(); - blockStart = currentPosition; - } - System.arraycopy(window, wSize, window, 0, wSize); - currentPosition -= wSize; - matchStart -= wSize; - blockStart -= wSize; - for (int i = 0; i < HASH_SIZE; i++) { - int h = head[i]; - head[i] = h >= wSize ? h - wSize : NO_MATCH; - } - for (int i = 0; i < wSize; i++) { - int p = prev[i]; - prev[i] = p >= wSize ? p - wSize : NO_MATCH; - } - } - - private void initialize() { - for (int i = 0; i < NUMBER_OF_BYTES_IN_HASH - 1; i++) { - insertHash = nextHash(insertHash, window[i]); - } - initialized = true; - } - - private void compress() throws IOException { - final int minMatch = params.getMinBackReferenceLength(); - final boolean lazy = params.getLazyMatching(); - final int lazyThreshold = params.getLazyMatchingThreshold(); - - while (lookahead >= minMatch) { - catchUpMissedInserts(); - int matchLength = 0; - int hashHead = insertString(currentPosition); - if (hashHead != NO_MATCH && hashHead - currentPosition <= params.getMaxOffset()) { - // sets matchStart as a side effect - matchLength = longestMatch(hashHead); - - if (lazy && matchLength <= lazyThreshold && lookahead > minMatch) { - // try to find a longer match using the next position - matchLength = longestMatchForNextPosition(matchLength); - } - } - if (matchLength >= minMatch) { - if (blockStart != currentPosition) { - // emit preceeding literal block - flushLiteralBlock(); - blockStart = NO_MATCH; - } - flushBackReference(matchLength); - insertStringsInMatch(matchLength); - lookahead -= matchLength; - currentPosition += matchLength; - blockStart = currentPosition; - } else { - // no match, append to current or start a new literal - lookahead--; - currentPosition++; - if (currentPosition - blockStart >= params.getMaxLiteralLength()) { - flushLiteralBlock(); - blockStart = currentPosition; - } - } - } - } - - /** - * Inserts the current three byte sequence into the dictionary and - * returns the previous head of the hash-chain. - * - *

Updates insertHash and prev as a - * side effect.

- */ - private int insertString(int pos) { - insertHash = nextHash(insertHash, window[pos - 1 + NUMBER_OF_BYTES_IN_HASH]); - int hashHead = head[insertHash]; - prev[pos & wMask] = hashHead; - head[insertHash] = pos; - return hashHead; - } - - private int longestMatchForNextPosition(final int prevMatchLength) { - // save a bunch of values to restore them if the next match isn't better than the current one - final int prevMatchStart = matchStart; - final int prevInsertHash = insertHash; - - lookahead--; - currentPosition++; - int hashHead = insertString(currentPosition); - final int prevHashHead = prev[currentPosition & wMask]; - int matchLength = longestMatch(hashHead); - - if (matchLength <= prevMatchLength) { - // use the first match, as the next one isn't any better - matchLength = prevMatchLength; - matchStart = prevMatchStart; - - // restore modified values - head[insertHash] = prevHashHead; - insertHash = prevInsertHash; - currentPosition--; - lookahead++; - } - return matchLength; - } - - private void insertStringsInMatch(int matchLength) { - // inserts strings contained in current match - // insertString inserts the byte 2 bytes after position, which may not yet be available -> missedInserts - final int stop = Math.min(matchLength - 1, lookahead - NUMBER_OF_BYTES_IN_HASH); - // currentPosition has been inserted already - for (int i = 1; i <= stop; i++) { - insertString(currentPosition + i); - } - missedInserts = matchLength - stop - 1; - } - - private void catchUpMissedInserts() { - while (missedInserts > 0) { - insertString(currentPosition - missedInserts--); - } - } - - private void flushBackReference(int matchLength) throws IOException { - callback.accept(new BackReference(currentPosition - matchStart, matchLength)); - } - - private void flushLiteralBlock() throws IOException { - callback.accept(new LiteralBlock(window, blockStart, currentPosition - blockStart)); - } - - /** - * Searches the hash chain for real matches and returns the length - * of the longest match (0 if none were found) that isn't too far - * away (WRT maxOffset). - * - *

Sets matchStart to the index of the start position of the - * longest match as a side effect.

- */ - private int longestMatch(int matchHead) { - final int minLength = params.getMinBackReferenceLength(); - int longestMatchLength = minLength - 1; - final int maxPossibleLength = Math.min(params.getMaxBackReferenceLength(), lookahead); - final int minIndex = Math.max(0, currentPosition - params.getMaxOffset()); - final int niceBackReferenceLength = Math.min(maxPossibleLength, params.getNiceBackReferenceLength()); - final int maxCandidates = params.getMaxCandidates(); - for (int candidates = 0; candidates < maxCandidates && matchHead >= minIndex; candidates++) { - int currentLength = 0; - for (int i = 0; i < maxPossibleLength; i++) { - if (window[matchHead + i] != window[currentPosition + i]) { - break; - } - currentLength++; - } - if (currentLength > longestMatchLength) { - longestMatchLength = currentLength; - matchStart = matchHead; - if (currentLength >= niceBackReferenceLength) { - // no need to search any further - break; - } - } - matchHead = prev[matchHead & wMask]; - } - return longestMatchLength; // < minLength if no matches have been found, will be ignored in compress() - } -} diff --git a/src/org/apache/commons/compress/compressors/lz77support/Parameters.java b/src/org/apache/commons/compress/compressors/lz77support/Parameters.java deleted file mode 100644 index fe892f37f65..00000000000 --- a/src/org/apache/commons/compress/compressors/lz77support/Parameters.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lz77support; - -/** - * Parameters of the {@link LZ77Compressor compressor}. - */ -public final class Parameters { - /** - * The hard-coded absolute minimal length of a back-reference. - */ - public static final int TRUE_MIN_BACK_REFERENCE_LENGTH = LZ77Compressor.NUMBER_OF_BYTES_IN_HASH; - - /** - * Initializes the builder for the compressor's parameters with a - * minBackReferenceLength of 3 and max*Length - * equal to windowSize - 1. - * - *

It is recommended to not use this method directly but rather - * tune a pre-configured builder created by a format specific - * factory like {@link - * org.apache.commons.compress.compressors.snappy.SnappyCompressorOutputStream#createParameterBuilder}.

- * - * @param windowSize the size of the sliding window - this - * determines the maximum offset a back-reference can take. Must - * be a power of two. - * @throws IllegalArgumentException if windowSize is not a power of two. - * @return a builder configured for the given window size - */ - public static Builder builder(int windowSize) { - return new Builder(windowSize); - } - - /** - * Builder for {@link Parameters} instances. - */ - public static class Builder { - private final int windowSize; - private int minBackReferenceLength, maxBackReferenceLength, maxOffset, maxLiteralLength; - private Integer niceBackReferenceLength, maxCandidates, lazyThreshold; - private Boolean lazyMatches; - - private Builder(int windowSize) { - if (windowSize < 2 || !isPowerOfTwo(windowSize)) { - throw new IllegalArgumentException("windowSize must be a power of two"); - } - this.windowSize = windowSize; - minBackReferenceLength = TRUE_MIN_BACK_REFERENCE_LENGTH; - maxBackReferenceLength = windowSize - 1; - maxOffset = windowSize - 1; - maxLiteralLength = windowSize; - } - - /** - * Sets the mininal length of a back-reference. - * - *

Ensures maxBackReferenceLength is not - * smaller than minBackReferenceLength. - * - *

It is recommended to not use this method directly but - * rather tune a pre-configured builder created by a format - * specific factory like {@link - * org.apache.commons.compress.compressors.snappy.SnappyCompressorOutputStream#createParameterBuilder}.

- * - * @param minBackReferenceLength the minimal length of a back-reference found. A - * true minimum of 3 is hard-coded inside of this implemention - * but bigger lengths can be configured. - * @throws IllegalArgumentException if windowSize - * is smaller than minBackReferenceLength. - * @return the builder - */ - public Builder withMinBackReferenceLength(int minBackReferenceLength) { - this.minBackReferenceLength = Math.max(TRUE_MIN_BACK_REFERENCE_LENGTH, minBackReferenceLength); - if (windowSize < this.minBackReferenceLength) { - throw new IllegalArgumentException("minBackReferenceLength can't be bigger than windowSize"); - } - if (maxBackReferenceLength < this.minBackReferenceLength) { - maxBackReferenceLength = this.minBackReferenceLength; - } - return this; - } - - /** - * Sets the maximal length of a back-reference. - * - *

It is recommended to not use this method directly but - * rather tune a pre-configured builder created by a format - * specific factory like {@link - * org.apache.commons.compress.compressors.snappy.SnappyCompressorOutputStream#createParameterBuilder}.

- * - * @param maxBackReferenceLength maximal length of a - * back-reference found. A value smaller than - * minBackReferenceLength is interpreted as - * minBackReferenceLength. maxBackReferenceLength - * is capped at windowSize - 1. - * @return the builder - */ - public Builder withMaxBackReferenceLength(int maxBackReferenceLength) { - this.maxBackReferenceLength = maxBackReferenceLength < minBackReferenceLength ? minBackReferenceLength - : Math.min(maxBackReferenceLength, windowSize - 1); - return this; - } - - /** - * Sets the maximal offset of a back-reference. - * - *

It is recommended to not use this method directly but - * rather tune a pre-configured builder created by a format - * specific factory like {@link - * org.apache.commons.compress.compressors.snappy.SnappyCompressorOutputStream#createParameterBuilder}.

- * - * @param maxOffset maximal offset of a back-reference. A - * non-positive value as well as values bigger than - * windowSize - 1 are interpreted as windowSize - * - 1. - * @return the builder - */ - public Builder withMaxOffset(int maxOffset) { - this.maxOffset = maxOffset < 1 ? windowSize - 1 : Math.min(maxOffset, windowSize - 1); - return this; - } - - /** - * Sets the maximal length of a literal block. - * - *

It is recommended to not use this method directly but - * rather tune a pre-configured builder created by a format - * specific factory like {@link - * org.apache.commons.compress.compressors.snappy.SnappyCompressorOutputStream#createParameterBuilder}.

- * - * @param maxLiteralLength maximal length of a literal - * block. Negative numbers and 0 as well as values bigger than - * windowSize are interpreted as - * windowSize. - * @return the builder - */ - public Builder withMaxLiteralLength(int maxLiteralLength) { - this.maxLiteralLength = maxLiteralLength < 1 ? windowSize - : Math.min(maxLiteralLength, windowSize); - return this; - } - - /** - * Sets the "nice length" of a back-reference. - * - *

When a back-references if this size has been found, stop searching for longer back-references.

- * - *

This settings can be used to tune the tradeoff between compression speed and compression ratio.

- * @param niceLen the "nice length" of a back-reference - * @return the builder - */ - public Builder withNiceBackReferenceLength(int niceLen) { - niceBackReferenceLength = niceLen; - return this; - } - - /** - * Sets the maximum number of back-reference candidates that should be consulted. - * - *

This settings can be used to tune the tradeoff between compression speed and compression ratio.

- * @param maxCandidates maximum number of back-reference candidates - * @return the builder - */ - public Builder withMaxNumberOfCandidates(int maxCandidates) { - this.maxCandidates = maxCandidates; - return this; - } - - /** - * Sets whether lazy matching should be performed. - * - *

Lazy matching means that after a back-reference for a certain position has been found the compressor will - * try to find a longer match for the next position.

- * - *

Lazy matching is enabled by default and disabled when tuning for speed.

- * @param lazy whether lazy matching should be performed - * @return the builder - */ - public Builder withLazyMatching(boolean lazy) { - lazyMatches = lazy; - return this; - } - - /** - * Sets the threshold for lazy matching. - * - *

Even if lazy matching is enabled it will not be performed if the length of the back-reference found for - * the current position is longer than this value.

- * @param threshold the threshold for lazy matching - * @return the builder - */ - public Builder withLazyThreshold(int threshold) { - lazyThreshold = threshold; - return this; - } - - /** - * Changes the default setting for "nice back-reference length" and "maximum number of candidates" for improved - * compression speed at the cost of compression ratio. - * - *

Use this method after configuring "maximum back-reference length".

- * @return the builder - */ - public Builder tunedForSpeed() { - niceBackReferenceLength = Math.max(minBackReferenceLength, maxBackReferenceLength / 8); - maxCandidates = Math.max(32, windowSize / 1024); - lazyMatches = false; - lazyThreshold = minBackReferenceLength; - return this; - } - - /** - * Changes the default setting for "nice back-reference length" and "maximum number of candidates" for improved - * compression ratio at the cost of compression speed. - * - *

Use this method after configuring "maximum back-reference length".

- * @return the builder - */ - public Builder tunedForCompressionRatio() { - niceBackReferenceLength = lazyThreshold = maxBackReferenceLength; - maxCandidates = Math.max(32, windowSize / 16); - lazyMatches = true; - return this; - } - - /** - * Creates the {@link Parameters} instance. - * @return the configured {@link Parameters} instance. - */ - public Parameters build() { - // default settings tuned for a compromise of good compression and acceptable speed - int niceLen = niceBackReferenceLength != null ? niceBackReferenceLength - : Math.max(minBackReferenceLength, maxBackReferenceLength / 2); - int candidates = maxCandidates != null ? maxCandidates : Math.max(256, windowSize / 128); - boolean lazy = lazyMatches == null || lazyMatches; - int threshold = lazy ? (lazyThreshold != null ? lazyThreshold : niceLen) : minBackReferenceLength; - - return new Parameters(windowSize, minBackReferenceLength, maxBackReferenceLength, - maxOffset, maxLiteralLength, niceLen, candidates, lazy, threshold); - } - } - - private final int windowSize, minBackReferenceLength, maxBackReferenceLength, maxOffset, maxLiteralLength, - niceBackReferenceLength, maxCandidates, lazyThreshold; - private final boolean lazyMatching; - - private Parameters(int windowSize, int minBackReferenceLength, int maxBackReferenceLength, int maxOffset, - int maxLiteralLength, int niceBackReferenceLength, int maxCandidates, boolean lazyMatching, - int lazyThreshold) { - this.windowSize = windowSize; - this.minBackReferenceLength = minBackReferenceLength; - this.maxBackReferenceLength = maxBackReferenceLength; - this.maxOffset = maxOffset; - this.maxLiteralLength = maxLiteralLength; - this.niceBackReferenceLength = niceBackReferenceLength; - this.maxCandidates = maxCandidates; - this.lazyMatching = lazyMatching; - this.lazyThreshold = lazyThreshold; - } - - /** - * Gets the size of the sliding window - this determines the - * maximum offset a back-reference can take. - * @return the size of the sliding window - */ - public int getWindowSize() { - return windowSize; - } - /** - * Gets the minimal length of a back-reference found. - * @return the minimal length of a back-reference found - */ - public int getMinBackReferenceLength() { - return minBackReferenceLength; - } - /** - * Gets the maximal length of a back-reference found. - * @return the maximal length of a back-reference found - */ - public int getMaxBackReferenceLength() { - return maxBackReferenceLength; - } - /** - * Gets the maximal offset of a back-reference found. - * @return the maximal offset of a back-reference found - */ - public int getMaxOffset() { - return maxOffset; - } - /** - * Gets the maximal length of a literal block. - * @return the maximal length of a literal block - */ - public int getMaxLiteralLength() { - return maxLiteralLength; - } - - /** - * Gets the length of a back-reference that is considered nice enough to stop searching for longer ones. - * @return the length of a back-reference that is considered nice enough to stop searching - */ - public int getNiceBackReferenceLength() { - return niceBackReferenceLength; - } - - /** - * Gets the maximum number of back-reference candidates to consider. - * @return the maximum number of back-reference candidates to consider - */ - public int getMaxCandidates() { - return maxCandidates; - } - - /** - * Gets whether to perform lazy matching. - * @return whether to perform lazy matching - */ - public boolean getLazyMatching() { - return lazyMatching; - } - - /** - * Gets the threshold for lazy matching. - * @return the threshold for lazy matching - */ - public int getLazyMatchingThreshold() { - return lazyThreshold; - } - - private static final boolean isPowerOfTwo(int x) { - // pre-condition: x > 0 - return (x & (x - 1)) == 0; - } -} diff --git a/src/org/apache/commons/compress/compressors/lz77support/package.html b/src/org/apache/commons/compress/compressors/lz77support/package.html deleted file mode 100644 index 951b1460a8e..00000000000 --- a/src/org/apache/commons/compress/compressors/lz77support/package.html +++ /dev/null @@ -1,28 +0,0 @@ - - - -

Provides utility classes for LZ77 based algorithms.

- -

The classes in this package are currently used by the LZ4 and - Snappy implementations but might also help implementing other - algorithms that derive from LZ77 and LZSS.

- - - diff --git a/src/org/apache/commons/compress/compressors/lzma/LZMACompressorInputStream.java b/src/org/apache/commons/compress/compressors/lzma/LZMACompressorInputStream.java deleted file mode 100644 index 794e3a54010..00000000000 --- a/src/org/apache/commons/compress/compressors/lzma/LZMACompressorInputStream.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lzma; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.MemoryLimitException; -import org.tukaani.xz.LZMAInputStream; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * LZMA decompressor. - * @since 1.6 - */ -public class LZMACompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - private final CountingInputStream countingStream; - private final InputStream in; - - /** - * Creates a new input stream that decompresses LZMA-compressed data - * from the specified input stream. - * - * @param inputStream where to read the compressed data - * - * @throws IOException if the input is not in the .lzma format, - * the input is corrupt or truncated, the .lzma - * headers specify sizes that are not supported - * by this implementation, or the underlying - * inputStream throws an exception - */ - public LZMACompressorInputStream(final InputStream inputStream) - throws IOException { - in = new LZMAInputStream(countingStream = new CountingInputStream(inputStream), -1); - } - - /** - * Creates a new input stream that decompresses LZMA-compressed data - * from the specified input stream. - * - * @param inputStream where to read the compressed data - * - * @param memoryLimitInKb calculated memory use threshold. Throws MemoryLimitException - * if calculate memory use is above this threshold - * - * @throws IOException if the input is not in the .lzma format, - * the input is corrupt or truncated, the .lzma - * headers specify sizes that are not supported - * by this implementation, or the underlying - * inputStream throws an exception - * - * @since 1.14 - */ - public LZMACompressorInputStream(final InputStream inputStream, int memoryLimitInKb) - throws IOException { - try { - in = new LZMAInputStream(countingStream = new CountingInputStream(inputStream), memoryLimitInKb); - } catch (org.tukaani.xz.MemoryLimitException e) { - //convert to commons-compress exception - throw new MemoryLimitException(e.getMemoryNeeded(), e.getMemoryLimit(), e); - } - } - - /** {@inheritDoc} */ - @Override - public int read() throws IOException { - final int ret = in.read(); - count(ret == -1 ? 0 : 1); - return ret; - } - - /** {@inheritDoc} */ - @Override - public int read(final byte[] buf, final int off, final int len) throws IOException { - final int ret = in.read(buf, off, len); - count(ret); - return ret; - } - - /** {@inheritDoc} */ - @Override - public long skip(final long n) throws IOException { - return IOUtils.skip(in, n); - } - - /** {@inheritDoc} */ - @Override - public int available() throws IOException { - return in.available(); - } - - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - in.close(); - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return countingStream.getBytesRead(); - } - - /** - * Checks if the signature matches what is expected for an lzma file. - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is an lzma compressed stream, false otherwise - * - * @since 1.10 - */ - public static boolean matches(final byte[] signature, final int length) { - return signature != null && length >= 3 && - signature[0] == 0x5d && signature[1] == 0 && - signature[2] == 0; - } -} diff --git a/src/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStream.java b/src/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStream.java deleted file mode 100644 index e6bdfa4557a..00000000000 --- a/src/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStream.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lzma; - -import java.io.IOException; -import java.io.OutputStream; -import org.tukaani.xz.LZMA2Options; -import org.tukaani.xz.LZMAOutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; - -/** - * LZMA compressor. - * @since 1.13 - */ -public class LZMACompressorOutputStream extends CompressorOutputStream { - private final LZMAOutputStream out; - - /** - * Creates a LZMA compressor. - * - * @param outputStream the stream to wrap - * @throws IOException on error - */ - public LZMACompressorOutputStream(final OutputStream outputStream) - throws IOException { - out = new LZMAOutputStream(outputStream, new LZMA2Options(), -1); - } - - /** {@inheritDoc} */ - @Override - public void write(final int b) throws IOException { - out.write(b); - } - - /** {@inheritDoc} */ - @Override - public void write(final byte[] buf, final int off, final int len) throws IOException { - out.write(buf, off, len); - } - - /** - * Doesn't do anything as {@link LZMAOutputStream} doesn't support flushing. - */ - @Override - public void flush() throws IOException { - } - - /** - * Finishes compression without closing the underlying stream. - * No more data can be written to this stream after finishing. - * @throws IOException on error - */ - public void finish() throws IOException { - out.finish(); - } - - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - out.close(); - } -} diff --git a/src/org/apache/commons/compress/compressors/lzma/LZMAUtils.java b/src/org/apache/commons/compress/compressors/lzma/LZMAUtils.java deleted file mode 100644 index 8722e6d8906..00000000000 --- a/src/org/apache/commons/compress/compressors/lzma/LZMAUtils.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lzma; - -import java.util.HashMap; -import java.util.Map; -import org.apache.commons.compress.compressors.FileNameUtil; - -/** - * Utility code for the lzma compression format. - * @ThreadSafe - * @since 1.10 - */ -public class LZMAUtils { - - private static final FileNameUtil fileNameUtil; - - /** - * LZMA Header Magic Bytes begin a LZMA file. - */ - private static final byte[] HEADER_MAGIC = { - (byte) 0x5D, 0, 0 - }; - - enum CachedAvailability { - DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE - } - - private static volatile CachedAvailability cachedLZMAAvailability; - - static { - final Map uncompressSuffix = new HashMap<>(); - uncompressSuffix.put(".lzma", ""); - uncompressSuffix.put("-lzma", ""); - fileNameUtil = new FileNameUtil(uncompressSuffix, ".lzma"); - cachedLZMAAvailability = CachedAvailability.DONT_CACHE; - try { - Class.forName("org.osgi.framework.BundleEvent"); - } catch (final Exception ex) { - setCacheLZMAAvailablity(true); - } - } - - /** Private constructor to prevent instantiation of this utility class. */ - private LZMAUtils() { - } - - /** - * Checks if the signature matches what is expected for a .lzma file. - * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true if signature matches the .lzma magic bytes, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < HEADER_MAGIC.length) { - return false; - } - - for (int i = 0; i < HEADER_MAGIC.length; ++i) { - if (signature[i] != HEADER_MAGIC[i]) { - return false; - } - } - - return true; - } - - /** - * Are the classes required to support LZMA compression available? - * @return true if the classes required to support LZMA - * compression are available - */ - public static boolean isLZMACompressionAvailable() { - final CachedAvailability cachedResult = cachedLZMAAvailability; - if (cachedResult != CachedAvailability.DONT_CACHE) { - return cachedResult == CachedAvailability.CACHED_AVAILABLE; - } - return internalIsLZMACompressionAvailable(); - } - - private static boolean internalIsLZMACompressionAvailable() { - try { - LZMACompressorInputStream.matches(null, 0); - return true; - } catch (final NoClassDefFoundError error) { - return false; - } - } - - /** - * Detects common lzma suffixes in the given filename. - * - * @param filename name of a file - * @return {@code true} if the filename has a common lzma suffix, - * {@code false} otherwise - */ - public static boolean isCompressedFilename(final String filename) { - return fileNameUtil.isCompressedFilename(filename); - } - - /** - * Maps the given name of a lzma-compressed file to the name that - * the file should have after uncompression. Any filenames with - * the generic ".lzma" suffix (or any other generic lzma suffix) - * is mapped to a name without that suffix. If no lzma suffix is - * detected, then the filename is returned unmapped. - * - * @param filename name of a file - * @return name of the corresponding uncompressed file - */ - public static String getUncompressedFilename(final String filename) { - return fileNameUtil.getUncompressedFilename(filename); - } - - /** - * Maps the given filename to the name that the file should have after - * compression with lzma. - * - * @param filename name of a file - * @return name of the corresponding compressed file - */ - public static String getCompressedFilename(final String filename) { - return fileNameUtil.getCompressedFilename(filename); - } - - /** - * Whether to cache the result of the LZMA check. - * - *

This defaults to {@code false} in an OSGi environment and {@code true} otherwise.

- * @param doCache whether to cache the result - */ - public static void setCacheLZMAAvailablity(final boolean doCache) { - if (!doCache) { - cachedLZMAAvailability = CachedAvailability.DONT_CACHE; - } else if (cachedLZMAAvailability == CachedAvailability.DONT_CACHE) { - final boolean hasLzma = internalIsLZMACompressionAvailable(); - cachedLZMAAvailability = hasLzma ? CachedAvailability.CACHED_AVAILABLE // NOSONAR - : CachedAvailability.CACHED_UNAVAILABLE; - } - } - - // only exists to support unit tests - static CachedAvailability getCachedLZMAAvailability() { - return cachedLZMAAvailability; - } -} diff --git a/src/org/apache/commons/compress/compressors/lzma/package.html b/src/org/apache/commons/compress/compressors/lzma/package.html deleted file mode 100644 index f3b54730f6a..00000000000 --- a/src/org/apache/commons/compress/compressors/lzma/package.html +++ /dev/null @@ -1,32 +0,0 @@ - - - -

Provides stream classes using the "stand-alone" LZMA - algorithm.

- -

The classes in this package are wrappers around stream classes - provided by the public - domain XZ for Java - library.

- -

In general you should prefer the more modern and robust XZ - format over stand-alone LZMA compression.

- - diff --git a/src/org/apache/commons/compress/compressors/lzw/LZWInputStream.java b/src/org/apache/commons/compress/compressors/lzw/LZWInputStream.java deleted file mode 100644 index a5e512c0528..00000000000 --- a/src/org/apache/commons/compress/compressors/lzw/LZWInputStream.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.lzw; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteOrder; - -import org.apache.commons.compress.MemoryLimitException; -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.BitInputStream; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - *

Generic LZW implementation. It is used internally for - * the Z decompressor and the Unshrinking Zip file compression method, - * but may be useful for third-party projects in implementing their own LZW variations.

- * - * @NotThreadSafe - * @since 1.10 - */ -public abstract class LZWInputStream extends CompressorInputStream implements InputStreamStatistics { - protected static final int DEFAULT_CODE_SIZE = 9; - protected static final int UNUSED_PREFIX = -1; - - private final byte[] oneByte = new byte[1]; - - protected final BitInputStream in; - private int clearCode = -1; - private int codeSize = DEFAULT_CODE_SIZE; - private byte previousCodeFirstChar; - private int previousCode = UNUSED_PREFIX; - private int tableSize; - private int[] prefixes; - private byte[] characters; - private byte[] outputStack; - private int outputStackLocation; - - protected LZWInputStream(final InputStream inputStream, final ByteOrder byteOrder) { - this.in = new BitInputStream(inputStream, byteOrder); - } - - @Override - public void close() throws IOException { - in.close(); - } - - @Override - public int read() throws IOException { - final int ret = read(oneByte); - if (ret < 0) { - return ret; - } - return 0xff & oneByte[0]; - } - - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - int bytesRead = readFromStack(b, off, len); - while (len - bytesRead > 0) { - final int result = decompressNextSymbol(); - if (result < 0) { - if (bytesRead > 0) { - count(bytesRead); - return bytesRead; - } - return result; - } - bytesRead += readFromStack(b, off + bytesRead, len - bytesRead); - } - count(bytesRead); - return bytesRead; - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return in.getBytesRead(); - } - - /** - * Read the next code and expand it. - * @return the expanded next code - * @throws IOException on error - */ - protected abstract int decompressNextSymbol() throws IOException; - - /** - * Add a new entry to the dictionary. - * @param previousCode the previous code - * @param character the next character to append - * @return the new code - * @throws IOException on error - */ - protected abstract int addEntry(int previousCode, byte character) - throws IOException; - - /** - * Sets the clear code based on the code size. - * @param codeSize code size - */ - protected void setClearCode(final int codeSize) { - clearCode = (1 << (codeSize - 1)); - } - - /** - * Initializes the arrays based on the maximum code size. - * First checks that the estimated memory usage is below memoryLimitInKb - * - * @param maxCodeSize maximum code size - * @param memoryLimitInKb maximum allowed estimated memory usage in Kb - * @throws MemoryLimitException if estimated memory usage is greater than memoryLimitInKb - */ - protected void initializeTables(final int maxCodeSize, final int memoryLimitInKb) - throws MemoryLimitException { - - if (memoryLimitInKb > -1) { - final int maxTableSize = 1 << maxCodeSize; - //account for potential overflow - long memoryUsageInBytes = (long) maxTableSize * 6;//(4 (prefixes) + 1 (characters) +1 (outputStack)) - long memoryUsageInKb = memoryUsageInBytes >> 10; - - if (memoryUsageInKb > memoryLimitInKb) { - throw new MemoryLimitException(memoryUsageInKb, memoryLimitInKb); - } - } - initializeTables(maxCodeSize); - } - - /** - * Initializes the arrays based on the maximum code size. - * @param maxCodeSize maximum code size - */ - protected void initializeTables(final int maxCodeSize) { - final int maxTableSize = 1 << maxCodeSize; - prefixes = new int[maxTableSize]; - characters = new byte[maxTableSize]; - outputStack = new byte[maxTableSize]; - outputStackLocation = maxTableSize; - final int max = 1 << 8; - for (int i = 0; i < max; i++) { - prefixes[i] = -1; - characters[i] = (byte) i; - } - } - - /** - * Reads the next code from the stream. - * @return the next code - * @throws IOException on error - */ - protected int readNextCode() throws IOException { - if (codeSize > 31) { - throw new IllegalArgumentException("code size must not be bigger than 31"); - } - return (int) in.readBits(codeSize); - } - - /** - * Adds a new entry if the maximum table size hasn't been exceeded - * and returns the new index. - * @param previousCode the previous code - * @param character the character to append - * @param maxTableSize the maximum table size - * @return the new code - */ - protected int addEntry(final int previousCode, final byte character, final int maxTableSize) { - if (tableSize < maxTableSize) { - prefixes[tableSize] = previousCode; - characters[tableSize] = character; - return tableSize++; - } - return -1; - } - - /** - * Add entry for repeat of previousCode we haven't added, yet. - * @return new code for a repeat of the previous code - * @throws IOException on error - */ - protected int addRepeatOfPreviousCode() throws IOException { - if (previousCode == -1) { - // can't have a repeat for the very first code - throw new IOException("The first code can't be a reference to its preceding code"); - } - return addEntry(previousCode, previousCodeFirstChar); - } - - /** - * Expands the entry with index code to the output stack and may - * create a new entry - * @param code the code - * @param addedUnfinishedEntry whether unfinished entries have been added - * @return the new location of the output stack - * @throws IOException on error - */ - protected int expandCodeToOutputStack(final int code, final boolean addedUnfinishedEntry) - throws IOException { - for (int entry = code; entry >= 0; entry = prefixes[entry]) { - outputStack[--outputStackLocation] = characters[entry]; - } - if (previousCode != -1 && !addedUnfinishedEntry) { - addEntry(previousCode, outputStack[outputStackLocation]); - } - previousCode = code; - previousCodeFirstChar = outputStack[outputStackLocation]; - return outputStackLocation; - } - - private int readFromStack(final byte[] b, final int off, final int len) { - final int remainingInStack = outputStack.length - outputStackLocation; - if (remainingInStack > 0) { - final int maxLength = Math.min(remainingInStack, len); - System.arraycopy(outputStack, outputStackLocation, b, off, maxLength); - outputStackLocation += maxLength; - return maxLength; - } - return 0; - } - - protected int getCodeSize() { - return codeSize; - } - - protected void resetCodeSize() { - setCodeSize(DEFAULT_CODE_SIZE); - } - - protected void setCodeSize(final int cs) { - this.codeSize = cs; - } - - protected void incrementCodeSize() { - codeSize++; - } - - protected void resetPreviousCode() { - this.previousCode = -1; - } - - protected int getPrefix(final int offset) { - return prefixes[offset]; - } - - protected void setPrefix(final int offset, final int value) { - prefixes[offset] = value; - } - - protected int getPrefixesLength() { - return prefixes.length; - } - - protected int getClearCode() { - return clearCode; - } - - protected int getTableSize() { - return tableSize; - } - - protected void setTableSize(final int newSize) { - tableSize = newSize; - } - -} diff --git a/src/org/apache/commons/compress/compressors/lzw/package.html b/src/org/apache/commons/compress/compressors/lzw/package.html deleted file mode 100644 index 3c45ca62a0d..00000000000 --- a/src/org/apache/commons/compress/compressors/lzw/package.html +++ /dev/null @@ -1,23 +0,0 @@ - - - -

Generic LZW implementation.

- - diff --git a/src/org/apache/commons/compress/compressors/pack200/InMemoryCachingStreamBridge.java b/src/org/apache/commons/compress/compressors/pack200/InMemoryCachingStreamBridge.java deleted file mode 100644 index e1fdc2cbac6..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/InMemoryCachingStreamBridge.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.pack200; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * StreamSwitcher that caches all data written to the output side in - * memory. - * @since 1.3 - */ -class InMemoryCachingStreamBridge extends StreamBridge { - InMemoryCachingStreamBridge() { - super(new ByteArrayOutputStream()); - } - - @Override - InputStream getInputView() throws IOException { - return new ByteArrayInputStream(((ByteArrayOutputStream) out) - .toByteArray()); - } -} \ No newline at end of file diff --git a/src/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java b/src/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java deleted file mode 100644 index 04fdc2bb6f7..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/Pack200CompressorInputStream.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.pack200; - -import java.io.File; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; -import java.util.jar.JarOutputStream; -import java.util.jar.Pack200; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.IOUtils; - -/** - * An input stream that decompresses from the Pack200 format to be read - * as any other stream. - * - *

The {@link CompressorInputStream#getCount getCount} and {@link - * CompressorInputStream#getBytesRead getBytesRead} methods always - * return 0.

- * - * @NotThreadSafe - * @since 1.3 - */ -public class Pack200CompressorInputStream extends CompressorInputStream { - private final InputStream originalInput; - private final StreamBridge streamBridge; - - /** - * Decompresses the given stream, caching the decompressed data in - * memory. - * - *

When reading from a file the File-arg constructor may - * provide better performance.

- * - * @param in the InputStream from which this object should be created - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final InputStream in) - throws IOException { - this(in, Pack200Strategy.IN_MEMORY); - } - - /** - * Decompresses the given stream using the given strategy to cache - * the results. - * - *

When reading from a file the File-arg constructor may - * provide better performance.

- * - * @param in the InputStream from which this object should be created - * @param mode the strategy to use - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final InputStream in, - final Pack200Strategy mode) - throws IOException { - this(in, null, mode, null); - } - - /** - * Decompresses the given stream, caching the decompressed data in - * memory and using the given properties. - * - *

When reading from a file the File-arg constructor may - * provide better performance.

- * - * @param in the InputStream from which this object should be created - * @param props Pack200 properties to use - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final InputStream in, - final Map props) - throws IOException { - this(in, Pack200Strategy.IN_MEMORY, props); - } - - /** - * Decompresses the given stream using the given strategy to cache - * the results and the given properties. - * - *

When reading from a file the File-arg constructor may - * provide better performance.

- * - * @param in the InputStream from which this object should be created - * @param mode the strategy to use - * @param props Pack200 properties to use - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final InputStream in, - final Pack200Strategy mode, - final Map props) - throws IOException { - this(in, null, mode, props); - } - - /** - * Decompresses the given file, caching the decompressed data in - * memory. - * - * @param f the file to decompress - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final File f) throws IOException { - this(f, Pack200Strategy.IN_MEMORY); - } - - /** - * Decompresses the given file using the given strategy to cache - * the results. - * - * @param f the file to decompress - * @param mode the strategy to use - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final File f, final Pack200Strategy mode) - throws IOException { - this(null, f, mode, null); - } - - /** - * Decompresses the given file, caching the decompressed data in - * memory and using the given properties. - * - * @param f the file to decompress - * @param props Pack200 properties to use - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final File f, - final Map props) - throws IOException { - this(f, Pack200Strategy.IN_MEMORY, props); - } - - /** - * Decompresses the given file using the given strategy to cache - * the results and the given properties. - * - * @param f the file to decompress - * @param mode the strategy to use - * @param props Pack200 properties to use - * @throws IOException if reading fails - */ - public Pack200CompressorInputStream(final File f, final Pack200Strategy mode, - final Map props) - throws IOException { - this(null, f, mode, props); - } - - private Pack200CompressorInputStream(final InputStream in, final File f, - final Pack200Strategy mode, - final Map props) - throws IOException { - originalInput = in; - streamBridge = mode.newStreamBridge(); - try (final JarOutputStream jarOut = new JarOutputStream(streamBridge)) { - final Pack200.Unpacker u = Pack200.newUnpacker(); - if (props != null) { - u.properties().putAll(props); - } - if (f == null) { - u.unpack(new FilterInputStream(in) { - @Override - public void close() { - // unpack would close this stream but we - // want to give the user code more control - } - }, jarOut); - } else { - u.unpack(f, jarOut); - } - } - } - - @Override - public int read() throws IOException { - return streamBridge.getInput().read(); - } - - @Override - public int read(final byte[] b) throws IOException { - return streamBridge.getInput().read(b); - } - - @Override - public int read(final byte[] b, final int off, final int count) throws IOException { - return streamBridge.getInput().read(b, off, count); - } - - @Override - public int available() throws IOException { - return streamBridge.getInput().available(); - } - - @Override - public boolean markSupported() { - try { - return streamBridge.getInput().markSupported(); - } catch (final IOException ex) { - return false; - } - } - - @Override - public void mark(final int limit) { - try { - streamBridge.getInput().mark(limit); - } catch (final IOException ex) { - throw new RuntimeException(ex); //NOSONAR - } - } - - @Override - public void reset() throws IOException { - streamBridge.getInput().reset(); - } - - @Override - public long skip(final long count) throws IOException { - return IOUtils.skip(streamBridge.getInput(), count); - } - - @Override - public void close() throws IOException { - try { - streamBridge.stop(); - } finally { - if (originalInput != null) { - originalInput.close(); - } - } - } - - private static final byte[] CAFE_DOOD = new byte[] { - (byte) 0xCA, (byte) 0xFE, (byte) 0xD0, (byte) 0x0D - }; - private static final int SIG_LENGTH = CAFE_DOOD.length; - - /** - * Checks if the signature matches what is expected for a pack200 - * file (0xCAFED00D). - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is a pack200 compressed stream, - * false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < SIG_LENGTH) { - return false; - } - - for (int i = 0; i < SIG_LENGTH; i++) { - if (signature[i] != CAFE_DOOD[i]) { - return false; - } - } - - return true; - } -} diff --git a/src/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java b/src/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java deleted file mode 100644 index ff43a94a98a..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/Pack200CompressorOutputStream.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.pack200; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Map; -import java.util.jar.JarInputStream; -import java.util.jar.Pack200; - -import org.apache.commons.compress.compressors.CompressorOutputStream; - -/** - * An output stream that compresses using the Pack200 format. - * - * @NotThreadSafe - * @since 1.3 - */ -public class Pack200CompressorOutputStream extends CompressorOutputStream { - private boolean finished = false; - private final OutputStream originalOutput; - private final StreamBridge streamBridge; - private final Map properties; - - /** - * Compresses the given stream, caching the compressed data in - * memory. - * - * @param out the stream to write to - * @throws IOException if writing fails - */ - public Pack200CompressorOutputStream(final OutputStream out) - throws IOException { - this(out, Pack200Strategy.IN_MEMORY); - } - - /** - * Compresses the given stream using the given strategy to cache - * the results. - * - * @param out the stream to write to - * @param mode the strategy to use - * @throws IOException if writing fails - */ - public Pack200CompressorOutputStream(final OutputStream out, - final Pack200Strategy mode) - throws IOException { - this(out, mode, null); - } - - /** - * Compresses the given stream, caching the compressed data in - * memory and using the given properties. - * - * @param out the stream to write to - * @param props Pack200 properties to use - * @throws IOException if writing fails - */ - public Pack200CompressorOutputStream(final OutputStream out, - final Map props) - throws IOException { - this(out, Pack200Strategy.IN_MEMORY, props); - } - - /** - * Compresses the given stream using the given strategy to cache - * the results and the given properties. - * - * @param out the stream to write to - * @param mode the strategy to use - * @param props Pack200 properties to use - * @throws IOException if writing fails - */ - public Pack200CompressorOutputStream(final OutputStream out, - final Pack200Strategy mode, - final Map props) - throws IOException { - originalOutput = out; - streamBridge = mode.newStreamBridge(); - properties = props; - } - - @Override - public void write(final int b) throws IOException { - streamBridge.write(b); - } - - @Override - public void write(final byte[] b) throws IOException { - streamBridge.write(b); - } - - @Override - public void write(final byte[] b, final int from, final int length) throws IOException { - streamBridge.write(b, from, length); - } - - @Override - public void close() throws IOException { - finish(); - try { - streamBridge.stop(); - } finally { - originalOutput.close(); - } - } - - public void finish() throws IOException { - if (!finished) { - finished = true; - final Pack200.Packer p = Pack200.newPacker(); - if (properties != null) { - p.properties().putAll(properties); - } - try (JarInputStream ji = new JarInputStream(streamBridge.getInput())) { - p.pack(ji, originalOutput); - } - } - } -} diff --git a/src/org/apache/commons/compress/compressors/pack200/Pack200Strategy.java b/src/org/apache/commons/compress/compressors/pack200/Pack200Strategy.java deleted file mode 100644 index dba19929662..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/Pack200Strategy.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.pack200; - -import java.io.IOException; - -/** - * The different modes the Pack200 streams can use to wrap input and - * output. - * @since 1.3 - */ -public enum Pack200Strategy { - /** Cache output in memory */ - IN_MEMORY() { - @Override - StreamBridge newStreamBridge() { - return new InMemoryCachingStreamBridge(); - } - }, - /** Cache output in a temporary file */ - TEMP_FILE() { - @Override - StreamBridge newStreamBridge() throws IOException { - return new TempFileCachingStreamBridge(); - } - }; - - abstract StreamBridge newStreamBridge() throws IOException; -} \ No newline at end of file diff --git a/src/org/apache/commons/compress/compressors/pack200/Pack200Utils.java b/src/org/apache/commons/compress/compressors/pack200/Pack200Utils.java deleted file mode 100644 index 91a54ca5f93..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/Pack200Utils.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.pack200; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.jar.JarFile; -import java.util.jar.JarOutputStream; -import java.util.jar.Pack200; - -/** - * Utility methods for Pack200. - * - * @ThreadSafe - * @since 1.3 - */ -public class Pack200Utils { - private Pack200Utils() { } - - /** - * Normalizes a JAR archive in-place so it can be safely signed - * and packed. - * - *

As stated in Pack200.Packer's - * javadocs applying a Pack200 compression to a JAR archive will - * in general make its sigantures invalid. In order to prepare a - * JAR for signing it should be "normalized" by packing and - * unpacking it. This is what this method does.

- * - *

Note this methods implicitly sets the segment length to - * -1.

- * - * @param jar the JAR archive to normalize - * @throws IOException if reading or writing fails - */ - public static void normalize(final File jar) - throws IOException { - normalize(jar, jar, null); - } - - /** - * Normalizes a JAR archive in-place so it can be safely signed - * and packed. - * - *

As stated in Pack200.Packer's - * javadocs applying a Pack200 compression to a JAR archive will - * in general make its sigantures invalid. In order to prepare a - * JAR for signing it should be "normalized" by packing and - * unpacking it. This is what this method does.

- * - * @param jar the JAR archive to normalize - * @param props properties to set for the pack operation. This - * method will implicitly set the segment limit to -1. - * @throws IOException if reading or writing fails - */ - public static void normalize(final File jar, final Map props) - throws IOException { - normalize(jar, jar, props); - } - - /** - * Normalizes a JAR archive so it can be safely signed and packed. - * - *

As stated in Pack200.Packer's - * javadocs applying a Pack200 compression to a JAR archive will - * in general make its sigantures invalid. In order to prepare a - * JAR for signing it should be "normalized" by packing and - * unpacking it. This is what this method does.

- * - *

This method does not replace the existing archive but creates - * a new one.

- * - *

Note this methods implicitly sets the segment length to - * -1.

- * - * @param from the JAR archive to normalize - * @param to the normalized archive - * @throws IOException if reading or writing fails - */ - public static void normalize(final File from, final File to) - throws IOException { - normalize(from, to, null); - } - - /** - * Normalizes a JAR archive so it can be safely signed and packed. - * - *

As stated in Pack200.Packer's - * javadocs applying a Pack200 compression to a JAR archive will - * in general make its sigantures invalid. In order to prepare a - * JAR for signing it should be "normalized" by packing and - * unpacking it. This is what this method does.

- * - *

This method does not replace the existing archive but creates - * a new one.

- * - * @param from the JAR archive to normalize - * @param to the normalized archive - * @param props properties to set for the pack operation. This - * method will implicitly set the segment limit to -1. - * @throws IOException if reading or writing fails - */ - public static void normalize(final File from, final File to, Map props) - throws IOException { - if (props == null) { - props = new HashMap<>(); - } - props.put(Pack200.Packer.SEGMENT_LIMIT, "-1"); - final File tempFile = File.createTempFile("commons-compress", "pack200normalize"); - try { - try (FileOutputStream fos = new FileOutputStream(tempFile); - JarFile jarFile = new JarFile(from)) { - final Pack200.Packer packer = Pack200.newPacker(); - packer.properties().putAll(props); - packer.pack(jarFile, fos); - } - final Pack200.Unpacker unpacker = Pack200.newUnpacker(); - try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(to))) { - unpacker.unpack(tempFile, jos); - } - } finally { - if (!tempFile.delete()) { - tempFile.deleteOnExit(); - } - } - } -} diff --git a/src/org/apache/commons/compress/compressors/pack200/StreamBridge.java b/src/org/apache/commons/compress/compressors/pack200/StreamBridge.java deleted file mode 100644 index 9de3567cea9..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/StreamBridge.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.pack200; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Provides an InputStream to read all data written to this - * OutputStream. - * - * @ThreadSafe - * @since 1.3 - */ -abstract class StreamBridge extends FilterOutputStream { - private InputStream input; - private final Object inputLock = new Object(); - - protected StreamBridge(final OutputStream out) { - super(out); - } - - protected StreamBridge() { - this(null); - } - - /** - * Provides the input view. - */ - InputStream getInput() throws IOException { - synchronized (inputLock) { - if (input == null) { - input = getInputView(); - } - } - return input; - } - - /** - * Creates the input view. - */ - abstract InputStream getInputView() throws IOException; - - /** - * Closes input and output and releases all associated resources. - */ - void stop() throws IOException { - close(); - synchronized (inputLock) { - if (input != null) { - input.close(); - input = null; - } - } - } -} diff --git a/src/org/apache/commons/compress/compressors/pack200/TempFileCachingStreamBridge.java b/src/org/apache/commons/compress/compressors/pack200/TempFileCachingStreamBridge.java deleted file mode 100644 index dc612aa200e..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/TempFileCachingStreamBridge.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.compressors.pack200; - -import java.io.File; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; - -/** - * StreamSwitcher that caches all data written to the output side in - * a temporary file. - * @since 1.3 - */ -class TempFileCachingStreamBridge extends StreamBridge { - private final File f; - - TempFileCachingStreamBridge() throws IOException { - f = File.createTempFile("commons-compress", "packtemp"); - f.deleteOnExit(); - out = Files.newOutputStream(f.toPath()); - } - - @Override - InputStream getInputView() throws IOException { - out.close(); - return new FilterInputStream(Files.newInputStream(f.toPath())) { - @Override - public void close() throws IOException { - super.close(); - f.delete(); - } - }; - } -} diff --git a/src/org/apache/commons/compress/compressors/pack200/package.html b/src/org/apache/commons/compress/compressors/pack200/package.html deleted file mode 100644 index 9dbf2a065e1..00000000000 --- a/src/org/apache/commons/compress/compressors/pack200/package.html +++ /dev/null @@ -1,82 +0,0 @@ - - - -

Provides stream classes for compressing and decompressing - streams using the Pack200 algorithm used to compress Java - archives.

- -

The streams of this package only work on JAR archives, i.e. a - {@link - org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream - Pack200CompressorOutputStream} expects to be wrapped around a - stream that a valid JAR archive will be written to and a {@link - org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream - Pack200CompressorInputStream} provides a stream to read from a - JAR archive.

- -

JAR archives compressed with Pack200 will in general be - different from the original archive when decompressed again. - For details see - the API - documentation of Pack200.

- -

The streams of this package work on non-deflated streams, - i.e. archives like those created with the --no-gzip - option of the JDK's pack200 command line tool. If - you want to work on deflated streams you must use an additional - stream layer - for example by using Apache Commons Compress' - gzip package.

- -

The Pack200 API provided by the Java class library doesn't lend - itself to real stream - processing. Pack200CompressorInputStream will - uncompress its input immediately and then provide - an InputStream to a cached result. - Likewise Pack200CompressorOutputStream will not - write anything to the given OutputStream - until finish or close is called - at - which point the cached output written so far gets - compressed.

- -

Two different caching modes are available - "in memory", which - is the default, and "temporary file". By default data is cached - in memory but you should switch to the temporary file option if - your archives are really big.

- -

Given there always is an intermediate result - the getBytesRead and getCount methods - of Pack200CompressorInputStream are meaningless - (read from the real stream or from the intermediate result?) - and always return 0.

- -

During development of the initial version several attempts have - been made to use a real streaming API based for example - on Piped(In|Out)putStream or explicit stream - pumping like Commons Exec's InputStreamPumper but - they have all failed because they rely on the output end to be - consumed completely or else the (un)pack will block - forever. Especially for Pack200InputStream it is - very likely that it will be wrapped in - a ZipArchiveInputStream which will never read the - archive completely as it is not interested in the ZIP central - directory data at the end of the JAR archive.

- - - diff --git a/src/org/apache/commons/compress/compressors/package.html b/src/org/apache/commons/compress/compressors/package.html deleted file mode 100644 index 7b7d504b9cc..00000000000 --- a/src/org/apache/commons/compress/compressors/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides a unified API and factories for dealing with - compressed streams.

- - diff --git a/src/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java b/src/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java deleted file mode 100644 index 12974ab5597..00000000000 --- a/src/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.snappy; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.util.Arrays; - -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.BoundedInputStream; -import org.apache.commons.compress.utils.ByteUtils; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * CompressorInputStream for the framing Snappy format. - * - *

Based on the "spec" in the version "Last revised: 2013-10-25"

- * - * @see Snappy framing format description - * @since 1.7 - */ -public class FramedSnappyCompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - /** - * package private for tests only. - */ - static final long MASK_OFFSET = 0xa282ead8L; - - private static final int STREAM_IDENTIFIER_TYPE = 0xff; - static final int COMPRESSED_CHUNK_TYPE = 0; - private static final int UNCOMPRESSED_CHUNK_TYPE = 1; - private static final int PADDING_CHUNK_TYPE = 0xfe; - private static final int MIN_UNSKIPPABLE_TYPE = 2; - private static final int MAX_UNSKIPPABLE_TYPE = 0x7f; - private static final int MAX_SKIPPABLE_TYPE = 0xfd; - - // used by FramedSnappyCompressorOutputStream as well - static final byte[] SZ_SIGNATURE = new byte[] { //NOSONAR - (byte) STREAM_IDENTIFIER_TYPE, // tag - 6, 0, 0, // length - 's', 'N', 'a', 'P', 'p', 'Y' - }; - - private long unreadBytes; - private final CountingInputStream countingStream; - - /** The underlying stream to read compressed data from */ - private final PushbackInputStream in; - - /** The dialect to expect */ - private final FramedSnappyDialect dialect; - - private SnappyCompressorInputStream currentCompressedChunk; - - // used in no-arg read method - private final byte[] oneByte = new byte[1]; - - private boolean endReached, inUncompressedChunk; - - private int uncompressedBytesRemaining; - private long expectedChecksum = -1; - private final int blockSize; - private final PureJavaCrc32C checksum = new PureJavaCrc32C(); - - private final ByteUtils.ByteSupplier supplier = new ByteUtils.ByteSupplier() { - @Override - public int getAsByte() throws IOException { - return readOneByte(); - } - }; - - /** - * Constructs a new input stream that decompresses - * snappy-framed-compressed data from the specified input stream - * using the {@link FramedSnappyDialect#STANDARD} dialect. - * @param in the InputStream from which to read the compressed data - * @throws IOException if reading fails - */ - public FramedSnappyCompressorInputStream(final InputStream in) throws IOException { - this(in, FramedSnappyDialect.STANDARD); - } - - /** - * Constructs a new input stream that decompresses snappy-framed-compressed data - * from the specified input stream. - * @param in the InputStream from which to read the compressed data - * @param dialect the dialect used by the compressed stream - * @throws IOException if reading fails - */ - public FramedSnappyCompressorInputStream(final InputStream in, - final FramedSnappyDialect dialect) - throws IOException { - this(in, SnappyCompressorInputStream.DEFAULT_BLOCK_SIZE, dialect); - } - - /** - * Constructs a new input stream that decompresses snappy-framed-compressed data - * from the specified input stream. - * @param in the InputStream from which to read the compressed data - * @param blockSize the block size to use for the compressed stream - * @param dialect the dialect used by the compressed stream - * @throws IOException if reading fails - * @since 1.14 - */ - public FramedSnappyCompressorInputStream(final InputStream in, - final int blockSize, - final FramedSnappyDialect dialect) - throws IOException { - countingStream = new CountingInputStream(in); - this.in = new PushbackInputStream(countingStream, 1); - this.blockSize = blockSize; - this.dialect = dialect; - if (dialect.hasStreamIdentifier()) { - readStreamIdentifier(); - } - } - - /** {@inheritDoc} */ - @Override - public int read() throws IOException { - return read(oneByte, 0, 1) == -1 ? -1 : oneByte[0] & 0xFF; - } - - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - if (currentCompressedChunk != null) { - currentCompressedChunk.close(); - currentCompressedChunk = null; - } - in.close(); - } - - /** {@inheritDoc} */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - int read = readOnce(b, off, len); - if (read == -1) { - readNextBlock(); - if (endReached) { - return -1; - } - read = readOnce(b, off, len); - } - return read; - } - - /** {@inheritDoc} */ - @Override - public int available() throws IOException { - if (inUncompressedChunk) { - return Math.min(uncompressedBytesRemaining, - in.available()); - } else if (currentCompressedChunk != null) { - return currentCompressedChunk.available(); - } - return 0; - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return countingStream.getBytesRead() - unreadBytes; - } - - /** - * Read from the current chunk into the given array. - * - * @return -1 if there is no current chunk or the number of bytes - * read from the current chunk (which may be -1 if the end of the - * chunk is reached). - */ - private int readOnce(final byte[] b, final int off, final int len) throws IOException { - int read = -1; - if (inUncompressedChunk) { - final int amount = Math.min(uncompressedBytesRemaining, len); - if (amount == 0) { - return -1; - } - read = in.read(b, off, amount); - if (read != -1) { - uncompressedBytesRemaining -= read; - count(read); - } - } else if (currentCompressedChunk != null) { - final long before = currentCompressedChunk.getBytesRead(); - read = currentCompressedChunk.read(b, off, len); - if (read == -1) { - currentCompressedChunk.close(); - currentCompressedChunk = null; - } else { - count(currentCompressedChunk.getBytesRead() - before); - } - } - if (read > 0) { - checksum.update(b, off, read); - } - return read; - } - - private void readNextBlock() throws IOException { - verifyLastChecksumAndReset(); - inUncompressedChunk = false; - final int type = readOneByte(); - if (type == -1) { - endReached = true; - } else if (type == STREAM_IDENTIFIER_TYPE) { - in.unread(type); - unreadBytes++; - pushedBackBytes(1); - readStreamIdentifier(); - readNextBlock(); - } else if (type == PADDING_CHUNK_TYPE - || (type > MAX_UNSKIPPABLE_TYPE && type <= MAX_SKIPPABLE_TYPE)) { - skipBlock(); - readNextBlock(); - } else if (type >= MIN_UNSKIPPABLE_TYPE && type <= MAX_UNSKIPPABLE_TYPE) { - throw new IOException("unskippable chunk with type " + type - + " (hex " + Integer.toHexString(type) + ")" - + " detected."); - } else if (type == UNCOMPRESSED_CHUNK_TYPE) { - inUncompressedChunk = true; - uncompressedBytesRemaining = readSize() - 4 /* CRC */; - expectedChecksum = unmask(readCrc()); - } else if (type == COMPRESSED_CHUNK_TYPE) { - final boolean expectChecksum = dialect.usesChecksumWithCompressedChunks(); - final long size = readSize() - (expectChecksum ? 4L : 0L); - if (expectChecksum) { - expectedChecksum = unmask(readCrc()); - } else { - expectedChecksum = -1; - } - currentCompressedChunk = - new SnappyCompressorInputStream(new BoundedInputStream(in, size), blockSize); - // constructor reads uncompressed size - count(currentCompressedChunk.getBytesRead()); - } else { - // impossible as all potential byte values have been covered - throw new IOException("unknown chunk type " + type - + " detected."); - } - } - - private long readCrc() throws IOException { - final byte[] b = new byte[4]; - final int read = IOUtils.readFully(in, b); - count(read); - if (read != 4) { - throw new IOException("premature end of stream"); - } - return ByteUtils.fromLittleEndian(b); - } - - static long unmask(long x) { - // ugly, maybe we should just have used ints and deal with the - // overflow - x -= MASK_OFFSET; - x &= 0xffffFFFFL; - return ((x >> 17) | (x << 15)) & 0xffffFFFFL; - } - - private int readSize() throws IOException { - return (int) ByteUtils.fromLittleEndian(supplier, 3); - } - - private void skipBlock() throws IOException { - final int size = readSize(); - final long read = IOUtils.skip(in, size); - count(read); - if (read != size) { - throw new IOException("premature end of stream"); - } - } - - private void readStreamIdentifier() throws IOException { - final byte[] b = new byte[10]; - final int read = IOUtils.readFully(in, b); - count(read); - if (10 != read || !matches(b, 10)) { - throw new IOException("Not a framed Snappy stream"); - } - } - - private int readOneByte() throws IOException { - final int b = in.read(); - if (b != -1) { - count(1); - return b & 0xFF; - } - return -1; - } - - private void verifyLastChecksumAndReset() throws IOException { - if (expectedChecksum >= 0 && expectedChecksum != checksum.getValue()) { - throw new IOException("Checksum verification failed"); - } - expectedChecksum = -1; - checksum.reset(); - } - - /** - * Checks if the signature matches what is expected for a .sz file. - * - *

.sz files start with a chunk with tag 0xff and content sNaPpY.

- * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true if this is a .sz stream, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - - if (length < SZ_SIGNATURE.length) { - return false; - } - - byte[] shortenedSig = signature; - if (signature.length > SZ_SIGNATURE.length) { - shortenedSig = new byte[SZ_SIGNATURE.length]; - System.arraycopy(signature, 0, shortenedSig, 0, SZ_SIGNATURE.length); - } - - return Arrays.equals(shortenedSig, SZ_SIGNATURE); - } - -} diff --git a/src/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorOutputStream.java b/src/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorOutputStream.java deleted file mode 100644 index 08cd619010d..00000000000 --- a/src/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorOutputStream.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.snappy; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; -import org.apache.commons.compress.compressors.lz77support.Parameters; -import org.apache.commons.compress.utils.ByteUtils; - -/** - * CompressorOutputStream for the framing Snappy format. - * - *

Based on the "spec" in the version "Last revised: 2013-10-25"

- * - * @see Snappy framing format description - * @since 1.14 - * @NotThreadSafe - */ -public class FramedSnappyCompressorOutputStream extends CompressorOutputStream { - // see spec: - // > However, we place an additional restriction that the uncompressed data - // > in a chunk must be no longer than 65536 bytes. This allows consumers to - // > easily use small fixed-size buffers. - private static final int MAX_COMPRESSED_BUFFER_SIZE = 1 << 16; - - private final OutputStream out; - private final Parameters params; - private final PureJavaCrc32C checksum = new PureJavaCrc32C(); - // used in one-arg write method - private final byte[] oneByte = new byte[1]; - private final byte[] buffer = new byte[MAX_COMPRESSED_BUFFER_SIZE]; - private int currentIndex = 0; - - private final ByteUtils.ByteConsumer consumer; - - /** - * Constructs a new output stream that compresses - * snappy-framed-compressed data to the specified output stream. - * @param out the OutputStream to which to write the compressed data - * @throws IOException if writing the signature fails - */ - public FramedSnappyCompressorOutputStream(final OutputStream out) throws IOException { - this(out, SnappyCompressorOutputStream.createParameterBuilder(SnappyCompressorInputStream.DEFAULT_BLOCK_SIZE) - .build()); - } - - /** - * Constructs a new output stream that compresses - * snappy-framed-compressed data to the specified output stream. - * @param out the OutputStream to which to write the compressed data - * @param params parameters used to fine-tune compression, in - * particular to balance compression ratio vs compression speed. - * @throws IOException if writing the signature fails - */ - public FramedSnappyCompressorOutputStream(final OutputStream out, Parameters params) throws IOException { - this.out = out; - this.params = params; - consumer = new ByteUtils.OutputStreamByteConsumer(out); - out.write(FramedSnappyCompressorInputStream.SZ_SIGNATURE); - } - - @Override - public void write(int b) throws IOException { - oneByte[0] = (byte) (b & 0xff); - write(oneByte); - } - - @Override - public void write(byte[] data, int off, int len) throws IOException { - if (currentIndex + len > MAX_COMPRESSED_BUFFER_SIZE) { - flushBuffer(); - while (len > MAX_COMPRESSED_BUFFER_SIZE) { - System.arraycopy(data, off, buffer, 0, MAX_COMPRESSED_BUFFER_SIZE); - off += MAX_COMPRESSED_BUFFER_SIZE; - len -= MAX_COMPRESSED_BUFFER_SIZE; - currentIndex = MAX_COMPRESSED_BUFFER_SIZE; - flushBuffer(); - } - } - System.arraycopy(data, off, buffer, currentIndex, len); - currentIndex += len; - } - - @Override - public void close() throws IOException { - finish(); - out.close(); - } - - /** - * Compresses all remaining data and writes it to the stream, - * doesn't close the underlying stream. - * @throws IOException if an error occurs - */ - public void finish() throws IOException { - if (currentIndex > 0) { - flushBuffer(); - } - } - - private void flushBuffer() throws IOException { - out.write(FramedSnappyCompressorInputStream.COMPRESSED_CHUNK_TYPE); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (OutputStream o = new SnappyCompressorOutputStream(baos, currentIndex, params)) { - o.write(buffer, 0, currentIndex); - } - byte[] b = baos.toByteArray(); - writeLittleEndian(3, b.length + 4L /* CRC */); - writeCrc(); - out.write(b); - currentIndex = 0; - } - - private void writeLittleEndian(final int numBytes, long num) throws IOException { - ByteUtils.toLittleEndian(consumer, num, numBytes); - } - - private void writeCrc() throws IOException { - checksum.update(buffer, 0, currentIndex); - writeLittleEndian(4, mask(checksum.getValue())); - checksum.reset(); - } - - static long mask(long x) { - // ugly, maybe we should just have used ints and deal with the - // overflow - x = ((x >> 15) | (x << 17)); - x += FramedSnappyCompressorInputStream.MASK_OFFSET; - x &= 0xffffFFFFL; - return x; - } -} diff --git a/src/org/apache/commons/compress/compressors/snappy/FramedSnappyDialect.java b/src/org/apache/commons/compress/compressors/snappy/FramedSnappyDialect.java deleted file mode 100644 index b83b7a50914..00000000000 --- a/src/org/apache/commons/compress/compressors/snappy/FramedSnappyDialect.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.snappy; - -/** - * Dialects of the framing format that {@link FramedSnappyCompressorInputStream} can deal with. - * @since 1.12 - */ -public enum FramedSnappyDialect { - /** - * The standard as defined by the Snappy - * framing format description - */ - STANDARD(true, true), - /** - * The format used by Apple's iWork Archives (.iwa files). - */ - IWORK_ARCHIVE(false, false); - - private final boolean streamIdentifier, checksumWithCompressedChunks; - - FramedSnappyDialect(final boolean hasStreamIdentifier, - final boolean usesChecksumWithCompressedChunks) { - this.streamIdentifier = hasStreamIdentifier; - this.checksumWithCompressedChunks = usesChecksumWithCompressedChunks; - } - - boolean hasStreamIdentifier() { - return streamIdentifier; - } - - boolean usesChecksumWithCompressedChunks() { - return checksumWithCompressedChunks; - } -} diff --git a/src/org/apache/commons/compress/compressors/snappy/PureJavaCrc32C.java b/src/org/apache/commons/compress/compressors/snappy/PureJavaCrc32C.java deleted file mode 100644 index 4c9738b912b..00000000000 --- a/src/org/apache/commons/compress/compressors/snappy/PureJavaCrc32C.java +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Some portions of this file Copyright (c) 2004-2006 Intel Corportation - * and licensed under the BSD license. - */ -package org.apache.commons.compress.compressors.snappy; - -import java.util.zip.Checksum; - -/** - * A pure-java implementation of the CRC32 checksum that uses - * the CRC32-C polynomial, the same polynomial used by iSCSI - * and implemented on many Intel chipsets supporting SSE4.2. - * - *

This file is a copy of the implementation at the Apache Hadoop project.

- * @see "https://svn.apache.org/repos/asf/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/PureJavaCrc32C.java" - * @NotThreadSafe - * @since 1.7 - */ -final class PureJavaCrc32C implements Checksum { - - /** the current CRC value, bit-flipped */ - private int crc; - - /** Create a new PureJavaCrc32 object. */ - public PureJavaCrc32C() { - reset(); // non-private, but the class is now final - } - - @Override - public long getValue() { - final long ret = crc; - return (~ret) & 0xffffffffL; - } - - @Override - // called by ctor but the class is final so this is safe - public void reset() { - crc = 0xffffffff; - } - - @Override - public void update(final byte[] b, int off, int len) { - int localCrc = crc; - - while(len > 7) { - final int c0 =(b[off+0] ^ localCrc) & 0xff; - final int c1 =(b[off+1] ^ (localCrc >>>= 8)) & 0xff; //NOSONAR - final int c2 =(b[off+2] ^ (localCrc >>>= 8)) & 0xff; //NOSONAR - final int c3 =(b[off+3] ^ (localCrc >>>= 8)) & 0xff; //NOSONAR - localCrc = (T[T8_7_START + c0] ^ T[T8_6_START + c1]) - ^ (T[T8_5_START + c2] ^ T[T8_4_START + c3]); - - final int c4 = b[off+4] & 0xff; - final int c5 = b[off+5] & 0xff; - final int c6 = b[off+6] & 0xff; - final int c7 = b[off+7] & 0xff; - - localCrc ^= (T[T8_3_START + c4] ^ T[T8_2_START + c5]) - ^ (T[T8_1_START + c6] ^ T[T8_0_START + c7]); - - off += 8; - len -= 8; - } - - /* loop unroll - duff's device style */ - switch(len) { - case 7: localCrc = (localCrc >>> 8) ^ T[T8_0_START + ((localCrc ^ b[off++]) & 0xff)]; - case 6: localCrc = (localCrc >>> 8) ^ T[T8_0_START + ((localCrc ^ b[off++]) & 0xff)]; - case 5: localCrc = (localCrc >>> 8) ^ T[T8_0_START + ((localCrc ^ b[off++]) & 0xff)]; - case 4: localCrc = (localCrc >>> 8) ^ T[T8_0_START + ((localCrc ^ b[off++]) & 0xff)]; - case 3: localCrc = (localCrc >>> 8) ^ T[T8_0_START + ((localCrc ^ b[off++]) & 0xff)]; - case 2: localCrc = (localCrc >>> 8) ^ T[T8_0_START + ((localCrc ^ b[off++]) & 0xff)]; - case 1: localCrc = (localCrc >>> 8) ^ T[T8_0_START + ((localCrc ^ b[off++]) & 0xff)]; - default: - /* nothing */ - } - - // Publish crc out to object - crc = localCrc; - } - - @Override - final public void update(final int b) { - crc = (crc >>> 8) ^ T[T8_0_START + ((crc ^ b) & 0xff)]; - } - - // CRC polynomial tables generated by: - // java -cp build/test/classes/:build/classes/ \ - // org.apache.hadoop.util.TestPureJavaCrc32\$Table 82F63B78 - - private static final int T8_0_START = 0*256; - private static final int T8_1_START = 1*256; - private static final int T8_2_START = 2*256; - private static final int T8_3_START = 3*256; - private static final int T8_4_START = 4*256; - private static final int T8_5_START = 5*256; - private static final int T8_6_START = 6*256; - private static final int T8_7_START = 7*256; - - private static final int[] T = new int[] { - /* T8_0 */ - 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, - 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, - 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, - 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, - 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, - 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, - 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, - 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, - 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, - 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, - 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, - 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, - 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, - 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, - 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, - 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, - 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, - 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, - 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, - 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, - 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, - 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, - 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, - 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, - 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, - 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, - 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, - 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, - 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, - 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, - 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, - 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, - 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, - /* T8_1 */ - 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, - 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, - 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, - 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, - 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, - 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, - 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, - 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, - 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, - 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, - 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, - 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, - 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, - 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, - 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, - 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, - 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, - 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, - 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, - 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, - 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, - 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, - 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, - 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, - 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, - 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, - 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, - 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, - 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, - 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, - 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, - 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, - 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, - 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, - 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, - 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, - 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, - 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, - 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, - 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, - 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, - 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, - 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, - 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, - 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, - 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, - 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, - 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, - 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, - 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, - 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, - 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, - 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, - 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, - 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, - 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, - 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, - 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, - 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, - 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, - 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, - 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, - 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, - 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483, - /* T8_2 */ - 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, - 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, - 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, - 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, - 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, - 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, - 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, - 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, - 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, - 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, - 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, - 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, - 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, - 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, - 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, - 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, - 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, - 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, - 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, - 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, - 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, - 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, - 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, - 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, - 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, - 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, - 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, - 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, - 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, - 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, - 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, - 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, - 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, - 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, - 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, - 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, - 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, - 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, - 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, - 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, - 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, - 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, - 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, - 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, - 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, - 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, - 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, - 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, - 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, - 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, - 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, - 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, - 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, - 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, - 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, - 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, - 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, - 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, - 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, - 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, - 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, - 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, - 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, - 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8, - /* T8_3 */ - 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, - 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, - 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, - 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, - 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, - 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, - 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, - 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, - 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, - 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, - 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, - 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, - 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, - 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, - 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, - 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, - 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, - 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, - 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, - 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, - 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, - 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, - 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, - 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, - 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, - 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, - 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, - 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, - 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, - 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, - 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, - 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, - 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, - 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, - 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, - 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, - 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, - 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, - 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, - 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, - 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, - 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, - 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, - 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, - 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, - 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, - 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, - 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, - 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, - 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, - 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, - 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, - 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, - 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, - 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, - 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, - 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, - 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, - 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, - 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, - 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, - 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, - 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, - 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842, - /* T8_4 */ - 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, - 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, - 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, - 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, - 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, - 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, - 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, - 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, - 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, - 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, - 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, - 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, - 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, - 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, - 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, - 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, - 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, - 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, - 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, - 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, - 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, - 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, - 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, - 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, - 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, - 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, - 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, - 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, - 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, - 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, - 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, - 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, - 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, - 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, - 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, - 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, - 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, - 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, - 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, - 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, - 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, - 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, - 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, - 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, - 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, - 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, - 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, - 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, - 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, - 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, - 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, - 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, - 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, - 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, - 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, - 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, - 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, - 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, - 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, - 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, - 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, - 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, - 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, - 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3, - /* T8_5 */ - 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, - 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, - 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, - 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, - 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, - 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, - 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, - 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, - 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, - 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, - 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, - 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, - 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, - 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, - 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, - 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, - 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, - 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, - 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, - 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, - 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, - 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, - 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, - 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, - 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, - 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, - 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, - 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, - 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, - 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, - 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, - 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, - 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, - 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, - 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, - 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, - 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, - 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, - 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, - 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, - 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, - 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, - 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, - 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, - 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, - 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, - 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, - 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, - 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, - 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, - 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, - 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, - 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, - 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, - 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, - 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, - 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, - 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, - 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, - 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, - 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, - 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, - 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, - 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C, - /* T8_6 */ - 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, - 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, - 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, - 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, - 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, - 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, - 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, - 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, - 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, - 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, - 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, - 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, - 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, - 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, - 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, - 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, - 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, - 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, - 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, - 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, - 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, - 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, - 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, - 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, - 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, - 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, - 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, - 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, - 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, - 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, - 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, - 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, - 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, - 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, - 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, - 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, - 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, - 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, - 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, - 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, - 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, - 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, - 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, - 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, - 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, - 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, - 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, - 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, - 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, - 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, - 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, - 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, - 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, - 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, - 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, - 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, - 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, - 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, - 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, - 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, - 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, - 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, - 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, - 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F, - /* T8_7 */ - 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, - 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, - 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, - 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, - 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, - 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, - 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, - 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, - 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, - 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, - 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, - 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, - 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, - 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, - 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, - 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, - 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, - 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, - 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, - 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, - 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, - 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, - 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, - 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, - 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, - 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, - 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, - 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, - 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, - 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, - 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, - 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, - 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, - 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, - 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, - 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, - 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, - 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, - 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, - 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, - 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, - 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, - 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, - 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, - 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, - 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, - 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, - 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, - 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, - 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, - 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, - 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, - 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, - 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, - 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, - 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, - 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, - 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, - 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, - 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, - 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, - 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, - 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, - 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 - }; -} diff --git a/src/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java b/src/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java deleted file mode 100644 index 4650cb865f6..00000000000 --- a/src/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.snappy; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.compress.compressors.lz77support.AbstractLZ77CompressorInputStream; -import org.apache.commons.compress.utils.ByteUtils; - -/** - * CompressorInputStream for the raw Snappy format. - * - *

This implementation uses an internal buffer in order to handle - * the back-references that are at the heart of the LZ77 algorithm. - * The size of the buffer must be at least as big as the biggest - * offset used in the compressed stream. The current version of the - * Snappy algorithm as defined by Google works on 32k blocks and - * doesn't contain offsets bigger than 32k which is the default block - * size used by this class.

- * - * @see Snappy compressed format description - * @since 1.7 - */ -public class SnappyCompressorInputStream extends AbstractLZ77CompressorInputStream { - - /** Mask used to determine the type of "tag" is being processed */ - private static final int TAG_MASK = 0x03; - - /** Default block size */ - public static final int DEFAULT_BLOCK_SIZE = 32768; - - /** The size of the uncompressed data */ - private final int size; - - /** Number of uncompressed bytes still to be read. */ - private int uncompressedBytesRemaining; - - /** Current state of the stream */ - private State state = State.NO_BLOCK; - - private boolean endReached = false; - - /** - * Constructor using the default buffer size of 32k. - * - * @param is - * An InputStream to read compressed data from - * - * @throws IOException if reading fails - */ - public SnappyCompressorInputStream(final InputStream is) throws IOException { - this(is, DEFAULT_BLOCK_SIZE); - } - - /** - * Constructor using a configurable buffer size. - * - * @param is - * An InputStream to read compressed data from - * @param blockSize - * The block size used in compression - * - * @throws IOException if reading fails - */ - public SnappyCompressorInputStream(final InputStream is, final int blockSize) - throws IOException { - super(is, blockSize); - uncompressedBytesRemaining = size = (int) readSize(); - } - - /** - * {@inheritDoc} - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (endReached) { - return -1; - } - switch (state) { - case NO_BLOCK: - fill(); - return read(b, off, len); - case IN_LITERAL: - int litLen = readLiteral(b, off, len); - if (!hasMoreDataInBlock()) { - state = State.NO_BLOCK; - } - return litLen > 0 ? litLen : read(b, off, len); - case IN_BACK_REFERENCE: - int backReferenceLen = readBackReference(b, off, len); - if (!hasMoreDataInBlock()) { - state = State.NO_BLOCK; - } - return backReferenceLen > 0 ? backReferenceLen : read(b, off, len); - default: - throw new IOException("Unknown stream state " + state); - } - } - - /** - * Try to fill the buffer with the next block of data. - */ - private void fill() throws IOException { - if (uncompressedBytesRemaining == 0) { - endReached = true; - return; - } - - int b = readOneByte(); - if (b == -1) { - throw new IOException("Premature end of stream reading block start"); - } - int length = 0; - int offset = 0; - - switch (b & TAG_MASK) { - - case 0x00: - - length = readLiteralLength(b); - uncompressedBytesRemaining -= length; - startLiteral(length); - state = State.IN_LITERAL; - break; - - case 0x01: - - /* - * These elements can encode lengths between [4..11] bytes and - * offsets between [0..2047] bytes. (len-4) occupies three bits - * and is stored in bits [2..4] of the tag byte. The offset - * occupies 11 bits, of which the upper three are stored in the - * upper three bits ([5..7]) of the tag byte, and the lower - * eight are stored in a byte following the tag byte. - */ - - length = 4 + ((b >> 2) & 0x07); - uncompressedBytesRemaining -= length; - offset = (b & 0xE0) << 3; - b = readOneByte(); - if (b == -1) { - throw new IOException("Premature end of stream reading back-reference length"); - } - offset |= b; - - startBackReference(offset, length); - state = State.IN_BACK_REFERENCE; - break; - - case 0x02: - - /* - * These elements can encode lengths between [1..64] and offsets - * from [0..65535]. (len-1) occupies six bits and is stored in - * the upper six bits ([2..7]) of the tag byte. The offset is - * stored as a little-endian 16-bit integer in the two bytes - * following the tag byte. - */ - - length = (b >> 2) + 1; - uncompressedBytesRemaining -= length; - - offset = (int) ByteUtils.fromLittleEndian(supplier, 2); - - startBackReference(offset, length); - state = State.IN_BACK_REFERENCE; - break; - - case 0x03: - - /* - * These are like the copies with 2-byte offsets (see previous - * subsection), except that the offset is stored as a 32-bit - * integer instead of a 16-bit integer (and thus will occupy - * four bytes). - */ - - length = (b >> 2) + 1; - uncompressedBytesRemaining -= length; - - offset = (int) ByteUtils.fromLittleEndian(supplier, 4) & 0x7fffffff; - - startBackReference(offset, length); - state = State.IN_BACK_REFERENCE; - break; - default: - // impossible as TAG_MASK is two bits and all four possible cases have been covered - break; - } - } - - /* - * For literals up to and including 60 bytes in length, the - * upper six bits of the tag byte contain (len-1). The literal - * follows immediately thereafter in the bytestream. - For - * longer literals, the (len-1) value is stored after the tag - * byte, little-endian. The upper six bits of the tag byte - * describe how many bytes are used for the length; 60, 61, 62 - * or 63 for 1-4 bytes, respectively. The literal itself follows - * after the length. - */ - private int readLiteralLength(final int b) throws IOException { - int length; - switch (b >> 2) { - case 60: - length = readOneByte(); - if (length == -1) { - throw new IOException("Premature end of stream reading literal length"); - } - break; - case 61: - length = (int) ByteUtils.fromLittleEndian(supplier, 2); - break; - case 62: - length = (int) ByteUtils.fromLittleEndian(supplier, 3); - break; - case 63: - length = (int) ByteUtils.fromLittleEndian(supplier, 4); - break; - default: - length = b >> 2; - break; - } - - return length + 1; - } - - /** - * The stream starts with the uncompressed length (up to a maximum of 2^32 - - * 1), stored as a little-endian varint. Varints consist of a series of - * bytes, where the lower 7 bits are data and the upper bit is set iff there - * are more bytes to be read. In other words, an uncompressed length of 64 - * would be stored as 0x40, and an uncompressed length of 2097150 (0x1FFFFE) - * would be stored as 0xFE 0xFF 0x7F. - * - * @return The size of the uncompressed data - * - * @throws IOException - * Could not read a byte - */ - private long readSize() throws IOException { - int index = 0; - long sz = 0; - int b = 0; - - do { - b = readOneByte(); - if (b == -1) { - throw new IOException("Premature end of stream reading size"); - } - sz |= (b & 0x7f) << (index++ * 7); - } while (0 != (b & 0x80)); - return sz; - } - - /** - * Get the uncompressed size of the stream - * - * @return the uncompressed size - */ - @Override - public int getSize() { - return size; - } - - private enum State { - NO_BLOCK, IN_LITERAL, IN_BACK_REFERENCE - } -} diff --git a/src/org/apache/commons/compress/compressors/snappy/SnappyCompressorOutputStream.java b/src/org/apache/commons/compress/compressors/snappy/SnappyCompressorOutputStream.java deleted file mode 100644 index 93a9d80f9e8..00000000000 --- a/src/org/apache/commons/compress/compressors/snappy/SnappyCompressorOutputStream.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.snappy; - -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; -import org.apache.commons.compress.compressors.lz77support.LZ77Compressor; -import org.apache.commons.compress.compressors.lz77support.Parameters; -import org.apache.commons.compress.utils.ByteUtils; - -/** - * CompressorOutputStream for the raw Snappy format. - * - *

This implementation uses an internal buffer in order to handle - * the back-references that are at the heart of the LZ77 algorithm. - * The size of the buffer must be at least as big as the biggest - * offset used in the compressed stream. The current version of the - * Snappy algorithm as defined by Google works on 32k blocks and - * doesn't contain offsets bigger than 32k which is the default block - * size used by this class.

- * - *

The raw Snappy format requires the uncompressed size to be - * written at the beginning of the stream using a varint - * representation, i.e. the number of bytes needed to write the - * information is not known before the uncompressed size is - * known. We've chosen to make the uncompressedSize a parameter of the - * constructor in favor of buffering the whole output until the size - * is known. When using the {@link FramedSnappyCompressorOutputStream} - * this limitation is taken care of by the warpping framing - * format.

- * - * @see Snappy compressed format description - * @since 1.14 - * @NotThreadSafe - */ -public class SnappyCompressorOutputStream extends CompressorOutputStream { - private final LZ77Compressor compressor; - private final OutputStream os; - private final ByteUtils.ByteConsumer consumer; - - // used in one-arg write method - private final byte[] oneByte = new byte[1]; - - private boolean finished = false; - - /** - * Constructor using the default block size of 32k. - * - * @param os the outputstream to write compressed data to - * @param uncompressedSize the uncompressed size of data - * @throws IOException if writing of the size fails - */ - public SnappyCompressorOutputStream(final OutputStream os, final long uncompressedSize) throws IOException { - this(os, uncompressedSize, SnappyCompressorInputStream.DEFAULT_BLOCK_SIZE); - } - - /** - * Constructor using a configurable block size. - * - * @param os the outputstream to write compressed data to - * @param uncompressedSize the uncompressed size of data - * @param blockSize the block size used - must be a power of two - * @throws IOException if writing of the size fails - */ - public SnappyCompressorOutputStream(final OutputStream os, final long uncompressedSize, final int blockSize) - throws IOException { - this(os, uncompressedSize, createParameterBuilder(blockSize).build()); - } - - /** - * Constructor providing full control over the underlying LZ77 compressor. - * - * @param os the outputstream to write compressed data to - * @param uncompressedSize the uncompressed size of data - * @param params the parameters to use by the compressor - note - * that the format itself imposes some limits like a maximum match - * length of 64 bytes - * @throws IOException if writing of the size fails - */ - public SnappyCompressorOutputStream(final OutputStream os, final long uncompressedSize, Parameters params) - throws IOException { - this.os = os; - consumer = new ByteUtils.OutputStreamByteConsumer(os); - compressor = new LZ77Compressor(params, new LZ77Compressor.Callback() { - @Override - public void accept(LZ77Compressor.Block block) throws IOException { - switch (block.getType()) { - case LITERAL: - writeLiteralBlock((LZ77Compressor.LiteralBlock) block); - break; - case BACK_REFERENCE: - writeBackReference((LZ77Compressor.BackReference) block); - break; - case EOD: - break; - } - } - }); - writeUncompressedSize(uncompressedSize); - } - - @Override - public void write(int b) throws IOException { - oneByte[0] = (byte) (b & 0xff); - write(oneByte); - } - - @Override - public void write(byte[] data, int off, int len) throws IOException { - compressor.compress(data, off, len); - } - - @Override - public void close() throws IOException { - finish(); - os.close(); - } - - /** - * Compresses all remaining data and writes it to the stream, - * doesn't close the underlying stream. - * @throws IOException if an error occurs - */ - public void finish() throws IOException { - if (!finished) { - compressor.finish(); - finished = true; - } - } - - private void writeUncompressedSize(long uncompressedSize) throws IOException { - boolean more = false; - do { - int currentByte = (int) (uncompressedSize & 0x7F); - more = uncompressedSize > currentByte; - if (more) { - currentByte |= 0x80; - } - os.write(currentByte); - uncompressedSize >>= 7; - } while (more); - } - - // literal length is stored as (len - 1) either inside the tag - // (six bits minus four flags) or in 1 to 4 bytes after the tag - private static final int MAX_LITERAL_SIZE_WITHOUT_SIZE_BYTES = 60; - private static final int MAX_LITERAL_SIZE_WITH_ONE_SIZE_BYTE = 1 << 8; - private static final int MAX_LITERAL_SIZE_WITH_TWO_SIZE_BYTES = 1 << 16; - private static final int MAX_LITERAL_SIZE_WITH_THREE_SIZE_BYTES = 1 << 24; - - private static final int ONE_SIZE_BYTE_MARKER = 60 << 2; - private static final int TWO_SIZE_BYTE_MARKER = 61 << 2; - private static final int THREE_SIZE_BYTE_MARKER = 62 << 2; - private static final int FOUR_SIZE_BYTE_MARKER = 63 << 2; - - private void writeLiteralBlock(LZ77Compressor.LiteralBlock block) throws IOException { - int len = block.getLength(); - if (len <= MAX_LITERAL_SIZE_WITHOUT_SIZE_BYTES) { - writeLiteralBlockNoSizeBytes(block, len); - } else if (len <= MAX_LITERAL_SIZE_WITH_ONE_SIZE_BYTE) { - writeLiteralBlockOneSizeByte(block, len); - } else if (len <= MAX_LITERAL_SIZE_WITH_TWO_SIZE_BYTES) { - writeLiteralBlockTwoSizeBytes(block, len); - } else if (len <= MAX_LITERAL_SIZE_WITH_THREE_SIZE_BYTES) { - writeLiteralBlockThreeSizeBytes(block, len); - } else { - writeLiteralBlockFourSizeBytes(block, len); - } - } - - private void writeLiteralBlockNoSizeBytes(LZ77Compressor.LiteralBlock block, int len) throws IOException { - writeLiteralBlockWithSize(len - 1 << 2, 0, len, block); - } - - private void writeLiteralBlockOneSizeByte(LZ77Compressor.LiteralBlock block, int len) throws IOException { - writeLiteralBlockWithSize(ONE_SIZE_BYTE_MARKER, 1, len, block); - } - - private void writeLiteralBlockTwoSizeBytes(LZ77Compressor.LiteralBlock block, int len) throws IOException { - writeLiteralBlockWithSize(TWO_SIZE_BYTE_MARKER, 2, len, block); - } - - private void writeLiteralBlockThreeSizeBytes(LZ77Compressor.LiteralBlock block, int len) throws IOException { - writeLiteralBlockWithSize(THREE_SIZE_BYTE_MARKER, 3, len, block); - } - - private void writeLiteralBlockFourSizeBytes(LZ77Compressor.LiteralBlock block, int len) throws IOException { - writeLiteralBlockWithSize(FOUR_SIZE_BYTE_MARKER, 4, len, block); - } - - private void writeLiteralBlockWithSize(int tagByte, int sizeBytes, int len, LZ77Compressor.LiteralBlock block) - throws IOException { - os.write(tagByte); - writeLittleEndian(sizeBytes, len - 1); - os.write(block.getData(), block.getOffset(), len); - } - - private void writeLittleEndian(final int numBytes, int num) throws IOException { - ByteUtils.toLittleEndian(consumer, num, numBytes); - } - - // Back-references ("copies") have their offset/size information - // in two, three or five bytes. - private static final int MIN_MATCH_LENGTH_WITH_ONE_OFFSET_BYTE = 4; - private static final int MAX_MATCH_LENGTH_WITH_ONE_OFFSET_BYTE = 11; - private static final int MAX_OFFSET_WITH_ONE_OFFSET_BYTE = 1 << 11 - 1; - private static final int MAX_OFFSET_WITH_TWO_OFFSET_BYTES = 1 << 16 - 1; - - private static final int ONE_BYTE_COPY_TAG = 1; - private static final int TWO_BYTE_COPY_TAG = 2; - private static final int FOUR_BYTE_COPY_TAG = 3; - - private void writeBackReference(LZ77Compressor.BackReference block) throws IOException { - final int len = block.getLength(); - final int offset = block.getOffset(); - if (len >= MIN_MATCH_LENGTH_WITH_ONE_OFFSET_BYTE && len <= MAX_MATCH_LENGTH_WITH_ONE_OFFSET_BYTE - && offset <= MAX_OFFSET_WITH_ONE_OFFSET_BYTE) { - writeBackReferenceWithOneOffsetByte(len, offset); - } else if (offset < MAX_OFFSET_WITH_TWO_OFFSET_BYTES) { - writeBackReferenceWithTwoOffsetBytes(len, offset); - } else { - writeBackReferenceWithFourOffsetBytes(len, offset); - } - } - - private void writeBackReferenceWithOneOffsetByte(int len, int offset) throws IOException { - os.write(ONE_BYTE_COPY_TAG | ((len - 4) << 2) | ((offset & 0x700) >> 3)); - os.write(offset & 0xff); - } - - private void writeBackReferenceWithTwoOffsetBytes(int len, int offset) throws IOException { - writeBackReferenceWithLittleEndianOffset(TWO_BYTE_COPY_TAG, 2, len, offset); - } - - private void writeBackReferenceWithFourOffsetBytes(int len, int offset) throws IOException { - writeBackReferenceWithLittleEndianOffset(FOUR_BYTE_COPY_TAG, 4, len, offset); - } - - private void writeBackReferenceWithLittleEndianOffset(int tag, int offsetBytes, int len, int offset) - throws IOException { - os.write(tag | ((len - 1) << 2)); - writeLittleEndian(offsetBytes, offset); - } - - // technically the format could use shorter matches but with a - // length of three the offset would be encoded as at least two - // bytes in addition to the tag, so yield no compression at all - private static final int MIN_MATCH_LENGTH = 4; - // Snappy stores the match length in six bits of the tag - private static final int MAX_MATCH_LENGTH = 64; - - /** - * Returns a builder correctly configured for the Snappy algorithm using the gven block size. - * @param blockSize the block size. - * @return a builder correctly configured for the Snappy algorithm using the gven block size - */ - public static Parameters.Builder createParameterBuilder(int blockSize) { - // the max offset and max literal length defined by the format - // are 2^32 - 1 and 2^32 respectively - with blockSize being - // an integer we will never exceed that - return Parameters.builder(blockSize) - .withMinBackReferenceLength(MIN_MATCH_LENGTH) - .withMaxBackReferenceLength(MAX_MATCH_LENGTH) - .withMaxOffset(blockSize) - .withMaxLiteralLength(blockSize); - } -} diff --git a/src/org/apache/commons/compress/compressors/snappy/package.html b/src/org/apache/commons/compress/compressors/snappy/package.html deleted file mode 100644 index efef0718013..00000000000 --- a/src/org/apache/commons/compress/compressors/snappy/package.html +++ /dev/null @@ -1,38 +0,0 @@ - - - -

Provides stream classes for the - Snappy - algorithm.

- -

The raw Snappy format which only contains the compressed data - is supported by the SnappyCompressor*putStream - classes while the so called "framing format" is implemented - by FramedSnappyCompressor*putStream. Note there - have been different versions of the framing format specification, - the implementation in Commons Compress is based on the - specification "Last revised: 2013-10-25".

- -

Only the "framing format" can be auto-detected this means you - have to speficy the format explicitly if you want to read a - "raw" Snappy stream - via CompressorStreamFactory.

- - diff --git a/src/org/apache/commons/compress/compressors/xz/XZCompressorInputStream.java b/src/org/apache/commons/compress/compressors/xz/XZCompressorInputStream.java deleted file mode 100644 index 20d67a19ab9..00000000000 --- a/src/org/apache/commons/compress/compressors/xz/XZCompressorInputStream.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.xz; - -import java.io.IOException; -import java.io.InputStream; - -import org.tukaani.xz.XZ; -import org.tukaani.xz.SingleXZInputStream; -import org.tukaani.xz.XZInputStream; - -import org.apache.commons.compress.MemoryLimitException; -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * XZ decompressor. - * @since 1.4 - */ -public class XZCompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - private final CountingInputStream countingStream; - private final InputStream in; - - /** - * Checks if the signature matches what is expected for a .xz file. - * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true if signature matches the .xz magic bytes, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < XZ.HEADER_MAGIC.length) { - return false; - } - - for (int i = 0; i < XZ.HEADER_MAGIC.length; ++i) { - if (signature[i] != XZ.HEADER_MAGIC[i]) { - return false; - } - } - - return true; - } - - /** - * Creates a new input stream that decompresses XZ-compressed data - * from the specified input stream. This doesn't support - * concatenated .xz files. - * - * @param inputStream where to read the compressed data - * - * @throws IOException if the input is not in the .xz format, - * the input is corrupt or truncated, the .xz - * headers specify options that are not supported - * by this implementation, or the underlying - * inputStream throws an exception - */ - public XZCompressorInputStream(final InputStream inputStream) - throws IOException { - this(inputStream, false); - } - - /** - * Creates a new input stream that decompresses XZ-compressed data - * from the specified input stream. - * - * @param inputStream where to read the compressed data - * @param decompressConcatenated - * if true, decompress until the end of the - * input; if false, stop after the first .xz - * stream and leave the input position to point - * to the next byte after the .xz stream - * - * @throws IOException if the input is not in the .xz format, - * the input is corrupt or truncated, the .xz - * headers specify options that are not supported - * by this implementation, or the underlying - * inputStream throws an exception - */ - public XZCompressorInputStream(final InputStream inputStream, - final boolean decompressConcatenated) - throws IOException { - this(inputStream, decompressConcatenated, -1); - } - - /** - * Creates a new input stream that decompresses XZ-compressed data - * from the specified input stream. - * - * @param inputStream where to read the compressed data - * @param decompressConcatenated - * if true, decompress until the end of the - * input; if false, stop after the first .xz - * stream and leave the input position to point - * to the next byte after the .xz stream - * @param memoryLimitInKb memory limit used when reading blocks. If - * the estimated memory limit is exceeded on {@link #read()}, - * a {@link MemoryLimitException} is thrown. - * - * @throws IOException if the input is not in the .xz format, - * the input is corrupt or truncated, the .xz - * headers specify options that are not supported - * by this implementation, - * or the underlying inputStream throws an exception - * - * @since 1.14 - */ - public XZCompressorInputStream(InputStream inputStream, - boolean decompressConcatenated, final int memoryLimitInKb) - throws IOException { - countingStream = new CountingInputStream(inputStream); - if (decompressConcatenated) { - in = new XZInputStream(countingStream, memoryLimitInKb); - } else { - in = new SingleXZInputStream(countingStream, memoryLimitInKb); - } - } - - @Override - public int read() throws IOException { - try { - final int ret = in.read(); - count(ret == -1 ? -1 : 1); - return ret; - } catch (org.tukaani.xz.MemoryLimitException e) { - throw new MemoryLimitException(e.getMemoryNeeded(), e.getMemoryLimit(), e); - } - } - - @Override - public int read(final byte[] buf, final int off, final int len) throws IOException { - try { - final int ret = in.read(buf, off, len); - count(ret); - return ret; - } catch (org.tukaani.xz.MemoryLimitException e) { - //convert to commons-compress MemoryLimtException - throw new MemoryLimitException(e.getMemoryNeeded(), e.getMemoryLimit(), e); - } - } - - @Override - public long skip(final long n) throws IOException { - try { - return IOUtils.skip(in, n); - } catch (org.tukaani.xz.MemoryLimitException e) { - //convert to commons-compress MemoryLimtException - throw new MemoryLimitException(e.getMemoryNeeded(), e.getMemoryLimit(), e); - } - } - - @Override - public int available() throws IOException { - return in.available(); - } - - @Override - public void close() throws IOException { - in.close(); - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return countingStream.getBytesRead(); - } -} diff --git a/src/org/apache/commons/compress/compressors/xz/XZCompressorOutputStream.java b/src/org/apache/commons/compress/compressors/xz/XZCompressorOutputStream.java deleted file mode 100644 index 6e9b70e05fa..00000000000 --- a/src/org/apache/commons/compress/compressors/xz/XZCompressorOutputStream.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.xz; - -import java.io.IOException; -import java.io.OutputStream; -import org.tukaani.xz.LZMA2Options; -import org.tukaani.xz.XZOutputStream; - -import org.apache.commons.compress.compressors.CompressorOutputStream; - -/** - * XZ compressor. - * @since 1.4 - */ -public class XZCompressorOutputStream extends CompressorOutputStream { - private final XZOutputStream out; - - /** - * Creates a new XZ compressor using the default LZMA2 options. - * This is equivalent to XZCompressorOutputStream(outputStream, 6). - * @param outputStream the stream to wrap - * @throws IOException on error - */ - public XZCompressorOutputStream(final OutputStream outputStream) - throws IOException { - out = new XZOutputStream(outputStream, new LZMA2Options()); - } - - /** - * Creates a new XZ compressor using the specified LZMA2 preset level. - *

- * The presets 0-3 are fast presets with medium compression. - * The presets 4-6 are fairly slow presets with high compression. - * The default preset is 6. - *

- * The presets 7-9 are like the preset 6 but use bigger dictionaries - * and have higher compressor and decompressor memory requirements. - * Unless the uncompressed size of the file exceeds 8 MiB, - * 16 MiB, or 32 MiB, it is waste of memory to use the - * presets 7, 8, or 9, respectively. - * @param outputStream the stream to wrap - * @param preset the preset - * @throws IOException on error - */ - public XZCompressorOutputStream(final OutputStream outputStream, final int preset) - throws IOException { - out = new XZOutputStream(outputStream, new LZMA2Options(preset)); - } - - @Override - public void write(final int b) throws IOException { - out.write(b); - } - - @Override - public void write(final byte[] buf, final int off, final int len) throws IOException { - out.write(buf, off, len); - } - - /** - * Flushes the encoder and calls outputStream.flush(). - * All buffered pending data will then be decompressible from - * the output stream. Calling this function very often may increase - * the compressed file size a lot. - */ - @Override - public void flush() throws IOException { - out.flush(); - } - - /** - * Finishes compression without closing the underlying stream. - * No more data can be written to this stream after finishing. - * @throws IOException on error - */ - public void finish() throws IOException { - out.finish(); - } - - @Override - public void close() throws IOException { - out.close(); - } -} diff --git a/src/org/apache/commons/compress/compressors/xz/XZUtils.java b/src/org/apache/commons/compress/compressors/xz/XZUtils.java deleted file mode 100644 index be4625e5dc2..00000000000 --- a/src/org/apache/commons/compress/compressors/xz/XZUtils.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.xz; - -import java.util.HashMap; -import java.util.Map; -import org.apache.commons.compress.compressors.FileNameUtil; - -/** - * Utility code for the xz compression format. - * @ThreadSafe - * @since 1.4 - */ -public class XZUtils { - - private static final FileNameUtil fileNameUtil; - - /** - * XZ Header Magic Bytes begin a XZ file. - * - *

This is a copy of {@code org.tukaani.xz.XZ.HEADER_MAGIC} in - * XZ for Java version 1.5.

- */ - private static final byte[] HEADER_MAGIC = { - (byte) 0xFD, '7', 'z', 'X', 'Z', '\0' - }; - - enum CachedAvailability { - DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE - } - - private static volatile CachedAvailability cachedXZAvailability; - - static { - final Map uncompressSuffix = new HashMap<>(); - uncompressSuffix.put(".txz", ".tar"); - uncompressSuffix.put(".xz", ""); - uncompressSuffix.put("-xz", ""); - fileNameUtil = new FileNameUtil(uncompressSuffix, ".xz"); - cachedXZAvailability = CachedAvailability.DONT_CACHE; - try { - Class.forName("org.osgi.framework.BundleEvent"); - } catch (final Exception ex) { - setCacheXZAvailablity(true); - } - } - - /** Private constructor to prevent instantiation of this utility class. */ - private XZUtils() { - } - - /** - * Checks if the signature matches what is expected for a .xz file. - * - *

This is more or less a copy of the version found in {@link - * XZCompressorInputStream} but doesn't depend on the presence of - * XZ for Java.

- * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true if signature matches the .xz magic bytes, false otherwise - * @since 1.9 - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < HEADER_MAGIC.length) { - return false; - } - - for (int i = 0; i < HEADER_MAGIC.length; ++i) { - if (signature[i] != HEADER_MAGIC[i]) { - return false; - } - } - - return true; - } - - /** - * Are the classes required to support XZ compression available? - * @since 1.5 - * @return true if the classes required to support XZ compression are available - */ - public static boolean isXZCompressionAvailable() { - final CachedAvailability cachedResult = cachedXZAvailability; - if (cachedResult != CachedAvailability.DONT_CACHE) { - return cachedResult == CachedAvailability.CACHED_AVAILABLE; - } - return internalIsXZCompressionAvailable(); - } - - private static boolean internalIsXZCompressionAvailable() { - try { - XZCompressorInputStream.matches(null, 0); - return true; - } catch (final NoClassDefFoundError error) { - return false; - } - } - - /** - * Detects common xz suffixes in the given filename. - * - * @param filename name of a file - * @return {@code true} if the filename has a common xz suffix, - * {@code false} otherwise - */ - public static boolean isCompressedFilename(final String filename) { - return fileNameUtil.isCompressedFilename(filename); - } - - /** - * Maps the given name of a xz-compressed file to the name that the - * file should have after uncompression. Commonly used file type specific - * suffixes like ".txz" are automatically detected and - * correctly mapped. For example the name "package.txz" is mapped to - * "package.tar". And any filenames with the generic ".xz" suffix - * (or any other generic xz suffix) is mapped to a name without that - * suffix. If no xz suffix is detected, then the filename is returned - * unmapped. - * - * @param filename name of a file - * @return name of the corresponding uncompressed file - */ - public static String getUncompressedFilename(final String filename) { - return fileNameUtil.getUncompressedFilename(filename); - } - - /** - * Maps the given filename to the name that the file should have after - * compression with xz. Common file types with custom suffixes for - * compressed versions are automatically detected and correctly mapped. - * For example the name "package.tar" is mapped to "package.txz". If no - * custom mapping is applicable, then the default ".xz" suffix is appended - * to the filename. - * - * @param filename name of a file - * @return name of the corresponding compressed file - */ - public static String getCompressedFilename(final String filename) { - return fileNameUtil.getCompressedFilename(filename); - } - - /** - * Whether to cache the result of the XZ for Java check. - * - *

This defaults to {@code false} in an OSGi environment and {@code true} otherwise.

- * @param doCache whether to cache the result - * @since 1.9 - */ - public static void setCacheXZAvailablity(final boolean doCache) { - if (!doCache) { - cachedXZAvailability = CachedAvailability.DONT_CACHE; - } else if (cachedXZAvailability == CachedAvailability.DONT_CACHE) { - final boolean hasXz = internalIsXZCompressionAvailable(); - cachedXZAvailability = hasXz ? CachedAvailability.CACHED_AVAILABLE // NOSONAR - : CachedAvailability.CACHED_UNAVAILABLE; - } - } - - // only exists to support unit tests - static CachedAvailability getCachedXZAvailability() { - return cachedXZAvailability; - } -} diff --git a/src/org/apache/commons/compress/compressors/xz/package.html b/src/org/apache/commons/compress/compressors/xz/package.html deleted file mode 100644 index 48eca2518de..00000000000 --- a/src/org/apache/commons/compress/compressors/xz/package.html +++ /dev/null @@ -1,31 +0,0 @@ - - - -

Provides stream classes for compressing and decompressing - streams using the XZ algorithm.

- -

The classes in this package are wrappers around {@link - org.tukaani.xz.XZInputStream org.tukaani.xz.XZInputStream} and - {@link org.tukaani.xz.XZOutputStream - org.tukaani.xz.XZOutputStream} provided by the public - domain XZ for Java - library.

- - diff --git a/src/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java b/src/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java deleted file mode 100644 index b7ce16f3313..00000000000 --- a/src/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.z; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteOrder; - -import org.apache.commons.compress.compressors.lzw.LZWInputStream; - -/** - * Input stream that decompresses .Z files. - * @NotThreadSafe - * @since 1.7 - */ -public class ZCompressorInputStream extends LZWInputStream { - private static final int MAGIC_1 = 0x1f; - private static final int MAGIC_2 = 0x9d; - private static final int BLOCK_MODE_MASK = 0x80; - private static final int MAX_CODE_SIZE_MASK = 0x1f; - private final boolean blockMode; - private final int maxCodeSize; - private long totalCodesRead = 0; - - public ZCompressorInputStream(final InputStream inputStream, final int memoryLimitInKb) - throws IOException { - super(inputStream, ByteOrder.LITTLE_ENDIAN); - final int firstByte = (int) in.readBits(8); - final int secondByte = (int) in.readBits(8); - final int thirdByte = (int) in.readBits(8); - if (firstByte != MAGIC_1 || secondByte != MAGIC_2 || thirdByte < 0) { - throw new IOException("Input is not in .Z format"); - } - blockMode = (thirdByte & BLOCK_MODE_MASK) != 0; - maxCodeSize = thirdByte & MAX_CODE_SIZE_MASK; - if (blockMode) { - setClearCode(DEFAULT_CODE_SIZE); - } - initializeTables(maxCodeSize, memoryLimitInKb); - clearEntries(); - } - - public ZCompressorInputStream(final InputStream inputStream) throws IOException { - this(inputStream, -1); - } - - private void clearEntries() { - setTableSize((1 << 8) + (blockMode ? 1 : 0)); - } - - /** - * {@inheritDoc} - *

This method is only protected for technical reasons - * and is not part of Commons Compress' published API. It may - * change or disappear without warning.

- */ - @Override - protected int readNextCode() throws IOException { - final int code = super.readNextCode(); - if (code >= 0) { - ++totalCodesRead; - } - return code; - } - - private void reAlignReading() throws IOException { - // "compress" works in multiples of 8 symbols, each codeBits bits long. - // When codeBits changes, the remaining unused symbols in the current - // group of 8 are still written out, in the old codeSize, - // as garbage values (usually zeroes) that need to be skipped. - long codeReadsToThrowAway = 8 - (totalCodesRead % 8); - if (codeReadsToThrowAway == 8) { - codeReadsToThrowAway = 0; - } - for (long i = 0; i < codeReadsToThrowAway; i++) { - readNextCode(); - } - in.clearBitCache(); - } - - /** - * {@inheritDoc} - *

This method is only protected for technical reasons - * and is not part of Commons Compress' published API. It may - * change or disappear without warning.

- */ - @Override - protected int addEntry(final int previousCode, final byte character) throws IOException { - final int maxTableSize = 1 << getCodeSize(); - final int r = addEntry(previousCode, character, maxTableSize); - if (getTableSize() == maxTableSize && getCodeSize() < maxCodeSize) { - reAlignReading(); - incrementCodeSize(); - } - return r; - } - - /** - * {@inheritDoc} - *

This method is only protected for technical reasons - * and is not part of Commons Compress' published API. It may - * change or disappear without warning.

- */ - @Override - protected int decompressNextSymbol() throws IOException { - // - // table entry table entry - // _____________ _____ - // table entry / \ / \ - // ____________/ \ \ - // / / \ / \ \ - // +---+---+---+---+---+---+---+---+---+---+ - // | . | . | . | . | . | . | . | . | . | . | - // +---+---+---+---+---+---+---+---+---+---+ - // |<--------->|<------------->|<----->|<->| - // symbol symbol symbol symbol - // - final int code = readNextCode(); - if (code < 0) { - return -1; - } else if (blockMode && code == getClearCode()) { - clearEntries(); - reAlignReading(); - resetCodeSize(); - resetPreviousCode(); - return 0; - } else { - boolean addedUnfinishedEntry = false; - if (code == getTableSize()) { - addRepeatOfPreviousCode(); - addedUnfinishedEntry = true; - } else if (code > getTableSize()) { - throw new IOException(String.format("Invalid %d bit code 0x%x", getCodeSize(), code)); - } - return expandCodeToOutputStack(code, addedUnfinishedEntry); - } - } - - /** - * Checks if the signature matches what is expected for a Unix compress file. - * - * @param signature - * the bytes to check - * @param length - * the number of bytes to check - * @return true, if this stream is a Unix compress compressed - * stream, false otherwise - * - * @since 1.9 - */ - public static boolean matches(final byte[] signature, final int length) { - return length > 3 && signature[0] == MAGIC_1 && signature[1] == (byte) MAGIC_2; - } - -} diff --git a/src/org/apache/commons/compress/compressors/z/package.html b/src/org/apache/commons/compress/compressors/z/package.html deleted file mode 100644 index ca9924b786d..00000000000 --- a/src/org/apache/commons/compress/compressors/z/package.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -

Provides stream classes for decompressing - streams using the "compress" algorithm used to write .Z files.

- - diff --git a/src/org/apache/commons/compress/compressors/zstandard/ZstdCompressorInputStream.java b/src/org/apache/commons/compress/compressors/zstandard/ZstdCompressorInputStream.java deleted file mode 100644 index 7a47f10006d..00000000000 --- a/src/org/apache/commons/compress/compressors/zstandard/ZstdCompressorInputStream.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.compress.compressors.zstandard; - - -import java.io.IOException; -import java.io.InputStream; - -import com.github.luben.zstd.ZstdInputStream; -import org.apache.commons.compress.compressors.CompressorInputStream; -import org.apache.commons.compress.utils.CountingInputStream; -import org.apache.commons.compress.utils.IOUtils; -import org.apache.commons.compress.utils.InputStreamStatistics; - -/** - * {@link CompressorInputStream} implementation to decode Zstandard encoded stream. - * Library relies on Zstandard JNI - * - * @since 1.16 - */ -public class ZstdCompressorInputStream extends CompressorInputStream - implements InputStreamStatistics { - - private final CountingInputStream countingStream; - private final ZstdInputStream decIS; - - public ZstdCompressorInputStream(final InputStream in) throws IOException { - this.decIS = new ZstdInputStream(countingStream = new CountingInputStream(in)); - } - - @Override - public int available() throws IOException { - return decIS.available(); - } - - @Override - public void close() throws IOException { - decIS.close(); - } - - @Override - public int read(final byte[] b) throws IOException { - return decIS.read(b); - } - - @Override - public long skip(final long n) throws IOException { - return IOUtils.skip(decIS, n); - } - - @Override - public void mark(final int readlimit) { - decIS.mark(readlimit); - } - - @Override - public boolean markSupported() { - return decIS.markSupported(); - } - - @Override - public int read() throws IOException { - final int ret = decIS.read(); - count(ret == -1 ? 0 : 1); - return ret; - } - - @Override - public int read(final byte[] buf, final int off, final int len) throws IOException { - final int ret = decIS.read(buf, off, len); - count(ret); - return ret; - } - - @Override - public String toString() { - return decIS.toString(); - } - - @Override - public void reset() throws IOException { - decIS.reset(); - } - - /** - * @since 1.17 - */ - @Override - public long getCompressedCount() { - return countingStream.getBytesRead(); - } -} diff --git a/src/org/apache/commons/compress/compressors/zstandard/ZstdCompressorOutputStream.java b/src/org/apache/commons/compress/compressors/zstandard/ZstdCompressorOutputStream.java deleted file mode 100644 index b54dfa73d75..00000000000 --- a/src/org/apache/commons/compress/compressors/zstandard/ZstdCompressorOutputStream.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.compress.compressors.zstandard; - - -import java.io.IOException; -import java.io.OutputStream; - -import com.github.luben.zstd.ZstdOutputStream; -import org.apache.commons.compress.compressors.CompressorOutputStream; - -/** - * {@link CompressorOutputStream} implementation to create Zstandard encoded stream. - * Library relies on Zstandard JNI - * - * @since 1.16 - */ -public class ZstdCompressorOutputStream extends CompressorOutputStream { - - private final ZstdOutputStream encOS; - - public ZstdCompressorOutputStream(final OutputStream out) throws IOException { - this.encOS = new ZstdOutputStream(out); - } - - @Override - public void close() throws IOException { - encOS.close(); - } - - @Override - public void write(final int b) throws IOException { - encOS.write(b); - } - - @Override - public void write(final byte[] buf, final int off, final int len) throws IOException { - encOS.write(buf, off, len); - } - - @Override - public String toString() { - return encOS.toString(); - } - - @Override - public void flush() throws IOException { - encOS.flush(); - } -} diff --git a/src/org/apache/commons/compress/compressors/zstandard/ZstdUtils.java b/src/org/apache/commons/compress/compressors/zstandard/ZstdUtils.java deleted file mode 100644 index 8b2f8d3d717..00000000000 --- a/src/org/apache/commons/compress/compressors/zstandard/ZstdUtils.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.compressors.zstandard; - -/** - * Utility code for the Zstandard compression format. - * @ThreadSafe - * @since 1.16 - */ -public class ZstdUtils { - - enum CachedAvailability { - DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE - } - - /** - * Zstandard Frame Magic Bytes. - */ - private static final byte[] ZSTANDARD_FRAME_MAGIC = { - (byte) 0x28, (byte) 0xB5, (byte) 0x2F, (byte) 0xFD - }; - - /** - * Skippable Frame Magic Bytes - the three common bytes. - */ - private static final byte[] SKIPPABLE_FRAME_MAGIC = { - (byte) 0x2A, (byte) 0x4D, (byte) 0x18 - }; - - private static volatile CachedAvailability cachedZstdAvailability; - - static { - cachedZstdAvailability = CachedAvailability.DONT_CACHE; - try { - Class.forName("org.osgi.framework.BundleEvent"); - } catch (final Exception ex) { // NOSONAR - setCacheZstdAvailablity(true); - } - } - - /** Private constructor to prevent instantiation of this utility class. */ - private ZstdUtils() { - } - - /** - * Are the classes required to support Zstandard compression available? - * @return true if the classes required to support Zstandard compression are available - */ - public static boolean isZstdCompressionAvailable() { - final CachedAvailability cachedResult = cachedZstdAvailability; - if (cachedResult != CachedAvailability.DONT_CACHE) { - return cachedResult == CachedAvailability.CACHED_AVAILABLE; - } - return internalIsZstdCompressionAvailable(); - } - - private static boolean internalIsZstdCompressionAvailable() { - try { - Class.forName("com.github.luben.zstd.ZstdInputStream"); - return true; - } catch (NoClassDefFoundError | Exception error) { // NOSONAR - return false; - } - } - - /** - * Whether to cache the result of the Zstandard for Java check. - * - *

This defaults to {@code false} in an OSGi environment and {@code true} otherwise.

- * @param doCache whether to cache the result - */ - public static void setCacheZstdAvailablity(final boolean doCache) { - if (!doCache) { - cachedZstdAvailability = CachedAvailability.DONT_CACHE; - } else if (cachedZstdAvailability == CachedAvailability.DONT_CACHE) { - final boolean hasZstd = internalIsZstdCompressionAvailable(); - cachedZstdAvailability = hasZstd ? CachedAvailability.CACHED_AVAILABLE - : CachedAvailability.CACHED_UNAVAILABLE; - } - } - - /** - * Checks if the signature matches what is expected for a Zstandard file. - * - * @param signature the bytes to check - * @param length the number of bytes to check - * @return true if signature matches the Ztstandard or skippable - * frame magic bytes, false otherwise - */ - public static boolean matches(final byte[] signature, final int length) { - if (length < ZSTANDARD_FRAME_MAGIC.length) { - return false; - } - - boolean isZstandard = true; - for (int i = 0; i < ZSTANDARD_FRAME_MAGIC.length; ++i) { - if (signature[i] != ZSTANDARD_FRAME_MAGIC[i]) { - isZstandard = false; - break; - } - } - if (isZstandard) { - return true; - } - - if (0x50 == (signature[0] & 0xF0)) { - // skippable frame - for (int i = 0; i < SKIPPABLE_FRAME_MAGIC.length; ++i) { - if (signature[i + 1] != SKIPPABLE_FRAME_MAGIC[i]) { - return false; - } - } - - return true; - } - - return false; - } - - // only exists to support unit tests - static CachedAvailability getCachedZstdAvailability() { - return cachedZstdAvailability; - } -} diff --git a/src/org/apache/commons/compress/compressors/zstandard/package.html b/src/org/apache/commons/compress/compressors/zstandard/package.html deleted file mode 100644 index 6deb74fcf0b..00000000000 --- a/src/org/apache/commons/compress/compressors/zstandard/package.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -

Provides stream class for (de)compressing streams using the - Zstandard algorithm based - on Zstandard - JNI.

- - diff --git a/src/org/apache/commons/compress/parallel/FileBasedScatterGatherBackingStore.java b/src/org/apache/commons/compress/parallel/FileBasedScatterGatherBackingStore.java deleted file mode 100644 index 92b447fabb1..00000000000 --- a/src/org/apache/commons/compress/parallel/FileBasedScatterGatherBackingStore.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.parallel; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; - -/** - * ScatterGatherBackingStore that is backed by a file. - * - * @since 1.10 - */ -public class FileBasedScatterGatherBackingStore implements ScatterGatherBackingStore { - private final File target; - private final OutputStream os; - private boolean closed; - - public FileBasedScatterGatherBackingStore(final File target) throws FileNotFoundException { - this.target = target; - try { - os = Files.newOutputStream(target.toPath()); - } catch (FileNotFoundException ex) { - throw ex; - } catch (IOException ex) { - // must convert exception to stay backwards compatible with Compress 1.10 to 1.13 - throw new RuntimeException(ex); // NOSONAR - } - } - - @Override - public InputStream getInputStream() throws IOException { - return Files.newInputStream(target.toPath()); - } - - @Override - @SuppressWarnings("ResultOfMethodCallIgnored") - public void closeForWriting() throws IOException { - if (!closed) { - os.close(); - closed = true; - } - } - - @Override - public void writeOut(final byte[] data, final int offset, final int length) throws IOException { - os.write(data, offset, length); - } - - @Override - public void close() throws IOException { - closeForWriting(); - target.delete(); - } -} diff --git a/src/org/apache/commons/compress/parallel/InputStreamSupplier.java b/src/org/apache/commons/compress/parallel/InputStreamSupplier.java deleted file mode 100644 index f227e643132..00000000000 --- a/src/org/apache/commons/compress/parallel/InputStreamSupplier.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.parallel; - -import java.io.InputStream; - -/** - * Supplies input streams. - * - * Implementations are required to support thread-handover. While an instance will - * not be accessed concurrently by multiple threads, it will be called by - * a different thread than it was created on. - * - * @since 1.10 - */ -public interface InputStreamSupplier { - - /** - * Supply an input stream for a resource. - * @return the input stream. Should never null, but may be an empty stream. - */ - InputStream get(); -} diff --git a/src/org/apache/commons/compress/parallel/ScatterGatherBackingStore.java b/src/org/apache/commons/compress/parallel/ScatterGatherBackingStore.java deleted file mode 100644 index ea726ff8a7b..00000000000 --- a/src/org/apache/commons/compress/parallel/ScatterGatherBackingStore.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.parallel; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; - -/** - *

Store intermediate payload in a scatter-gather scenario. - * Multiple threads write their payload to a backing store, which can - * subsequently be reversed to an {@link InputStream} to be used as input in the - * gather phase.

- * - *

It is the responsibility of the allocator of an instance of this class - * to close this. Closing it should clear off any allocated structures - * and preferably delete files.

- * - * @since 1.10 - */ -public interface ScatterGatherBackingStore extends Closeable { - - /** - * An input stream that contains the scattered payload - * - * @return An InputStream, should be closed by the caller of this method. - * @throws IOException when something fails - */ - InputStream getInputStream() throws IOException; - - /** - * Writes a piece of payload. - * - * @param data the data to write - * @param offset offset inside data to start writing from - * @param length the amount of data to write - * @throws IOException when something fails - */ - void writeOut(byte[] data, int offset, int length) throws IOException; - - /** - * Closes this backing store for further writing. - * @throws IOException when something fails - */ - void closeForWriting() throws IOException; -} diff --git a/src/org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier.java b/src/org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier.java deleted file mode 100644 index 9a216a7b823..00000000000 --- a/src/org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.parallel; - -import java.io.IOException; - -/** - * Supplies {@link ScatterGatherBackingStore} instances. - * - * @since 1.10 - */ -public interface ScatterGatherBackingStoreSupplier { - /** - * Create a ScatterGatherBackingStore. - * - * @return a ScatterGatherBackingStore, not null - * @throws IOException when something fails - */ - ScatterGatherBackingStore get() throws IOException; -} diff --git a/src/org/apache/commons/compress/parallel/package.html b/src/org/apache/commons/compress/parallel/package.html deleted file mode 100644 index 3517bc57526..00000000000 --- a/src/org/apache/commons/compress/parallel/package.html +++ /dev/null @@ -1,23 +0,0 @@ - - - -

Provides common API classes for parallel compression features.

- - diff --git a/src/org/apache/commons/compress/utils/ArchiveUtils.java b/src/org/apache/commons/compress/utils/ArchiveUtils.java deleted file mode 100644 index 3fe3fbadd15..00000000000 --- a/src/org/apache/commons/compress/utils/ArchiveUtils.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.utils; - -import java.io.UnsupportedEncodingException; -import java.util.Arrays; - -import org.apache.commons.compress.archivers.ArchiveEntry; - -/** - * Generic Archive utilities - */ -public class ArchiveUtils { - - private static final int MAX_SANITIZED_NAME_LENGTH = 255; - - /** Private constructor to prevent instantiation of this utility class. */ - private ArchiveUtils(){ - } - - /** - * Generates a string containing the name, isDirectory setting and size of an entry. - *

- * For example: - *

-     * -    2000 main.c
-     * d     100 testfiles
-     * 
- * - * @param entry the entry - * @return the representation of the entry - */ - public static String toString(final ArchiveEntry entry){ - final StringBuilder sb = new StringBuilder(); - sb.append(entry.isDirectory()? 'd' : '-');// c.f. "ls -l" output - final String size = Long.toString(entry.getSize()); - sb.append(' '); - // Pad output to 7 places, leading spaces - for(int i=7; i > size.length(); i--){ - sb.append(' '); - } - sb.append(size); - sb.append(' ').append(entry.getName()); - return sb.toString(); - } - - /** - * Check if buffer contents matches Ascii String. - * - * @param expected expected string - * @param buffer the buffer - * @param offset offset to read from - * @param length length of the buffer - * @return {@code true} if buffer is the same as the expected string - */ - public static boolean matchAsciiBuffer( - final String expected, final byte[] buffer, final int offset, final int length){ - byte[] buffer1; - try { - buffer1 = expected.getBytes(CharsetNames.US_ASCII); - } catch (final UnsupportedEncodingException e) { - // Should not happen - throw new RuntimeException(e); //NOSONAR - } - return isEqual(buffer1, 0, buffer1.length, buffer, offset, length, false); - } - - /** - * Check if buffer contents matches Ascii String. - * - * @param expected the expected strin - * @param buffer the buffer - * @return {@code true} if buffer is the same as the expected string - */ - public static boolean matchAsciiBuffer(final String expected, final byte[] buffer){ - return matchAsciiBuffer(expected, buffer, 0, buffer.length); - } - - /** - * Convert a string to Ascii bytes. - * Used for comparing "magic" strings which need to be independent of the default Locale. - * - * @param inputString string to convert - * @return the bytes - */ - public static byte[] toAsciiBytes(final String inputString){ - try { - return inputString.getBytes(CharsetNames.US_ASCII); - } catch (final UnsupportedEncodingException e) { - // Should never happen - throw new RuntimeException(e); //NOSONAR - } - } - - /** - * Convert an input byte array to a String using the ASCII character set. - * - * @param inputBytes bytes to convert - * @return the bytes, interpreted as an Ascii string - */ - public static String toAsciiString(final byte[] inputBytes){ - try { - return new String(inputBytes, CharsetNames.US_ASCII); - } catch (final UnsupportedEncodingException e) { - // Should never happen - throw new RuntimeException(e); //NOSONAR - } - } - - /** - * Convert an input byte array to a String using the ASCII character set. - * - * @param inputBytes input byte array - * @param offset offset within array - * @param length length of array - * @return the bytes, interpreted as an Ascii string - */ - public static String toAsciiString(final byte[] inputBytes, final int offset, final int length){ - try { - return new String(inputBytes, offset, length, CharsetNames.US_ASCII); - } catch (final UnsupportedEncodingException e) { - // Should never happen - throw new RuntimeException(e); //NOSONAR - } - } - - /** - * Compare byte buffers, optionally ignoring trailing nulls - * - * @param buffer1 first buffer - * @param offset1 first offset - * @param length1 first length - * @param buffer2 second buffer - * @param offset2 second offset - * @param length2 second length - * @param ignoreTrailingNulls whether to ignore trailing nulls - * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls - */ - public static boolean isEqual( - final byte[] buffer1, final int offset1, final int length1, - final byte[] buffer2, final int offset2, final int length2, - final boolean ignoreTrailingNulls){ - final int minLen=length1 < length2 ? length1 : length2; - for (int i=0; i < minLen; i++){ - if (buffer1[offset1+i] != buffer2[offset2+i]){ - return false; - } - } - if (length1 == length2){ - return true; - } - if (ignoreTrailingNulls){ - if (length1 > length2){ - for(int i = length2; i < length1; i++){ - if (buffer1[offset1+i] != 0){ - return false; - } - } - } else { - for(int i = length1; i < length2; i++){ - if (buffer2[offset2+i] != 0){ - return false; - } - } - } - return true; - } - return false; - } - - /** - * Compare byte buffers - * - * @param buffer1 the first buffer - * @param offset1 the first offset - * @param length1 the first length - * @param buffer2 the second buffer - * @param offset2 the second offset - * @param length2 the second length - * @return {@code true} if buffer1 and buffer2 have same contents - */ - public static boolean isEqual( - final byte[] buffer1, final int offset1, final int length1, - final byte[] buffer2, final int offset2, final int length2){ - return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, false); - } - - /** - * Compare byte buffers - * - * @param buffer1 the first buffer - * @param buffer2 the second buffer - * @return {@code true} if buffer1 and buffer2 have same contents - */ - public static boolean isEqual(final byte[] buffer1, final byte[] buffer2 ){ - return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, false); - } - - /** - * Compare byte buffers, optionally ignoring trailing nulls - * - * @param buffer1 the first buffer - * @param buffer2 the second buffer - * @param ignoreTrailingNulls whether to ignore tariling nulls - * @return {@code true} if buffer1 and buffer2 have same contents - */ - public static boolean isEqual(final byte[] buffer1, final byte[] buffer2, final boolean ignoreTrailingNulls){ - return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, ignoreTrailingNulls); - } - - /** - * Compare byte buffers, ignoring trailing nulls - * - * @param buffer1 the first buffer - * @param offset1 the first offset - * @param length1 the first length - * @param buffer2 the second buffer - * @param offset2 the second offset - * @param length2 the second length - * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls - */ - public static boolean isEqualWithNull( - final byte[] buffer1, final int offset1, final int length1, - final byte[] buffer2, final int offset2, final int length2){ - return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, true); - } - - /** - * Returns true if the first N bytes of an array are all zero - * - * @param a - * The array to check - * @param size - * The number of characters to check (not the size of the array) - * @return true if the first N bytes are zero - */ - public static boolean isArrayZero(final byte[] a, final int size) { - for (int i = 0; i < size; i++) { - if (a[i] != 0) { - return false; - } - } - return true; - } - - /** - * Returns a "sanitized" version of the string given as arguments, - * where sanitized means non-printable characters have been - * replaced with a question mark and the outcome is not longer - * than 255 chars. - * - *

This method is used to clean up file names when they are - * used in exception messages as they may end up in log files or - * as console output and may have been read from a corrupted - * input.

- * - * @param s the string to sanitize - * @return a sanitized version of the argument - * @since Compress 1.12 - */ - public static String sanitize(final String s) { - final char[] cs = s.toCharArray(); - final char[] chars = cs.length <= MAX_SANITIZED_NAME_LENGTH ? cs : Arrays.copyOf(cs, MAX_SANITIZED_NAME_LENGTH); - if (cs.length > MAX_SANITIZED_NAME_LENGTH) { - for (int i = MAX_SANITIZED_NAME_LENGTH - 3; i < MAX_SANITIZED_NAME_LENGTH; i++) { - chars[i] = '.'; - } - } - final StringBuilder sb = new StringBuilder(); - for (final char c : chars) { - if (!Character.isISOControl(c)) { - final Character.UnicodeBlock block = Character.UnicodeBlock.of(c); - if (block != null && block != Character.UnicodeBlock.SPECIALS) { - sb.append(c); - continue; - } - } - sb.append('?'); - } - return sb.toString(); - } - -} diff --git a/src/org/apache/commons/compress/utils/BitInputStream.java b/src/org/apache/commons/compress/utils/BitInputStream.java deleted file mode 100644 index 8abff5f786a..00000000000 --- a/src/org/apache/commons/compress/utils/BitInputStream.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.utils; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteOrder; - -/** - * Reads bits from an InputStream. - * @since 1.10 - * @NotThreadSafe - */ -public class BitInputStream implements Closeable { - private static final int MAXIMUM_CACHE_SIZE = 63; // bits in long minus sign bit - private static final long[] MASKS = new long[MAXIMUM_CACHE_SIZE + 1]; - - static { - for (int i = 1; i <= MAXIMUM_CACHE_SIZE; i++) { - MASKS[i] = (MASKS[i - 1] << 1) + 1; - } - } - - private final CountingInputStream in; - private final ByteOrder byteOrder; - private long bitsCached = 0; - private int bitsCachedSize = 0; - - /** - * Constructor taking an InputStream and its bit arrangement. - * @param in the InputStream - * @param byteOrder the bit arrangement across byte boundaries, - * either BIG_ENDIAN (aaaaabbb bb000000) or LITTLE_ENDIAN (bbbaaaaa 000000bb) - */ - public BitInputStream(final InputStream in, final ByteOrder byteOrder) { - this.in = new CountingInputStream(in); - this.byteOrder = byteOrder; - } - - @Override - public void close() throws IOException { - in.close(); - } - - /** - * Clears the cache of bits that have been read from the - * underlying stream but not yet provided via {@link #readBits}. - */ - public void clearBitCache() { - bitsCached = 0; - bitsCachedSize = 0; - } - - /** - * Returns at most 63 bits read from the underlying stream. - * - * @param count the number of bits to read, must be a positive - * number not bigger than 63. - * @return the bits concatenated as a long using the stream's byte order. - * -1 if the end of the underlying stream has been reached before reading - * the requested number of bits - * @throws IOException on error - */ - public long readBits(final int count) throws IOException { - if (count < 0 || count > MAXIMUM_CACHE_SIZE) { - throw new IllegalArgumentException("count must not be negative or greater than " + MAXIMUM_CACHE_SIZE); - } - if (ensureCache(count)) { - return -1; - } - - if (bitsCachedSize < count) { - return processBitsGreater57(count); - } - return readCachedBits(count); - } - - /** - * Returns the number of bits that can be read from this input - * stream without reading from the underlying input stream at all. - * @return estimate of the number of bits that can be read without reading from the underlying stream - * @since 1.16 - */ - public int bitsCached() { - return bitsCachedSize; - } - - /** - * Returns an estimate of the number of bits that can be read from - * this input stream without blocking by the next invocation of a - * method for this input stream. - * @throws IOException if the underlying stream throws one when calling available - * @return estimate of the number of bits that can be read without blocking - * @since 1.16 - */ - public long bitsAvailable() throws IOException { - return bitsCachedSize + ((long) Byte.SIZE) * in.available(); - } - - /** - * Drops bits until the next bits will be read from a byte boundary. - * @since 1.16 - */ - public void alignWithByteBoundary() { - int toSkip = bitsCachedSize % Byte.SIZE; - if (toSkip > 0) { - readCachedBits(toSkip); - } - } - - /** - * Returns the number of bytes read from the underlying stream. - * - *

This includes the bytes read to fill the current cache and - * not read as bits so far.

- * @return the number of bytes read from the underlying stream - * @since 1.17 - */ - public long getBytesRead() { - return in.getBytesRead(); - } - - private long processBitsGreater57(final int count) throws IOException { - final long bitsOut; - int overflowBits = 0; - long overflow = 0L; - - // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow - int bitsToAddCount = count - bitsCachedSize; - overflowBits = Byte.SIZE - bitsToAddCount; - final long nextByte = in.read(); - if (nextByte < 0) { - return nextByte; - } - if (byteOrder == ByteOrder.LITTLE_ENDIAN) { - long bitsToAdd = nextByte & MASKS[bitsToAddCount]; - bitsCached |= (bitsToAdd << bitsCachedSize); - overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits]; - } else { - bitsCached <<= bitsToAddCount; - long bitsToAdd = (nextByte >>> (overflowBits)) & MASKS[bitsToAddCount]; - bitsCached |= bitsToAdd; - overflow = nextByte & MASKS[overflowBits]; - } - bitsOut = bitsCached & MASKS[count]; - bitsCached = overflow; - bitsCachedSize = overflowBits; - return bitsOut; - } - - private long readCachedBits(int count) { - final long bitsOut; - if (byteOrder == ByteOrder.LITTLE_ENDIAN) { - bitsOut = (bitsCached & MASKS[count]); - bitsCached >>>= count; - } else { - bitsOut = (bitsCached >> (bitsCachedSize - count)) & MASKS[count]; - } - bitsCachedSize -= count; - return bitsOut; - } - - /** - * Fills the cache up to 56 bits - * @param count - * @return return true, when EOF - * @throws IOException - */ - private boolean ensureCache(final int count) throws IOException { - while (bitsCachedSize < count && bitsCachedSize < 57) { - final long nextByte = in.read(); - if (nextByte < 0) { - return true; - } - if (byteOrder == ByteOrder.LITTLE_ENDIAN) { - bitsCached |= (nextByte << bitsCachedSize); - } else { - bitsCached <<= Byte.SIZE; - bitsCached |= nextByte; - } - bitsCachedSize += Byte.SIZE; - } - return false; - } - -} diff --git a/src/org/apache/commons/compress/utils/BoundedInputStream.java b/src/org/apache/commons/compress/utils/BoundedInputStream.java deleted file mode 100644 index 8c3465ded31..00000000000 --- a/src/org/apache/commons/compress/utils/BoundedInputStream.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.utils; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A stream that limits reading from a wrapped stream to a given number of bytes. - * @NotThreadSafe - * @since 1.6 - */ -public class BoundedInputStream extends InputStream { - private final InputStream in; - private long bytesRemaining; - - /** - * Creates the stream that will at most read the given amount of - * bytes from the given stream. - * @param in the stream to read from - * @param size the maximum amount of bytes to read - */ - public BoundedInputStream(final InputStream in, final long size) { - this.in = in; - bytesRemaining = size; - } - - @Override - public int read() throws IOException { - if (bytesRemaining > 0) { - --bytesRemaining; - return in.read(); - } - return -1; - } - - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (bytesRemaining == 0) { - return -1; - } - int bytesToRead = len; - if (bytesToRead > bytesRemaining) { - bytesToRead = (int) bytesRemaining; - } - final int bytesRead = in.read(b, off, bytesToRead); - if (bytesRead >= 0) { - bytesRemaining -= bytesRead; - } - return bytesRead; - } - - @Override - public void close() { - // there isn't anything to close in this stream and the nested - // stream is controlled externally - } -} diff --git a/src/org/apache/commons/compress/utils/ByteUtils.java b/src/org/apache/commons/compress/utils/ByteUtils.java deleted file mode 100644 index 85b4118e972..00000000000 --- a/src/org/apache/commons/compress/utils/ByteUtils.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.utils; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Utility methods for reading and writing bytes. - * @since 1.14 - */ -public final class ByteUtils { - private ByteUtils() { /* no instances */ } - - /** - * Used to supply bytes. - * @since 1.14 - */ - public interface ByteSupplier { - /** - * The contract is similar to {@link InputStream#read()}, return - * the byte as an unsigned int, -1 if there are no more bytes. - * @return the supplied byte or -1 if there are no more bytes - * @throws IOException if supplying fails - */ - int getAsByte() throws IOException; - } - - /** - * Used to consume bytes. - * @since 1.14 - */ - public interface ByteConsumer { - /** - * The contract is similar to {@link OutputStream#write(int)}, - * consume the lower eight bytes of the int as a byte. - * @param b the byte to consume - * @throws IOException if consuming fails - */ - void accept(int b) throws IOException; - } - - /** - * Reads the given byte array as a little endian long. - * @param bytes the byte array to convert - * @return the number read - */ - public static long fromLittleEndian(byte[] bytes) { - return fromLittleEndian(bytes, 0, bytes.length); - } - - /** - * Reads the given byte array as a little endian long. - * @param bytes the byte array to convert - * @param off the offset into the array that starts the value - * @param length the number of bytes representing the value - * @return the number read - * @throws IllegalArgumentException if len is bigger than eight - */ - public static long fromLittleEndian(byte[] bytes, final int off, final int length) { - checkReadLength(length); - long l = 0; - for (int i = 0; i < length; i++) { - l |= (bytes[off + i] & 0xffL) << (8 * i); - } - return l; - } - - /** - * Reads the given number of bytes from the given stream as a little endian long. - * @param in the stream to read from - * @param length the number of bytes representing the value - * @return the number read - * @throws IllegalArgumentException if len is bigger than eight - * @throws IOException if reading fails or the stream doesn't - * contain the given number of bytes anymore - */ - public static long fromLittleEndian(InputStream in, int length) throws IOException { - // somewhat duplicates the ByteSupplier version in order to save the creation of a wrapper object - checkReadLength(length); - long l = 0; - for (int i = 0; i < length; i++) { - long b = in.read(); - if (b == -1) { - throw new IOException("premature end of data"); - } - l |= (b << (i * 8)); - } - return l; - } - - /** - * Reads the given number of bytes from the given supplier as a little endian long. - * - *

Typically used by our InputStreams that need to count the - * bytes read as well.

- * - * @param supplier the supplier for bytes - * @param length the number of bytes representing the value - * @return the number read - * @throws IllegalArgumentException if len is bigger than eight - * @throws IOException if the supplier fails or doesn't supply the - * given number of bytes anymore - */ - public static long fromLittleEndian(ByteSupplier supplier, final int length) throws IOException { - checkReadLength(length); - long l = 0; - for (int i = 0; i < length; i++) { - long b = supplier.getAsByte(); - if (b == -1) { - throw new IOException("premature end of data"); - } - l |= (b << (i * 8)); - } - return l; - } - - /** - * Reads the given number of bytes from the given input as little endian long. - * @param in the input to read from - * @param length the number of bytes representing the value - * @return the number read - * @throws IllegalArgumentException if len is bigger than eight - * @throws IOException if reading fails or the stream doesn't - * contain the given number of bytes anymore - */ - public static long fromLittleEndian(DataInput in, int length) throws IOException { - // somewhat duplicates the ByteSupplier version in order to save the creation of a wrapper object - checkReadLength(length); - long l = 0; - for (int i = 0; i < length; i++) { - long b = in.readUnsignedByte(); - l |= (b << (i * 8)); - } - return l; - } - - /** - * Inserts the given value into the array as a little endian - * sequence of the given length starting at the given offset. - * @param b the array to write into - * @param value the value to insert - * @param off the offset into the array that receives the first byte - * @param length the number of bytes to use to represent the value - */ - public static void toLittleEndian(final byte[] b, final long value, final int off, final int length) { - long num = value; - for (int i = 0; i < length; i++) { - b[off + i] = (byte) (num & 0xff); - num >>= 8; - } - } - - /** - * Writes the given value to the given stream as a little endian - * array of the given length. - * @param out the stream to write to - * @param value the value to write - * @param length the number of bytes to use to represent the value - * @throws IOException if writing fails - */ - public static void toLittleEndian(OutputStream out, final long value, final int length) - throws IOException { - // somewhat duplicates the ByteConsumer version in order to save the creation of a wrapper object - long num = value; - for (int i = 0; i < length; i++) { - out.write((int) (num & 0xff)); - num >>= 8; - } - } - - /** - * Provides the given value to the given consumer as a little endian - * sequence of the given length. - * @param consumer the consumer to provide the bytes to - * @param value the value to provide - * @param length the number of bytes to use to represent the value - * @throws IOException if writing fails - */ - public static void toLittleEndian(ByteConsumer consumer, final long value, final int length) - throws IOException { - long num = value; - for (int i = 0; i < length; i++) { - consumer.accept((int) (num & 0xff)); - num >>= 8; - } - } - - /** - * Writes the given value to the given stream as a little endian - * array of the given length. - * @param out the output to write to - * @param value the value to write - * @param length the number of bytes to use to represent the value - * @throws IOException if writing fails - */ - public static void toLittleEndian(DataOutput out, final long value, final int length) - throws IOException { - // somewhat duplicates the ByteConsumer version in order to save the creation of a wrapper object - long num = value; - for (int i = 0; i < length; i++) { - out.write((int) (num & 0xff)); - num >>= 8; - } - } - - /** - * {@link ByteSupplier} based on {@link InputStream}. - * @since 1.14 - */ - public static class InputStreamByteSupplier implements ByteSupplier { - private final InputStream is; - public InputStreamByteSupplier(InputStream is) { - this.is = is; - } - @Override - public int getAsByte() throws IOException { - return is.read(); - } - } - - /** - * {@link ByteConsumer} based on {@link OutputStream}. - * @since 1.14 - */ - public static class OutputStreamByteConsumer implements ByteConsumer { - private final OutputStream os; - public OutputStreamByteConsumer(OutputStream os) { - this.os = os; - } - @Override - public void accept(int b) throws IOException { - os.write(b); - } - } - - private static final void checkReadLength(int length) { - if (length > 8) { - throw new IllegalArgumentException("can't read more than eight bytes into a long value"); - } - } -} diff --git a/src/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java b/src/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java deleted file mode 100644 index 1b50e8ce572..00000000000 --- a/src/org/apache/commons/compress/utils/CRC32VerifyingInputStream.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.utils; - -import java.io.InputStream; -import java.util.zip.CRC32; - -/** - * A stream that verifies the CRC of the data read once the stream is - * exhausted. - * @NotThreadSafe - * @since 1.6 - */ -public class CRC32VerifyingInputStream extends ChecksumVerifyingInputStream { - - /** - * @param in the stream to wrap - * @param size the of the stream's content - * @param expectedCrc32 the expected checksum - */ - public CRC32VerifyingInputStream(final InputStream in, final long size, final int expectedCrc32) { - this(in, size, expectedCrc32 & 0xFFFFffffL); - } - - /** - * @since 1.7 - * @param in the stream to wrap - * @param size the of the stream's content - * @param expectedCrc32 the expected checksum - */ - public CRC32VerifyingInputStream(final InputStream in, final long size, final long expectedCrc32) { - super(new CRC32(), in, size, expectedCrc32); - } - -} diff --git a/src/org/apache/commons/compress/utils/CharsetNames.java b/src/org/apache/commons/compress/utils/CharsetNames.java deleted file mode 100644 index f6b9cc8ed18..00000000000 --- a/src/org/apache/commons/compress/utils/CharsetNames.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.utils; - -/** - * Character encoding names required of every implementation of the Java platform. - * - * From the Java documentation Standard - * charsets: - *

- * Every implementation of the Java platform is required to support the following character encodings. Consult the - * release documentation for your implementation to see if any other encodings are supported. Consult the release - * documentation for your implementation to see if any other encodings are supported. - *

- * - *
- *
US-ASCII
- *
Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
- *
ISO-8859-1
- *
ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
- *
UTF-8
- *
Eight-bit Unicode Transformation Format.
- *
UTF-16BE
- *
Sixteen-bit Unicode Transformation Format, big-endian byte order.
- *
UTF-16LE
- *
Sixteen-bit Unicode Transformation Format, little-endian byte order.
- *
UTF-16
- *
Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order - * accepted on input, big-endian used on output.)
- *
- * - *

This perhaps would best belong in the [lang] project. Even if a similar interface is defined in [lang], it is not - * foreseen that [compress] would be made to depend on [lang].

- * - * @see Standard charsets - * @since 1.4 - */ -public class CharsetNames { - /** - * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1. - *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - */ - public static final String ISO_8859_1 = "ISO-8859-1"; - - /** - *

- * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - */ - public static final String US_ASCII = "US-ASCII"; - - /** - *

- * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark - * (either order accepted on input, big-endian used on output) - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - */ - public static final String UTF_16 = "UTF-16"; - - /** - *

- * Sixteen-bit Unicode Transformation Format, big-endian byte order. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - */ - public static final String UTF_16BE = "UTF-16BE"; - - /** - *

- * Sixteen-bit Unicode Transformation Format, little-endian byte order. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - */ - public static final String UTF_16LE = "UTF-16LE"; - - /** - *

- * Eight-bit Unicode Transformation Format. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - */ - public static final String UTF_8 = "UTF-8"; -} diff --git a/src/org/apache/commons/compress/utils/Charsets.java b/src/org/apache/commons/compress/utils/Charsets.java deleted file mode 100644 index 9f5240af89f..00000000000 --- a/src/org/apache/commons/compress/utils/Charsets.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.utils; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -/** - * Charsets required of every implementation of the Java platform. - * - * From the Java documentation Standard - * charsets: - *

- * Every implementation of the Java platform is required to support the following character encodings. Consult the - * release documentation for your implementation to see if any other encodings are supported. Consult the release - * documentation for your implementation to see if any other encodings are supported. - *

- * - *
- *
US-ASCII
- *
Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
- *
ISO-8859-1
- *
ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
- *
UTF-8
- *
Eight-bit Unicode Transformation Format.
- *
UTF-16BE
- *
Sixteen-bit Unicode Transformation Format, big-endian byte order.
- *
UTF-16LE
- *
Sixteen-bit Unicode Transformation Format, little-endian byte order.
- *
UTF-16
- *
Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order - * accepted on input, big-endian used on output.)
- *
- * - *

This class best belongs in the Commons Lang or IO project. Even if a similar class is defined in another Commons - * component, it is not foreseen that Commons Compress would be made to depend on another Commons component.

- * - * @see Standard charsets - * @see StandardCharsets - * @since 1.4 - */ -public class Charsets { - - // - // This class should only contain Charset instances for required encodings. This guarantees that it will load correctly and - // without delay on all Java platforms. - // - - /** - * Returns the given Charset or the default Charset if the given Charset is null. - * - * @param charset - * A charset or null. - * @return the given Charset or the default Charset if the given Charset is null - */ - public static Charset toCharset(final Charset charset) { - return charset == null ? Charset.defaultCharset() : charset; - } - - /** - * Returns a Charset for the named charset. If the name is null, return the default Charset. - * - * @param charset - * The name of the requested charset, may be null. - * @return a Charset for the named charset - * @throws java.nio.charset.UnsupportedCharsetException - * If the named charset is unavailable - * @throws java.nio.charset.IllegalCharsetNameException - * If the given charset name is illegal - */ - public static Charset toCharset(final String charset) { - return charset == null ? Charset.defaultCharset() : Charset.forName(charset); - } - - /** - * CharsetNamesISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1. - *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated replaced by {@link StandardCharsets} in Java 7 - */ - public static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1; - - /** - *

- * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated replaced by {@link StandardCharsets} in Java 7 - */ - public static final Charset US_ASCII = StandardCharsets.US_ASCII; - - /** - *

- * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark - * (either order accepted on input, big-endian used on output) - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated replaced by {@link StandardCharsets} in Java 7 - */ - public static final Charset UTF_16 = StandardCharsets.UTF_16; - - /** - *

- * Sixteen-bit Unicode Transformation Format, big-endian byte order. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated replaced by {@link StandardCharsets} in Java 7 - */ - public static final Charset UTF_16BE = StandardCharsets.UTF_16BE; - - /** - *

- * Sixteen-bit Unicode Transformation Format, little-endian byte order. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated replaced by {@link StandardCharsets} in Java 7 - */ - public static final Charset UTF_16LE = StandardCharsets.UTF_16LE; - - /** - *

- * Eight-bit Unicode Transformation Format. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated replaced by {@link StandardCharsets} in Java 7 - */ - public static final Charset UTF_8 = StandardCharsets.UTF_8; -} diff --git a/src/org/apache/commons/compress/utils/ChecksumCalculatingInputStream.java b/src/org/apache/commons/compress/utils/ChecksumCalculatingInputStream.java deleted file mode 100644 index 4a408a564ce..00000000000 --- a/src/org/apache/commons/compress/utils/ChecksumCalculatingInputStream.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.utils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.Checksum; - -/** - * A stream that calculates the checksum of the data read. - * @NotThreadSafe - * @since 1.14 - */ -public class ChecksumCalculatingInputStream extends InputStream { - private final InputStream in; - private final Checksum checksum; - - public ChecksumCalculatingInputStream(final Checksum checksum, final InputStream in) { - - if ( checksum == null ){ - throw new NullPointerException("Parameter checksum must not be null"); - } - - if ( in == null ){ - throw new NullPointerException("Parameter in must not be null"); - } - - this.checksum = checksum; - this.in = in; - } - - /** - * Reads a single byte from the stream - * @throws IOException if the underlying stream throws or the - * stream is exhausted and the Checksum doesn't match the expected - * value - */ - @Override - public int read() throws IOException { - final int ret = in.read(); - if (ret >= 0) { - checksum.update(ret); - } - return ret; - } - - /** - * Reads a byte array from the stream - * @throws IOException if the underlying stream throws or the - * stream is exhausted and the Checksum doesn't match the expected - * value - */ - @Override - public int read(final byte[] b) throws IOException { - return read(b, 0, b.length); - } - - /** - * Reads from the stream into a byte array. - * @throws IOException if the underlying stream throws or the - * stream is exhausted and the Checksum doesn't match the expected - * value - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - final int ret = in.read(b, off, len); - if (ret >= 0) { - checksum.update(b, off, ret); - } - return ret; - } - - @Override - public long skip(final long n) throws IOException { - // Can't really skip, we have to hash everything to verify the checksum - if (read() >= 0) { - return 1; - } - return 0; - } - - /** - * Returns the calculated checksum. - * @return the calculated checksum. - */ - public long getValue() { - return checksum.getValue(); - } - -} diff --git a/src/org/apache/commons/compress/utils/ChecksumVerifyingInputStream.java b/src/org/apache/commons/compress/utils/ChecksumVerifyingInputStream.java deleted file mode 100644 index a7d8d6ce511..00000000000 --- a/src/org/apache/commons/compress/utils/ChecksumVerifyingInputStream.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.utils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.Checksum; - -/** - * A stream that verifies the checksum of the data read once the stream is - * exhausted. - * @NotThreadSafe - * @since 1.7 - */ -public class ChecksumVerifyingInputStream extends InputStream { - private final InputStream in; - private long bytesRemaining; - private final long expectedChecksum; - private final Checksum checksum; - - public ChecksumVerifyingInputStream(final Checksum checksum, final InputStream in, - final long size, final long expectedChecksum) { - this.checksum = checksum; - this.in = in; - this.expectedChecksum = expectedChecksum; - this.bytesRemaining = size; - } - - /** - * Reads a single byte from the stream - * @throws IOException if the underlying stream throws or the - * stream is exhausted and the Checksum doesn't match the expected - * value - */ - @Override - public int read() throws IOException { - if (bytesRemaining <= 0) { - return -1; - } - final int ret = in.read(); - if (ret >= 0) { - checksum.update(ret); - --bytesRemaining; - } - if (bytesRemaining == 0 && expectedChecksum != checksum.getValue()) { - throw new IOException("Checksum verification failed"); - } - return ret; - } - - /** - * Reads a byte array from the stream - * @throws IOException if the underlying stream throws or the - * stream is exhausted and the Checksum doesn't match the expected - * value - */ - @Override - public int read(final byte[] b) throws IOException { - return read(b, 0, b.length); - } - - /** - * Reads from the stream into a byte array. - * @throws IOException if the underlying stream throws or the - * stream is exhausted and the Checksum doesn't match the expected - * value - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - final int ret = in.read(b, off, len); - if (ret >= 0) { - checksum.update(b, off, ret); - bytesRemaining -= ret; - } - if (bytesRemaining <= 0 && expectedChecksum != checksum.getValue()) { - throw new IOException("Checksum verification failed"); - } - return ret; - } - - @Override - public long skip(final long n) throws IOException { - // Can't really skip, we have to hash everything to verify the checksum - if (read() >= 0) { - return 1; - } - return 0; - } - - @Override - public void close() throws IOException { - in.close(); - } -} diff --git a/src/org/apache/commons/compress/utils/CloseShieldFilterInputStream.java b/src/org/apache/commons/compress/utils/CloseShieldFilterInputStream.java deleted file mode 100644 index a0ec8ff4b51..00000000000 --- a/src/org/apache/commons/compress/utils/CloseShieldFilterInputStream.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.utils; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Re-implements {@link FilterInputStream#close()} to do nothing. - * @since 1.14 - */ -public class CloseShieldFilterInputStream extends FilterInputStream { - - public CloseShieldFilterInputStream(InputStream in) { - super(in); - } - - @Override - public void close() throws IOException { - // NO IMPLEMENTATION. - } - -} diff --git a/src/org/apache/commons/compress/utils/CountingInputStream.java b/src/org/apache/commons/compress/utils/CountingInputStream.java deleted file mode 100644 index 461071e8dce..00000000000 --- a/src/org/apache/commons/compress/utils/CountingInputStream.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.utils; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Stream that tracks the number of bytes read. - * @since 1.3 - * @NotThreadSafe - */ -public class CountingInputStream extends FilterInputStream { - private long bytesRead; - - public CountingInputStream(final InputStream in) { - super(in); - } - - @Override - public int read() throws IOException { - final int r = in.read(); - if (r >= 0) { - count(1); - } - return r; - } - @Override - public int read(final byte[] b) throws IOException { - return read(b, 0, b.length); - } - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - final int r = in.read(b, off, len); - if (r >= 0) { - count(r); - } - return r; - } - /** - * Increments the counter of already read bytes. - * Doesn't increment if the EOF has been hit (read == -1) - * - * @param read the number of bytes read - */ - protected final void count(final long read) { - if (read != -1) { - bytesRead += read; - } - } - - /** - * Returns the current number of bytes read from this stream. - * @return the number of read bytes - */ - public long getBytesRead() { - return bytesRead; - } -} diff --git a/src/org/apache/commons/compress/utils/CountingOutputStream.java b/src/org/apache/commons/compress/utils/CountingOutputStream.java deleted file mode 100644 index ac886bcd442..00000000000 --- a/src/org/apache/commons/compress/utils/CountingOutputStream.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.utils; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Stream that tracks the number of bytes read. - * @since 1.3 - * @NotThreadSafe - */ -public class CountingOutputStream extends FilterOutputStream { - private long bytesWritten = 0; - - public CountingOutputStream(final OutputStream out) { - super(out); - } - - @Override - public void write(final int b) throws IOException { - out.write(b); - count(1); - } - @Override - public void write(final byte[] b) throws IOException { - write(b, 0, b.length); - } - @Override - public void write(final byte[] b, final int off, final int len) throws IOException { - out.write(b, off, len); - count(len); - } - - /** - * Increments the counter of already written bytes. - * Doesn't increment if the EOF has been hit (written == -1) - * - * @param written the number of bytes written - */ - protected void count(final long written) { - if (written != -1) { - bytesWritten += written; - } - } - - /** - * Returns the current number of bytes written to this stream. - * @return the number of written bytes - */ - public long getBytesWritten() { - return bytesWritten; - } -} diff --git a/src/org/apache/commons/compress/utils/FixedLengthBlockOutputStream.java b/src/org/apache/commons/compress/utils/FixedLengthBlockOutputStream.java deleted file mode 100644 index d9f2f80f3f5..00000000000 --- a/src/org/apache/commons/compress/utils/FixedLengthBlockOutputStream.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.utils; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.WritableByteChannel; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This class supports writing to an Outputstream or WritableByteChannel in fixed length blocks. - *

It can be be used to support output to devices such as tape drives that require output in this - * format. If the final block does not have enough content to fill an entire block, the output will - * be padded to a full block size.

- * - *

This class can be used to support TAR,PAX, and CPIO blocked output to character special devices. - * It is not recommended that this class be used unless writing to such devices, as the padding - * serves no useful purpose in such cases.

- * - *

This class should normally wrap a FileOutputStream or associated WritableByteChannel directly. - * If there is an intervening filter that modified the output, such as a CompressorOutputStream, or - * performs its own buffering, such as BufferedOutputStream, output to the device may - * no longer be of the specified size.

- * - *

Any content written to this stream should be self-delimiting and should tolerate any padding - * added to fill the last block.

- * - * @since 1.15 - */ -public class FixedLengthBlockOutputStream extends OutputStream implements WritableByteChannel { - - private final WritableByteChannel out; - private final int blockSize; - private final ByteBuffer buffer; - private final AtomicBoolean closed = new AtomicBoolean(false); - - /** - * Create a fixed length block output stream with given destination stream and block size - * @param os The stream to wrap. - * @param blockSize The block size to use. - */ - public FixedLengthBlockOutputStream(OutputStream os, int blockSize) { - if (os instanceof FileOutputStream) { - FileOutputStream fileOutputStream = (FileOutputStream) os; - out = fileOutputStream.getChannel(); - buffer = ByteBuffer.allocateDirect(blockSize); - } else { - out = new BufferAtATimeOutputChannel(os); - buffer = ByteBuffer.allocate(blockSize); - } - this.blockSize = blockSize; - } - /** - * Create a fixed length block output stream with given destination writable byte channel and block size - * @param out The writable byte channel to wrap. - * @param blockSize The block size to use. - */ - public FixedLengthBlockOutputStream(WritableByteChannel out, int blockSize) { - this.out = out; - this.blockSize = blockSize; - this.buffer = ByteBuffer.allocateDirect(blockSize); - } - - private void maybeFlush() throws IOException { - if (!buffer.hasRemaining()) { - writeBlock(); - } - } - - private void writeBlock() throws IOException { - buffer.flip(); - int i = out.write(buffer); - boolean hasRemaining = buffer.hasRemaining(); - if (i != blockSize || hasRemaining) { - String msg = String - .format("Failed to write %,d bytes atomically. Only wrote %,d", - blockSize, i); - throw new IOException(msg); - } - buffer.clear(); - } - - @Override - public void write(int b) throws IOException { - if (!isOpen()) { - throw new ClosedChannelException(); - } - buffer.put((byte) b); - maybeFlush(); - } - - @Override - public void write(byte[] b, final int offset, final int length) throws IOException { - if (!isOpen()) { - throw new ClosedChannelException(); - } - int off = offset; - int len = length; - while (len > 0) { - int n = Math.min(len, buffer.remaining()); - buffer.put(b, off, n); - maybeFlush(); - len -= n; - off += n; - } - } - - @Override - public int write(ByteBuffer src) throws IOException { - if (!isOpen()) { - throw new ClosedChannelException(); - } - int srcRemaining = src.remaining(); - - if (srcRemaining < buffer.remaining()) { - // if don't have enough bytes in src to fill up a block we must buffer - buffer.put(src); - } else { - int srcLeft = srcRemaining; - int savedLimit = src.limit(); - // If we're not at the start of buffer, we have some bytes already buffered - // fill up the reset of buffer and write the block. - if (buffer.position() != 0) { - int n = buffer.remaining(); - src.limit(src.position() + n); - buffer.put(src); - writeBlock(); - srcLeft -= n; - } - // whilst we have enough bytes in src for complete blocks, - // write them directly from src without copying them to buffer - while (srcLeft >= blockSize) { - src.limit(src.position() + blockSize); - out.write(src); - srcLeft -= blockSize; - } - // copy any remaining bytes into buffer - src.limit(savedLimit); - buffer.put(src); - } - return srcRemaining; - } - - @Override - public boolean isOpen() { - if (!out.isOpen()) { - closed.set(true); - } - return !closed.get(); - } - - /** - * Potentially pads and then writes the current block to the underlying stream. - * @throws IOException if writing fails - */ - public void flushBlock() throws IOException { - if (buffer.position() != 0) { - padBlock(); - writeBlock(); - } - } - - @Override - public void close() throws IOException { - if (closed.compareAndSet(false, true)) { - flushBlock(); - out.close(); - } - } - - private void padBlock() { - buffer.order(ByteOrder.nativeOrder()); - int bytesToWrite = buffer.remaining(); - if (bytesToWrite > 8) { - int align = buffer.position() & 7; - if (align != 0) { - int limit = 8 - align; - for (int i = 0; i < limit; i++) { - buffer.put((byte) 0); - } - bytesToWrite -= limit; - } - - while (bytesToWrite >= 8) { - buffer.putLong(0L); - bytesToWrite -= 8; - } - } - while (buffer.hasRemaining()) { - buffer.put((byte) 0); - } - } - - /** - * Helper class to provide channel wrapper for arbitrary output stream that doesn't alter the - * size of writes. We can't use Channels.newChannel, because for non FileOutputStreams, it - * breaks up writes into 8KB max chunks. Since the purpose of this class is to always write - * complete blocks, we need to write a simple class to take care of it. - */ - private static class BufferAtATimeOutputChannel implements WritableByteChannel { - - private final OutputStream out; - private final AtomicBoolean closed = new AtomicBoolean(false); - - private BufferAtATimeOutputChannel(OutputStream out) { - this.out = out; - } - - @Override - public int write(ByteBuffer buffer) throws IOException { - if (!isOpen()) { - throw new ClosedChannelException(); - } - if (!buffer.hasArray()) { - throw new IllegalArgumentException("direct buffer somehow written to BufferAtATimeOutputChannel"); - } - - try { - int pos = buffer.position(); - int len = buffer.limit() - pos; - out.write(buffer.array(), buffer.arrayOffset() + pos, len); - buffer.position(buffer.limit()); - return len; - } catch (IOException e) { - try { - close(); - } catch (IOException ignored) { //NOSONAR - } - throw e; - } - } - - @Override - public boolean isOpen() { - return !closed.get(); - } - - @Override - public void close() throws IOException { - if (closed.compareAndSet(false, true)) { - out.close(); - } - } - - } - - -} diff --git a/src/org/apache/commons/compress/utils/FlushShieldFilterOutputStream.java b/src/org/apache/commons/compress/utils/FlushShieldFilterOutputStream.java deleted file mode 100644 index 239e8237406..00000000000 --- a/src/org/apache/commons/compress/utils/FlushShieldFilterOutputStream.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.utils; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Re-implements {@link FilterOutputStream#flush()} to do nothing. - */ -public class FlushShieldFilterOutputStream extends FilterOutputStream { - - public FlushShieldFilterOutputStream(OutputStream out) { - super(out); - } - - @Override - public void flush() throws IOException { - // NO IMPLEMENTATION. - } - -} diff --git a/src/org/apache/commons/compress/utils/IOUtils.java b/src/org/apache/commons/compress/utils/IOUtils.java deleted file mode 100644 index 50577c90dd5..00000000000 --- a/src/org/apache/commons/compress/utils/IOUtils.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.utils; - -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.ReadableByteChannel; - -/** - * Utility functions - * @Immutable (has mutable data but it is write-only) - */ -public final class IOUtils { - - private static final int COPY_BUF_SIZE = 8024; - private static final int SKIP_BUF_SIZE = 4096; - - // This buffer does not need to be synchronised because it is write only; the contents are ignored - // Does not affect Immutability - private static final byte[] SKIP_BUF = new byte[SKIP_BUF_SIZE]; - - /** Private constructor to prevent instantiation of this utility class. */ - private IOUtils(){ - } - - /** - * Copies the content of a InputStream into an OutputStream. - * Uses a default buffer size of 8024 bytes. - * - * @param input - * the InputStream to copy - * @param output - * the target Stream - * @return the number of bytes copied - * @throws IOException - * if an error occurs - */ - public static long copy(final InputStream input, final OutputStream output) throws IOException { - return copy(input, output, COPY_BUF_SIZE); - } - - /** - * Copies the content of a InputStream into an OutputStream - * - * @param input - * the InputStream to copy - * @param output - * the target Stream - * @param buffersize - * the buffer size to use, must be bigger than 0 - * @return the number of bytes copied - * @throws IOException - * if an error occurs - * @throws IllegalArgumentException - * if buffersize is smaller than or equal to 0 - */ - public static long copy(final InputStream input, final OutputStream output, final int buffersize) throws IOException { - if (buffersize < 1) { - throw new IllegalArgumentException("buffersize must be bigger than 0"); - } - final byte[] buffer = new byte[buffersize]; - int n = 0; - long count=0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Skips the given number of bytes by repeatedly invoking skip on - * the given input stream if necessary. - * - *

In a case where the stream's skip() method returns 0 before - * the requested number of bytes has been skip this implementation - * will fall back to using the read() method.

- * - *

This method will only skip less than the requested number of - * bytes if the end of the input stream has been reached.

- * - * @param input stream to skip bytes in - * @param numToSkip the number of bytes to skip - * @return the number of bytes actually skipped - * @throws IOException on error - */ - public static long skip(final InputStream input, long numToSkip) throws IOException { - final long available = numToSkip; - while (numToSkip > 0) { - final long skipped = input.skip(numToSkip); - if (skipped == 0) { - break; - } - numToSkip -= skipped; - } - - while (numToSkip > 0) { - final int read = readFully(input, SKIP_BUF, 0, - (int) Math.min(numToSkip, SKIP_BUF_SIZE)); - if (read < 1) { - break; - } - numToSkip -= read; - } - return available - numToSkip; - } - - /** - * Reads as much from input as possible to fill the given array. - * - *

This method may invoke read repeatedly to fill the array and - * only read less bytes than the length of the array if the end of - * the stream has been reached.

- * - * @param input stream to read from - * @param b buffer to fill - * @return the number of bytes actually read - * @throws IOException on error - */ - public static int readFully(final InputStream input, final byte[] b) throws IOException { - return readFully(input, b, 0, b.length); - } - - /** - * Reads as much from input as possible to fill the given array - * with the given amount of bytes. - * - *

This method may invoke read repeatedly to read the bytes and - * only read less bytes than the requested length if the end of - * the stream has been reached.

- * - * @param input stream to read from - * @param b buffer to fill - * @param offset offset into the buffer to start filling at - * @param len of bytes to read - * @return the number of bytes actually read - * @throws IOException - * if an I/O error has occurred - */ - public static int readFully(final InputStream input, final byte[] b, final int offset, final int len) - throws IOException { - if (len < 0 || offset < 0 || len + offset > b.length) { - throw new IndexOutOfBoundsException(); - } - int count = 0, x = 0; - while (count != len) { - x = input.read(b, offset + count, len - count); - if (x == -1) { - break; - } - count += x; - } - return count; - } - - /** - * Reads {@code b.remaining()} bytes from the given channel - * starting at the current channel's position. - * - *

This method reads repeatedly from the channel until the - * requested number of bytes are read. This method blocks until - * the requested number of bytes are read, the end of the channel - * is detected, or an exception is thrown.

- * - * @param channel the channel to read from - * @param b the buffer into which the data is read. - * @throws IOException - if an I/O error occurs. - * @throws EOFException - if the channel reaches the end before reading all the bytes. - */ - public static void readFully(ReadableByteChannel channel, ByteBuffer b) throws IOException { - final int expectedLength = b.remaining(); - int read = 0; - while (read < expectedLength) { - int readNow = channel.read(b); - if (readNow <= 0) { - break; - } - read += readNow; - } - if (read < expectedLength) { - throw new EOFException(); - } - } - - // toByteArray(InputStream) copied from: - // commons/proper/io/trunk/src/main/java/org/apache/commons/io/IOUtils.java?revision=1428941 - // January 8th, 2013 - // - // Assuming our copy() works just as well as theirs! :-) - - /** - * Gets the contents of an InputStream as a byte[]. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 1.5 - */ - public static byte[] toByteArray(final InputStream input) throws IOException { - final ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output); - return output.toByteArray(); - } - - /** - * Closes the given Closeable and swallows any IOException that may occur. - * @param c Closeable to close, can be null - * @since 1.7 - */ - public static void closeQuietly(final Closeable c) { - if (c != null) { - try { - c.close(); - } catch (final IOException ignored) { // NOPMD - } - } - } -} diff --git a/src/org/apache/commons/compress/utils/InputStreamStatistics.java b/src/org/apache/commons/compress/utils/InputStreamStatistics.java deleted file mode 100644 index 569ab3687b7..00000000000 --- a/src/org/apache/commons/compress/utils/InputStreamStatistics.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.utils; - -/** - * This interface provides statistics on the current decompression stream. - * The stream consumer can use that statistics to handle abnormal - * compression ratios, i.e. to prevent zip bombs. - * - * @since 1.17 - */ -public interface InputStreamStatistics { - /** - * @return the amount of raw or compressed bytes read by the stream - */ - long getCompressedCount(); - - /** - * @return the amount of decompressed bytes returned by the stream - */ - long getUncompressedCount(); -} diff --git a/src/org/apache/commons/compress/utils/Iterators.java b/src/org/apache/commons/compress/utils/Iterators.java deleted file mode 100644 index 0db0c36017f..00000000000 --- a/src/org/apache/commons/compress/utils/Iterators.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.utils; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Objects; - -/** - * Iterator utilities. - * - * @since 1.13. - */ -public class Iterators { - - /** - * Adds all the elements in the source {@code iterator} to the target - * {@code collection}. - * - *

- * When this method returns, the {@code iterator} will be "empty": its - * {@code hasNext()} method returns {@code false}. - *

- * - * @param type of the elements contained inside the collection - * @param collection target collection - * @param iterator source - * @return {@code true} if the target {@code collection} was modified as a - * result of this operation - */ - public static boolean addAll(final Collection collection, final Iterator iterator) { - Objects.requireNonNull(collection); - Objects.requireNonNull(iterator); - boolean wasModified = false; - while (iterator.hasNext()) { - wasModified |= collection.add(iterator.next()); - } - return wasModified; - } - - private Iterators() { - // do not instantiate - } - -} diff --git a/src/org/apache/commons/compress/utils/Lists.java b/src/org/apache/commons/compress/utils/Lists.java deleted file mode 100644 index e7a82dc6a75..00000000000 --- a/src/org/apache/commons/compress/utils/Lists.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.utils; - -import java.util.ArrayList; -import java.util.Iterator; - -/** - * List utilities - * - * @since 1.13 - */ -public class Lists { - - /** - * Creates a new {@link ArrayList}. - * - * @param type of elements contained in new list - * @return a new {@link ArrayList} - */ - public static ArrayList newArrayList() { - return new ArrayList<>(); - } - - /** - * Creates a new {@link ArrayList} filled with the contents of the given - * {@code iterator}. - * - * @param iterator - * the source iterator - * @param type of elements contained in new list - * @return a new {@link ArrayList} - */ - public static ArrayList newArrayList(final Iterator iterator) { - final ArrayList list = newArrayList(); - Iterators.addAll(list, iterator); - return list; - } - - private Lists() { - // do not instantiate - } - -} diff --git a/src/org/apache/commons/compress/utils/NoCloseInputStream.java b/src/org/apache/commons/compress/utils/NoCloseInputStream.java deleted file mode 100644 index bdc0ee9b9ff..00000000000 --- a/src/org/apache/commons/compress/utils/NoCloseInputStream.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.compress.utils; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Wrapper that overrides {@link #close} so that it doesn't close the - * underlying stream. - * - * @since 1.17 - */ -public class NoCloseInputStream extends FilterInputStream { - - public NoCloseInputStream(InputStream in) { - super(in); - } - - /** - * This method does nothing. - */ - public void close() { - // do not close the stream - } -} diff --git a/src/org/apache/commons/compress/utils/SeekableInMemoryByteChannel.java b/src/org/apache/commons/compress/utils/SeekableInMemoryByteChannel.java deleted file mode 100644 index eece7f5bb6d..00000000000 --- a/src/org/apache/commons/compress/utils/SeekableInMemoryByteChannel.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.compress.utils; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SeekableByteChannel; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * A {@link SeekableByteChannel} implementation that wraps a byte[]. - * - *

When this channel is used for writing an internal buffer grows to accommodate - * incoming data. A natural size limit is the value of {@link Integer#MAX_VALUE}. - * Internal buffer can be accessed via {@link SeekableInMemoryByteChannel#array()}.

- * - * @since 1.13 - * @NotThreadSafe - */ -public class SeekableInMemoryByteChannel implements SeekableByteChannel { - - private static final int NAIVE_RESIZE_LIMIT = Integer.MAX_VALUE >> 1; - - private byte[] data; - private final AtomicBoolean closed = new AtomicBoolean(); - private int position, size; - - /** - * Constructor taking a byte array. - * - *

This constructor is intended to be used with pre-allocated buffer or when - * reading from a given byte array.

- * - * @param data input data or pre-allocated array. - */ - public SeekableInMemoryByteChannel(byte[] data) { - this.data = data; - size = data.length; - } - - /** - * Parameterless constructor - allocates internal buffer by itself. - */ - public SeekableInMemoryByteChannel() { - this(new byte[0]); - } - - /** - * Constructor taking a size of storage to be allocated. - * - *

Creates a channel and allocates internal storage of a given size.

- * - * @param size size of internal buffer to allocate, in bytes. - */ - public SeekableInMemoryByteChannel(int size) { - this(new byte[size]); - } - - @Override - public long position() { - return position; - } - - @Override - public SeekableByteChannel position(long newPosition) throws IOException { - ensureOpen(); - if (newPosition < 0L || newPosition > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Position has to be in range 0.. " + Integer.MAX_VALUE); - } - position = (int) newPosition; - return this; - } - - @Override - public long size() { - return size; - } - - @Override - public SeekableByteChannel truncate(long newSize) { - if (size > newSize) { - size = (int) newSize; - } - repositionIfNecessary(); - return this; - } - - @Override - public int read(ByteBuffer buf) throws IOException { - ensureOpen(); - repositionIfNecessary(); - int wanted = buf.remaining(); - int possible = size - position; - if (possible <= 0) { - return -1; - } - if (wanted > possible) { - wanted = possible; - } - buf.put(data, position, wanted); - position += wanted; - return wanted; - } - - @Override - public void close() { - closed.set(true); - } - - @Override - public boolean isOpen() { - return !closed.get(); - } - - @Override - public int write(ByteBuffer b) throws IOException { - ensureOpen(); - int wanted = b.remaining(); - int possibleWithoutResize = size - position; - if (wanted > possibleWithoutResize) { - int newSize = position + wanted; - if (newSize < 0) { // overflow - resize(Integer.MAX_VALUE); - wanted = Integer.MAX_VALUE - position; - } else { - resize(newSize); - } - } - b.get(data, position, wanted); - position += wanted; - if (size < position) { - size = position; - } - return wanted; - } - - /** - * Obtains the array backing this channel. - * - *

NOTE: - * The returned buffer is not aligned with containing data, use - * {@link #size()} to obtain the size of data stored in the buffer.

- * - * @return internal byte array. - */ - public byte[] array() { - return data; - } - - private void resize(int newLength) { - int len = data.length; - if (len <= 0) { - len = 1; - } - if (newLength < NAIVE_RESIZE_LIMIT) { - while (len < newLength) { - len <<= 1; - } - } else { // avoid overflow - len = newLength; - } - data = Arrays.copyOf(data, len); - } - - private void ensureOpen() throws ClosedChannelException { - if (!isOpen()) { - throw new ClosedChannelException(); - } - } - - private void repositionIfNecessary() { - if (position > size) { - position = size; - } - } - -} diff --git a/src/org/apache/commons/compress/utils/ServiceLoaderIterator.java b/src/org/apache/commons/compress/utils/ServiceLoaderIterator.java deleted file mode 100644 index aeda85721cd..00000000000 --- a/src/org/apache/commons/compress/utils/ServiceLoaderIterator.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.utils; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; - -/** - * Iterates all services for a given class through the standard - * {@link ServiceLoader} mechanism. - * - * @param - * The service to load - * @since 1.13 - */ -public class ServiceLoaderIterator implements Iterator { - - private E nextServiceLoader; - private final Class service; - private final Iterator serviceLoaderIterator; - - public ServiceLoaderIterator(final Class service) { - this(service, ClassLoader.getSystemClassLoader()); - } - - public ServiceLoaderIterator(final Class service, final ClassLoader classLoader) { - this.service = service; - final ServiceLoader serviceLoader = ServiceLoader.load(service, classLoader); - serviceLoaderIterator = serviceLoader.iterator(); - nextServiceLoader = null; - } - - private boolean getNextServiceLoader() { - while (nextServiceLoader == null) { - try { - if (!serviceLoaderIterator.hasNext()) { - return false; - } - nextServiceLoader = serviceLoaderIterator.next(); - } catch (final ServiceConfigurationError e) { - if (e.getCause() instanceof SecurityException) { - // Ignore security exceptions - // TODO Log? - continue; - } - throw e; - } - } - return true; - } - - @Override - public boolean hasNext() { - return getNextServiceLoader(); - } - - @Override - public E next() { - if (!getNextServiceLoader()) { - throw new NoSuchElementException("No more elements for service " + service.getName()); - } - final E tempNext = nextServiceLoader; - nextServiceLoader = null; - return tempNext; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("service=" + service.getName()); - } - -} diff --git a/src/org/apache/commons/compress/utils/Sets.java b/src/org/apache/commons/compress/utils/Sets.java deleted file mode 100644 index 29981208dfd..00000000000 --- a/src/org/apache/commons/compress/utils/Sets.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.commons.compress.utils; - -import java.util.Collections; -import java.util.HashSet; - -/** - * Set utilities - * - * @since 1.13 - */ -public class Sets { - - private Sets() { - // Do not instantiate - } - - /** - * Creates a new HashSet filled with the given elements - * - * @param elements - * the elements to fill the new set - * @param type of elements contained in new set - * @return A new HasSet - */ - public static HashSet newHashSet(@SuppressWarnings("unchecked") E... elements) { - final HashSet set = new HashSet<>(elements.length); - Collections.addAll(set, elements); - return set; - } -} diff --git a/src/org/apache/commons/compress/utils/SkipShieldingInputStream.java b/src/org/apache/commons/compress/utils/SkipShieldingInputStream.java deleted file mode 100644 index 09b5ce21de8..00000000000 --- a/src/org/apache/commons/compress/utils/SkipShieldingInputStream.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.commons.compress.utils; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * A wrapper that overwrites {@link #skip} and delegates to {@link #read} instead. - * - *

Some implementations of {@link InputStream} implement {@link - * InputStream#skip} in a way that throws an expecption if the stream - * is not seekable - {@link System#in System.in} is known to behave - * that way. For such a stream it is impossible to invoke skip at all - * and you have to read from the stream (and discard the data read) - * instead. Skipping is potentially much faster than reading so we do - * want to invoke {@code skip} when possible. We provide this class so - * you can wrap your own {@link InputStream} in it if you encounter - * problems with {@code skip} throwing an excpetion.

- * - * @since 1.17 - */ -public class SkipShieldingInputStream extends FilterInputStream { - private static final int SKIP_BUFFER_SIZE = 8192; - // we can use a shared buffer as the content is discarded anyway - private static final byte[] SKIP_BUFFER = new byte[SKIP_BUFFER_SIZE]; - public SkipShieldingInputStream(InputStream in) { - super(in); - } - - @Override - public long skip(long n) throws IOException { - return n < 0 ? 0 : read(SKIP_BUFFER, 0, (int) Math.min(n, SKIP_BUFFER_SIZE)); - } -} diff --git a/src/org/apache/commons/compress/utils/package.html b/src/org/apache/commons/compress/utils/package.html deleted file mode 100644 index 0409d1267b3..00000000000 --- a/src/org/apache/commons/compress/utils/package.html +++ /dev/null @@ -1,23 +0,0 @@ - - - -

Contains utilities used internally by the compress library.

- - diff --git a/src/org/apache/commons/jcs/JCS.java b/src/org/apache/commons/jcs/JCS.java deleted file mode 100644 index 282988be479..00000000000 --- a/src/org/apache/commons/jcs/JCS.java +++ /dev/null @@ -1,210 +0,0 @@ -package org.apache.commons.jcs; - -import java.util.Properties; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.CacheAccess; -import org.apache.commons.jcs.access.GroupCacheAccess; -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.CompositeCacheManager; -import org.apache.commons.jcs.engine.control.group.GroupAttrName; - -/** - * Simple class for using JCS. To use JCS in your application, you can use the static methods of - * this class to get access objects (instances of this class) for your cache regions. One CacheAccess - * object should be created for each region you want to access. If you have several regions, then - * get instances for each. For best performance the getInstance call should be made in an - * initialization method. - */ -public abstract class JCS -{ - /** cache.ccf alternative. */ - private static String configFilename = null; - - /** alternative configuration properties */ - private static Properties configProps = null; - - /** Cache manager use by the various forms of defineRegion and getAccess */ - private static CompositeCacheManager cacheMgr; - - /** - * Set the filename that the cache manager will be initialized with. Only matters before the - * instance is initialized. - *

- * @param configFilename - */ - public static void setConfigFilename( String configFilename ) - { - JCS.configFilename = configFilename; - } - - /** - * Set the properties that the cache manager will be initialized with. Only - * matters before the instance is initialized. - * - * @param configProps - */ - public static void setConfigProperties( Properties configProps ) - { - JCS.configProps = configProps; - } - - /** - * Shut down the cache manager and set the instance to null - */ - public static void shutdown() - { - synchronized ( JCS.class ) - { - if ( cacheMgr != null && cacheMgr.isInitialized()) - { - cacheMgr.shutDown(); - } - - cacheMgr = null; - } - } - - /** - * Helper method which checks to make sure the cacheMgr class field is set, and if not requests - * an instance from CacheManagerFactory. - * - * @throws CacheException if the configuration cannot be loaded - */ - private static CompositeCacheManager getCacheManager() throws CacheException - { - synchronized ( JCS.class ) - { - if ( cacheMgr == null || !cacheMgr.isInitialized()) - { - if ( configProps != null ) - { - cacheMgr = CompositeCacheManager.getUnconfiguredInstance(); - cacheMgr.configure( configProps ); - } - else if ( configFilename != null ) - { - cacheMgr = CompositeCacheManager.getUnconfiguredInstance(); - cacheMgr.configure( configFilename ); - } - else - { - cacheMgr = CompositeCacheManager.getInstance(); - } - } - - return cacheMgr; - } - } - - /** - * Get a CacheAccess which accesses the provided region. - *

- * @param region Region that return CacheAccess will provide access to - * @return A CacheAccess which provides access to a given region. - * @throws CacheException - */ - public static CacheAccess getInstance( String region ) - throws CacheException - { - CompositeCache cache = getCacheManager().getCache( region ); - return new CacheAccess( cache ); - } - - /** - * Get a CacheAccess which accesses the provided region. - *

- * @param region Region that return CacheAccess will provide access to - * @param icca CacheAttributes for region - * @return A CacheAccess which provides access to a given region. - * @throws CacheException - */ - public static CacheAccess getInstance( String region, ICompositeCacheAttributes icca ) - throws CacheException - { - CompositeCache cache = getCacheManager().getCache( region, icca ); - return new CacheAccess( cache ); - } - - /** - * Get a CacheAccess which accesses the provided region. - *

- * @param region Region that return CacheAccess will provide access to - * @param icca CacheAttributes for region - * @param eattr ElementAttributes for the region - * @return A CacheAccess which provides access to a given region. - * @throws CacheException - */ - public static CacheAccess getInstance( String region, ICompositeCacheAttributes icca, IElementAttributes eattr ) - throws CacheException - { - CompositeCache cache = getCacheManager().getCache( region, icca, eattr ); - return new CacheAccess( cache ); - } - - /** - * Get a GroupCacheAccess which accesses the provided region. - *

- * @param region Region that return GroupCacheAccess will provide access to - * @return A GroupCacheAccess which provides access to a given region. - * @throws CacheException - */ - public static GroupCacheAccess getGroupCacheInstance( String region ) - throws CacheException - { - CompositeCache, V> cache = getCacheManager().getCache( region ); - return new GroupCacheAccess( cache ); - } - - /** - * Get a GroupCacheAccess which accesses the provided region. - *

- * @param region Region that return GroupCacheAccess will provide access to - * @param icca CacheAttributes for region - * @return A GroupCacheAccess which provides access to a given region. - * @throws CacheException - */ - public static GroupCacheAccess getGroupCacheInstance( String region, ICompositeCacheAttributes icca ) - throws CacheException - { - CompositeCache, V> cache = getCacheManager().getCache( region, icca ); - return new GroupCacheAccess( cache ); - } - - /** - * Get a GroupCacheAccess which accesses the provided region. - *

- * @param region Region that return CacheAccess will provide access to - * @param icca CacheAttributes for region - * @param eattr ElementAttributes for the region - * @return A GroupCacheAccess which provides access to a given region. - * @throws CacheException - */ - public static GroupCacheAccess getGroupCacheInstance( String region, ICompositeCacheAttributes icca, IElementAttributes eattr ) - throws CacheException - { - CompositeCache, V> cache = getCacheManager().getCache( region, icca, eattr ); - return new GroupCacheAccess( cache ); - } -} diff --git a/src/org/apache/commons/jcs/access/AbstractCacheAccess.java b/src/org/apache/commons/jcs/access/AbstractCacheAccess.java deleted file mode 100644 index c727c7c49b7..00000000000 --- a/src/org/apache/commons/jcs/access/AbstractCacheAccess.java +++ /dev/null @@ -1,203 +0,0 @@ -package org.apache.commons.jcs.access; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -import org.apache.commons.jcs.access.behavior.ICacheAccessManagement; -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.stats.behavior.ICacheStats; - -/** - * This class provides the common methods for all types of access to the cache. - *

- * An instance of this class is tied to a specific cache region. Static methods are provided to get - * such instances. - *

- * Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an - * item in the cache, remove an item, and clear a region. - *

- * The JCS class is the preferred way to access these methods. - */ -public abstract class AbstractCacheAccess - implements ICacheAccessManagement -{ - /** - * The cache that a given instance of this class provides access to. - *

- * TODO Should this be the interface? - */ - private final CompositeCache cacheControl; - - /** - * Constructor for the CacheAccess object. - *

- * @param cacheControl The cache which the created instance accesses - */ - protected AbstractCacheAccess( CompositeCache cacheControl ) - { - this.cacheControl = cacheControl; - } - - /** - * Removes all of the elements from a region. - *

- * @throws CacheException - */ - @Override - public void clear() - throws CacheException - { - try - { - this.getCacheControl().removeAll(); - } - catch ( IOException e ) - { - throw new CacheException( e ); - } - } - - /** - * This method is does not reset the attributes for items already in the cache. It could - * potentially do this for items in memory, and maybe on disk (which would be slow) but not - * remote items. Rather than have unpredictable behavior, this method just sets the default - * attributes. Items subsequently put into the cache will use these defaults if they do not - * specify specific attributes. - *

- * @param attr the default attributes. - * @throws CacheException if something goes wrong. - */ - @Override - public void setDefaultElementAttributes( IElementAttributes attr ) - throws CacheException - { - this.getCacheControl().setElementAttributes( attr ); - } - - /** - * Retrieves A COPY OF the default element attributes used by this region. This does not provide - * a reference to the element attributes. - *

- * Each time an element is added to the cache without element attributes, the default element - * attributes are cloned. - *

- * @return the default element attributes used by this region. - * @throws CacheException - */ - @Override - public IElementAttributes getDefaultElementAttributes() - throws CacheException - { - return this.getCacheControl().getElementAttributes(); - } - - /** - * This returns the ICacheStats object with information on this region and its auxiliaries. - *

- * This data can be formatted as needed. - *

- * @return ICacheStats - */ - @Override - public ICacheStats getStatistics() - { - return this.getCacheControl().getStatistics(); - } - - /** - * @return A String version of the stats. - */ - @Override - public String getStats() - { - return this.getCacheControl().getStats(); - } - - /** - * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown - * command! - *

- * To simply remove all elements from the region use clear(). - */ - @Override - public void dispose() - { - this.getCacheControl().dispose(); - } - - /** - * Gets the ICompositeCacheAttributes of the cache region. - *

- * @return ICompositeCacheAttributes, the controllers config info, defined in the top section of - * a region definition. - */ - @Override - public ICompositeCacheAttributes getCacheAttributes() - { - return this.getCacheControl().getCacheAttributes(); - } - - /** - * Sets the ICompositeCacheAttributes of the cache region. - *

- * @param cattr The new ICompositeCacheAttribute value - */ - @Override - public void setCacheAttributes( ICompositeCacheAttributes cattr ) - { - this.getCacheControl().setCacheAttributes( cattr ); - } - - /** - * This instructs the memory cache to remove the numberToFree according to its eviction - * policy. For example, the LRUMemoryCache will remove the numberToFree least recently - * used items. These will be spooled to disk if a disk auxiliary is available. - *

- * @param numberToFree - * @return the number that were removed. if you ask to free 5, but there are only 3, you will - * get 3. - * @throws CacheException - */ - @Override - public int freeMemoryElements( int numberToFree ) - throws CacheException - { - int numFreed = -1; - try - { - numFreed = this.getCacheControl().getMemoryCache().freeElements( numberToFree ); - } - catch ( IOException ioe ) - { - String message = "Failure freeing memory elements."; - throw new CacheException( message, ioe ); - } - return numFreed; - } - - public CompositeCache getCacheControl() { - return cacheControl; - } - -} diff --git a/src/org/apache/commons/jcs/access/CacheAccess.java b/src/org/apache/commons/jcs/access/CacheAccess.java deleted file mode 100644 index 8a7262c2e90..00000000000 --- a/src/org/apache/commons/jcs/access/CacheAccess.java +++ /dev/null @@ -1,308 +0,0 @@ -package org.apache.commons.jcs.access; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.access.behavior.ICacheAccess; -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.access.exception.InvalidArgumentException; -import org.apache.commons.jcs.access.exception.InvalidHandleException; -import org.apache.commons.jcs.access.exception.ObjectExistsException; -import org.apache.commons.jcs.engine.CacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class provides an interface for all types of access to the cache. - *

- * An instance of this class is tied to a specific cache region. Static methods are provided to get - * such instances. - *

- * Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an - * item in the cache, remove an item, and clear a region. - *

- * The JCS class is the preferred way to access these methods. - */ -public class CacheAccess - extends AbstractCacheAccess - implements ICacheAccess -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( CacheAccess.class ); - - /** - * Constructor for the CacheAccess object. - *

- * @param cacheControl The cache which the created instance accesses - */ - public CacheAccess( CompositeCache cacheControl ) - { - super(cacheControl); - } - - /** - * Retrieve an object from the cache region this instance provides access to. - *

- * @param name Key the object is stored as - * @return The object if found or null - */ - @Override - public V get( K name ) - { - ICacheElement element = this.getCacheControl().get( name ); - - return ( element != null ) ? element.getVal() : null; - } - - /** - * Retrieve matching objects from the cache region this instance provides access to. - *

- * @param pattern - a key pattern for the objects stored - * @return A map of key to values. These are stripped from the wrapper. - */ - @Override - public Map getMatching( String pattern ) - { - HashMap unwrappedResults = new HashMap(); - - Map> wrappedResults = this.getCacheControl().getMatching( pattern ); - if ( wrappedResults != null ) - { - for (Map.Entry> entry : wrappedResults.entrySet()) - { - ICacheElement element = entry.getValue(); - if ( element != null ) - { - unwrappedResults.put( entry.getKey(), element.getVal() ); - } - } - } - return unwrappedResults; - } - - /** - * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other - * attributes. - *

- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No - * defensive copy is made. - *

- * This method is most useful if you want to determine things such as the how long the element - * has been in the cache. - *

- * The last access time in the ElementAttributes should be current. - *

- * @param name Key the Serializable is stored as - * @return The ICacheElement<K, V> if the object is found or null - */ - @Override - public ICacheElement getCacheElement( K name ) - { - return this.getCacheControl().get( name ); - } - - /** - * Get multiple elements from the cache based on a set of cache keys. - *

- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other - * attributes. - *

- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No - * defensive copy is made. - *

- * This method is most useful if you want to determine things such as the how long the element - * has been in the cache. - *

- * The last access time in the ElementAttributes should be current. - *

- * @param names set of Serializable cache keys - * @return a map of K key to ICacheElement<K, V> element, or empty map if none of the keys are present - */ - @Override - public Map> getCacheElements( Set names ) - { - return this.getCacheControl().getMultiple( names ); - } - - /** - * Get multiple elements from the cache based on a set of cache keys. - *

- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other - * attributes. - *

- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No - * defensive copy is made. - *

- * This method is most useful if you want to determine things such as the how long the element - * has been in the cache. - *

- * The last access time in the ElementAttributes should be current. - *

- * @param pattern key search pattern - * @return a map of K key to ICacheElement<K, V> element, or empty map if no keys match the pattern - */ - @Override - public Map> getMatchingCacheElements( String pattern ) - { - return this.getCacheControl().getMatching( pattern ); - } - - /** - * Place a new object in the cache, associated with key name. If there is currently an object - * associated with name in the region an ObjectExistsException is thrown. Names are scoped to a - * region so they must be unique within the region they are placed. - *

- * @param key Key object will be stored with - * @param value Object to store - * @throws CacheException and ObjectExistsException is thrown if the item is already in the - * cache. - */ - @Override - public void putSafe( K key, V value ) - { - if ( this.getCacheControl().get( key ) != null ) - { - throw new ObjectExistsException( "putSafe failed. Object exists in the cache for key [" + key - + "]. Remove first or use a non-safe put to override the value." ); - } - put( key, value ); - } - - /** - * Place a new object in the cache, associated with key name. If there is currently an object - * associated with name in the region it is replaced. Names are scoped to a region so they must - * be unique within the region they are placed. - * @param name Key object will be stored with - * @param obj Object to store - */ - @Override - public void put( K name, V obj ) - { - // Call put with a copy of the contained caches default attributes. - // the attributes are copied by the cacheControl - put( name, obj, this.getCacheControl().getElementAttributes() ); - } - - /** - * Constructs a cache element with these attributes, and puts it into the cache. - *

- * If the key or the value is null, and InvalidArgumentException is thrown. - *

- * @see org.apache.commons.jcs.access.behavior.ICacheAccess#put(Object, Object, IElementAttributes) - */ - @Override - public void put( K key, V val, IElementAttributes attr ) - { - if ( key == null ) - { - throw new InvalidArgumentException( "Key must not be null" ); - } - - if ( val == null ) - { - throw new InvalidArgumentException( "Value must not be null" ); - } - - // Create the element and update. This may throw an IOException which - // should be wrapped by cache access. - try - { - CacheElement ce = new CacheElement( this.getCacheControl().getCacheName(), key, - val ); - - ce.setElementAttributes( attr ); - - this.getCacheControl().update( ce ); - } - catch ( IOException e ) - { - throw new CacheException( e ); - } - } - - /** - * Removes a single item by name. - *

- * @param name the name of the item to remove. - */ - @Override - public void remove( K name ) - { - this.getCacheControl().remove( name ); - } - - /** - * Reset attributes for a particular element in the cache. NOTE: this method is currently not - * implemented. - *

- * @param name Key of object to reset attributes for - * @param attr New attributes for the object - * @throws InvalidHandleException if the item does not exist. - */ - @Override - public void resetElementAttributes( K name, IElementAttributes attr ) - { - ICacheElement element = this.getCacheControl().get( name ); - - if ( element == null ) - { - throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" ); - } - - // Although it will work currently, don't assume pass by reference here, - // i.e. don't do this: - // element.setElementAttributes( attr ); - // Another reason to call put is to force the changes to be distributed. - - put( element.getKey(), element.getVal(), attr ); - } - - /** - * GetElementAttributes will return an attribute object describing the current attributes - * associated with the object name. The name object must override the Object.equals and - * Object.hashCode methods. - *

- * @param name Key of object to get attributes for - * @return Attributes for the object, null if object not in cache - */ - @Override - public IElementAttributes getElementAttributes( K name ) - { - IElementAttributes attr = null; - - try - { - attr = this.getCacheControl().getElementAttributes( name ); - } - catch ( IOException ioe ) - { - log.error( "Failure getting element attributes", ioe ); - } - - return attr; - } -} diff --git a/src/org/apache/commons/jcs/access/GroupCacheAccess.java b/src/org/apache/commons/jcs/access/GroupCacheAccess.java deleted file mode 100644 index 958abba1048..00000000000 --- a/src/org/apache/commons/jcs/access/GroupCacheAccess.java +++ /dev/null @@ -1,211 +0,0 @@ -package org.apache.commons.jcs.access; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.behavior.IGroupCacheAccess; -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.access.exception.InvalidArgumentException; -import org.apache.commons.jcs.engine.CacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.group.GroupAttrName; -import org.apache.commons.jcs.engine.control.group.GroupId; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -/** - * Access for groups. - */ -public class GroupCacheAccess - extends AbstractCacheAccess, V> - implements IGroupCacheAccess -{ - /** - * Constructor for the GroupCacheAccess object - *

- * @param cacheControl - */ - public GroupCacheAccess( CompositeCache, V> cacheControl ) - { - super(cacheControl); - } - - /** - * Gets an item out of the cache that is in a specified group. - *

- * @param name - * The key name. - * @param group - * The group name. - * @return The cached value, null if not found. - */ - @Override - public V getFromGroup( K name, String group ) - { - ICacheElement, V> element = this.getCacheControl().get( getGroupAttrName( group, name ) ); - return ( element != null ) ? element.getVal() : null; - } - - /** - * Internal method used for group functionality. - *

- * @param group - * @param name - * @return GroupAttrName - */ - private GroupAttrName getGroupAttrName( String group, K name ) - { - GroupId gid = new GroupId( this.getCacheControl().getCacheName(), group ); - return new GroupAttrName( gid, name ); - } - - /** - * Allows the user to put an object into a group within a particular cache - * region. This method sets the object's attributes to the default for the - * region. - *

- * @param name - * The key name. - * @param groupName - * The group name. - * @param value - * The object to cache - * @throws CacheException - */ - @Override - public void putInGroup( K name, String groupName, V value ) - throws CacheException - { - putInGroup( name, groupName, value, null ); - } - - /** - * Allows the user to put an object into a group within a particular cache - * region. This method allows the object's attributes to be individually - * specified. - *

- * @param name - * The key name. - * @param groupName - * The group name. - * @param value - * The object to cache - * @param attr - * The objects attributes. - * @throws CacheException - */ - @Override - public void putInGroup( K name, String groupName, V value, IElementAttributes attr ) - throws CacheException - { - if ( name == null ) - { - throw new InvalidArgumentException( "Key must not be null" ); - } - - if ( value == null ) - { - throw new InvalidArgumentException( "Value must not be null" ); - } - - // Create the element and update. This may throw an IOException which - // should be wrapped by cache access. - try - { - GroupAttrName key = getGroupAttrName( groupName, name ); - CacheElement, V> ce = - new CacheElement, V>( this.getCacheControl().getCacheName(), key, value ); - - IElementAttributes attributes = (attr == null) ? this.getCacheControl().getElementAttributes() : attr; - ce.setElementAttributes( attributes ); - - this.getCacheControl().update( ce ); - } - catch ( IOException e ) - { - throw new CacheException( e ); - } - - } - - /** - * @param name - * @param group - */ - @Override - public void removeFromGroup( K name, String group ) - { - GroupAttrName key = getGroupAttrName( group, name ); - this.getCacheControl().remove( key ); - } - - /** - * Gets the set of keys of objects currently in the group. - *

- * @param group - * @return A Set of keys. - */ - @Override - public Set getGroupKeys( String group ) - { - Set groupKeys = new HashSet(); - GroupId groupId = new GroupId( this.getCacheControl().getCacheName(), group ); - - for (GroupAttrName gan : this.getCacheControl().getKeySet()) - { - if (gan.groupId.equals( groupId )) - { - groupKeys.add( gan.attrName ); - } - } - - return groupKeys; - } - - /** - * Gets the set of group names in the cache - *

- * @return A Set of group names. - */ - public Set getGroupNames() - { - HashSet names = new HashSet(); - for (GroupAttrName gan : this.getCacheControl().getKeySet()) - { - names.add(gan.groupId.groupName); - } - return names; - } - - /** - * Invalidates a group: remove all the group members - *

- * @param group - * The name of the group to invalidate - */ - @Override - public void invalidateGroup( String group ) - { - this.getCacheControl().remove(getGroupAttrName(group, null)); - } -} diff --git a/src/org/apache/commons/jcs/access/PartitionedCacheAccess.java b/src/org/apache/commons/jcs/access/PartitionedCacheAccess.java deleted file mode 100644 index e1000022f64..00000000000 --- a/src/org/apache/commons/jcs/access/PartitionedCacheAccess.java +++ /dev/null @@ -1,845 +0,0 @@ -package org.apache.commons.jcs.access; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.JCS; -import org.apache.commons.jcs.access.behavior.ICacheAccess; -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.access.exception.ConfigurationException; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.stats.behavior.ICacheStats; -import org.apache.commons.jcs.utils.props.AbstractPropertyContainer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * TODO: Add new methods that will allow you to provide a partition indicator for all major calls. Add an interface as well. - *

- * This handles dividing puts and gets. - *

- * There are two required properties. - *

- *

    - *
  1. .numberOfPartitions
  2. - *
  3. .partitionRegionNamePrefix
  4. - *
- * System properties will override values in the properties file. - *

- * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix + "_" - * + partitionNumber. The number is 0 indexed based. - *

- * @author Aaron Smuts - */ -public class PartitionedCacheAccess - extends AbstractPropertyContainer - implements ICacheAccess -{ - /** the logger. */ - private static final Log log = LogFactory.getLog( PartitionedCacheAccess.class ); - - /** The number of partitions. */ - private int numberOfPartitions = 1; - - /** - * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix + - * "_" + partitionNumber - */ - private String partitionRegionNamePrefix; - - /** An array of partitions built during initialization. */ - private ICacheAccess[] partitions; - - /** Is the class initialized. */ - private boolean initialized = false; - - /** Sets default properties heading and group. */ - public PartitionedCacheAccess() - { - setPropertiesHeading( "PartitionedCacheAccess" ); - setPropertiesGroup( "cache" ); - } - - /** - * Puts the value into the appropriate cache partition. - *

- * @param key key - * @param object object - * @throws CacheException on configuration problem - */ - @Override - public void put( K key, V object ) - throws CacheException - { - if ( key == null || object == null ) - { - log.warn( "Bad input key [" + key + "]. Cannot put null into the cache." ); - return; - } - - if (!ensureInit()) - { - return; - } - - int partition = getPartitionNumberForKey( key ); - try - { - partitions[partition].put( key, object ); - } - catch ( CacheException e ) - { - log.error( "Problem putting value for key [" + key + "] in cache [" + partitions[partition] + "]" ); - throw e; - } - } - - /** - * Puts in cache if an item does not exist with the name in that region. - *

- * @param key - * @param object - * @throws CacheException - */ - @Override - public void putSafe( K key, V object ) - throws CacheException - { - if ( key == null || object == null ) - { - log.warn( "Bad input key [" + key + "]. Cannot putSafe null into the cache." ); - } - - if (!ensureInit()) - { - return; - } - - int partition = getPartitionNumberForKey( key ); - partitions[partition].putSafe( key, object ); - } - - /** - * Puts the value into the appropriate cache partition. - *

- * @param key key - * @param object object - * @param attr - * @throws CacheException on configuration problem - */ - @Override - public void put( K key, V object, IElementAttributes attr ) - throws CacheException - { - if ( key == null || object == null ) - { - log.warn( "Bad input key [" + key + "]. Cannot put null into the cache." ); - return; - } - - if (!ensureInit()) - { - return; - } - - int partition = getPartitionNumberForKey( key ); - - try - { - partitions[partition].put( key, object, attr ); - } - catch ( CacheException e ) - { - log.error( "Problem putting value for key [" + key + "] in cache [" + partitions[partition] + "]" ); - throw e; - } - } - - /** - * Gets the object for the key from the desired partition. - *

- * @param key key - * @return result, null if not found. - */ - @Override - public V get( K key ) - { - if ( key == null ) - { - log.warn( "Input key is null." ); - return null; - } - - if (!ensureInit()) - { - return null; - } - - int partition = getPartitionNumberForKey( key ); - - return partitions[partition].get( key ); - } - - /** - * Gets the ICacheElement<K, V> (the wrapped object) for the key from the desired partition. - *

- * @param key key - * @return result, null if not found. - */ - @Override - public ICacheElement getCacheElement( K key ) - { - if ( key == null ) - { - log.warn( "Input key is null." ); - return null; - } - - if (!ensureInit()) - { - return null; - } - - int partition = getPartitionNumberForKey( key ); - - return partitions[partition].getCacheElement( key ); - } - - /** - * This is a getMultiple. We try to group the keys so that we make as few calls as needed. - *

- * @param names - * @return Map of keys to ICacheElement - */ - @Override - public Map> getCacheElements( Set names ) - { - if ( names == null ) - { - log.warn( "Bad input names cannot be null." ); - return Collections.emptyMap(); - } - - if (!ensureInit()) - { - return Collections.emptyMap(); - } - - @SuppressWarnings("unchecked") // No generic arrays in java - Set[] dividedNames = new Set[this.getNumberOfPartitions()]; - - for (K key : names) - { - int partition = getPartitionNumberForKey( key ); - if ( dividedNames[partition] == null ) - { - dividedNames[partition] = new HashSet(); - } - dividedNames[partition].add( key ); - } - - Map> result = new HashMap>(); - for ( int i = 0; i < partitions.length; i++ ) - { - if ( dividedNames[i] != null && !dividedNames[i].isEmpty() ) - { - result.putAll( partitions[i].getCacheElements( dividedNames[i] ) ); - } - } - return result; - } - - /** - * This is tricky. Do we need to get from all the partitions? - *

- * If this interface took an object, we could use the hashcode to determine the partition. Then - * we could use the toString for the pattern. - *

- * @param pattern - * @return HashMap key to value - */ - @Override - public Map getMatching( String pattern ) - { - if ( pattern == null ) - { - log.warn( "Input pattern is null." ); - return null; - } - - if (!ensureInit()) - { - return null; - } - - Map result = new HashMap(); - for (ICacheAccess partition : partitions) - { - result.putAll( partition.getMatching( pattern ) ); - } - - return result; - } - - /** - * This is tricky. Do we need to get from all the partitions? - *

- * @param pattern - * @return HashMap key to ICacheElement - */ - @Override - public Map> getMatchingCacheElements( String pattern ) - { - if ( pattern == null ) - { - log.warn( "Input pattern is null." ); - return null; - } - - if (!ensureInit()) - { - return null; - } - - Map> result = new HashMap>(); - for (ICacheAccess partition : partitions) - { - result.putAll( partition.getMatchingCacheElements( pattern ) ); - } - return result; - } - - /** - * Removes the item from the appropriate partition. - *

- * @param key - * @throws CacheException - */ - @Override - public void remove( K key ) - throws CacheException - { - if ( key == null ) - { - log.warn( "Input key is null. Cannot remove null from the cache." ); - return; - } - - if (!ensureInit()) - { - return; - } - - int partition = getPartitionNumberForKey( key ); - try - { - partitions[partition].remove( key ); - } - catch ( CacheException e ) - { - log.error( "Problem removing value for key [" + key + "] in cache [" + partitions[partition] + "]" ); - throw e; - } - } - - /** - * Calls free on each partition. - *

- * @param numberToFree - * @return number removed - * @throws CacheException - */ - @Override - public int freeMemoryElements( int numberToFree ) - throws CacheException - { - if (!ensureInit()) - { - return 0; - } - - int count = 0; - for (ICacheAccess partition : partitions) - { - count += partition.freeMemoryElements( numberToFree ); - } - return count; - } - - /** - * @return ICompositeCacheAttributes from the first partition. - */ - @Override - public ICompositeCacheAttributes getCacheAttributes() - { - if (!ensureInit()) - { - return null; - } - - if ( partitions.length == 0 ) - { - return null; - } - - return partitions[0].getCacheAttributes(); - } - - /** - * @return IElementAttributes from the first partition. - * @throws CacheException - */ - @Override - public IElementAttributes getDefaultElementAttributes() - throws CacheException - { - if (!ensureInit()) - { - return null; - } - - if ( partitions.length == 0 ) - { - return null; - } - - return partitions[0].getDefaultElementAttributes(); - } - - /** - * This is no more efficient than simply getting the cache element. - *

- * @param key - * @return IElementAttributes - * @throws CacheException - */ - @Override - public IElementAttributes getElementAttributes( K key ) - throws CacheException - { - if ( key == null ) - { - log.warn( "Input key is null. Cannot getElementAttributes for null from the cache." ); - return null; - } - - if (!ensureInit()) - { - return null; - } - - int partition = getPartitionNumberForKey( key ); - - return partitions[partition].getElementAttributes( key ); - } - - /** - * Resets the attributes for this item. This has the same effect as an update, in most cases. - * None of the auxiliaries are optimized to do this more efficiently than a simply update. - *

- * @param key - * @param attributes - * @throws CacheException - */ - @Override - public void resetElementAttributes( K key, IElementAttributes attributes ) - throws CacheException - { - if ( key == null ) - { - log.warn( "Input key is null. Cannot resetElementAttributes for null." ); - return; - } - - if (!ensureInit()) - { - return; - } - - int partition = getPartitionNumberForKey( key ); - - partitions[partition].resetElementAttributes( key, attributes ); - } - - /** - * Sets the attributes on all the partitions. - *

- * @param cattr - */ - @Override - public void setCacheAttributes( ICompositeCacheAttributes cattr ) - { - if (!ensureInit()) - { - return; - } - - for (ICacheAccess partition : partitions) - { - partition.setCacheAttributes( cattr ); - } - } - - /** - * Removes all of the elements from a region. - *

- * @throws CacheException - */ - @Override - public void clear() - throws CacheException - { - if (!ensureInit()) - { - return; - } - - for (ICacheAccess partition : partitions) - { - partition.clear(); - } - } - - /** - * This method is does not reset the attributes for items already in the cache. It could - * potentially do this for items in memory, and maybe on disk (which would be slow) but not - * remote items. Rather than have unpredictable behavior, this method just sets the default - * attributes. Items subsequently put into the cache will use these defaults if they do not - * specify specific attributes. - *

- * @param attr the default attributes. - * @throws CacheException if something goes wrong. - */ - @Override - public void setDefaultElementAttributes( IElementAttributes attr ) - throws CacheException - { - if (!ensureInit()) - { - return; - } - - for (ICacheAccess partition : partitions) - { - partition.setDefaultElementAttributes(attr); - } - } - - /** - * This returns the ICacheStats object with information on this region and its auxiliaries. - *

- * This data can be formatted as needed. - *

- * @return ICacheStats - */ - @Override - public ICacheStats getStatistics() - { - if (!ensureInit()) - { - return null; - } - - if ( partitions.length == 0 ) - { - return null; - } - - return partitions[0].getStatistics(); - } - - /** - * @return A String version of the stats. - */ - @Override - public String getStats() - { - if (!ensureInit()) - { - return ""; - } - - StringBuilder stats = new StringBuilder(); - for (ICacheAccess partition : partitions) - { - stats.append(partition.getStats()); - stats.append("\n"); - } - - return stats.toString(); - } - - /** - * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown - * command! - *

- * To simply remove all elements from the region use clear(). - */ - @Override - public synchronized void dispose() - { - if (!ensureInit()) - { - return; - } - - for (ICacheAccess partition : partitions) - { - partition.dispose(); - } - - initialized = false; - } - - /** - * This expects a numeric key. If the key cannot be converted into a number, we will return 0. - * TODO we could md5 it or get the hashcode. - *

- * We determine the partition by taking the mod of the number of partitions. - *

- * @param key key - * @return the partition number. - */ - protected int getPartitionNumberForKey( K key ) - { - if ( key == null ) - { - return 0; - } - - long keyNum = getNumericValueForKey( key ); - - int partition = (int) ( keyNum % getNumberOfPartitions() ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Using partition [" + partition + "] for key [" + key + "]" ); - } - - return partition; - } - - /** - * This can be overridden for special purposes. - *

- * @param key key - * @return long - */ - public long getNumericValueForKey( K key ) - { - String keyString = key.toString(); - long keyNum = -1; - try - { - keyNum = Long.parseLong( keyString ); - } - catch ( NumberFormatException e ) - { - // THIS IS UGLY, but I can't think of a better failsafe right now. - keyNum = key.hashCode(); - log.warn( "Couldn't convert [" + key + "] into a number. Will use hashcode [" + keyNum + "]" ); - } - return keyNum; - } - - /** - * Initialize if we haven't already. - *

- * @throws ConfigurationException on configuration problem - */ - protected synchronized boolean ensureInit() - { - if ( !initialized ) - { - try - { - initialize(); - } - catch ( ConfigurationException e ) - { - log.error( "Couldn't configure partioned access.", e ); - return false; - } - } - - return true; - } - - /** - * Use the partition prefix and the number of partitions to get JCS regions. - *

- * @throws ConfigurationException on configuration problem - */ - protected synchronized void initialize() - throws ConfigurationException - { - ensureProperties(); - - @SuppressWarnings("unchecked") // No generic arrays in java - ICacheAccess[] tempPartitions = new ICacheAccess[this.getNumberOfPartitions()]; - for ( int i = 0; i < this.getNumberOfPartitions(); i++ ) - { - String regionName = this.getPartitionRegionNamePrefix() + "_" + i; - try - { - tempPartitions[i] = JCS.getInstance( regionName ); - } - catch ( CacheException e ) - { - log.error( "Problem getting cache for region [" + regionName + "]" ); - } - } - - partitions = tempPartitions; - initialized = true; - } - - /** - * Loads in the needed configuration settings. System properties are checked first. A system - * property will override local property value. - *

- * Loads the following JCS Cache specific properties: - *

    - *
  • heading.numberOfPartitions
  • - *
  • heading.partitionRegionNamePrefix
  • - *
- * @throws ConfigurationException on configuration problem - */ - @Override - protected void handleProperties() - throws ConfigurationException - { - // Number of Partitions. - String numberOfPartitionsPropertyName = this.getPropertiesHeading() + ".numberOfPartitions"; - String numberOfPartitionsPropertyValue = getPropertyForName( numberOfPartitionsPropertyName, true ); - try - { - this.setNumberOfPartitions( Integer.parseInt( numberOfPartitionsPropertyValue ) ); - } - catch ( NumberFormatException e ) - { - String message = "Could not convert [" + numberOfPartitionsPropertyValue + "] into a number for [" - + numberOfPartitionsPropertyName + "]"; - log.error( message ); - throw new ConfigurationException( message ); - } - - // Partition Name Prefix. - String prefixPropertyName = this.getPropertiesHeading() + ".partitionRegionNamePrefix"; - String prefix = getPropertyForName( prefixPropertyName, true ); - this.setPartitionRegionNamePrefix( prefix ); - } - - /** - * Checks the system properties before the properties. - *

- * @param propertyName name - * @param required is it required? - * @return the property value if one is found - * @throws ConfigurationException thrown if it is required and not found. - */ - protected String getPropertyForName( String propertyName, boolean required ) - throws ConfigurationException - { - String propertyValue = null; - propertyValue = System.getProperty( propertyName ); - if ( propertyValue != null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Found system property override: Name [" + propertyName + "] Value [" + propertyValue + "]" ); - } - } - else - { - propertyValue = this.getProperties().getProperty( propertyName ); - if ( required && propertyValue == null ) - { - String message = "Could not find required property [" + propertyName + "] in propertiesGroup [" - + this.getPropertiesGroup() + "]"; - log.error( message ); - throw new ConfigurationException( message ); - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "Name [" + propertyName + "] Value [" + propertyValue + "]" ); - } - } - } - return propertyValue; - } - - /** - * @param numberOfPartitions The numberOfPartitions to set. - */ - protected void setNumberOfPartitions( int numberOfPartitions ) - { - this.numberOfPartitions = numberOfPartitions; - } - - /** - * @return Returns the numberOfPartitions. - */ - protected int getNumberOfPartitions() - { - return numberOfPartitions; - } - - /** - * @param partitionRegionNamePrefix The partitionRegionNamePrefix to set. - */ - protected void setPartitionRegionNamePrefix( String partitionRegionNamePrefix ) - { - this.partitionRegionNamePrefix = partitionRegionNamePrefix; - } - - /** - * @return Returns the partitionRegionNamePrefix. - */ - protected String getPartitionRegionNamePrefix() - { - return partitionRegionNamePrefix; - } - - /** - * @param partitions The partitions to set. - */ - protected void setPartitions( ICacheAccess[] partitions ) - { - this.partitions = partitions; - } - - /** - * @return Returns the partitions. - */ - protected ICacheAccess[] getPartitions() - { - return partitions; - } -} diff --git a/src/org/apache/commons/jcs/access/behavior/ICacheAccess.java b/src/org/apache/commons/jcs/access/behavior/ICacheAccess.java deleted file mode 100644 index 7c0db9602b2..00000000000 --- a/src/org/apache/commons/jcs/access/behavior/ICacheAccess.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.apache.commons.jcs.access.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; - -import java.util.Map; -import java.util.Set; - -/** - * ICacheAccess defines the behavior for client access. - */ -public interface ICacheAccess - extends ICacheAccessManagement -{ - /** - * Basic get method. - *

- * @param name - * @return Object or null if not found. - */ - V get( K name ); - - /** - * Retrieve matching objects from the cache region this instance provides access to. - *

- * @param pattern - a key pattern for the objects stored - * @return A map of key to values. These are stripped from the wrapper. - */ - Map getMatching( String pattern ); - - /** - * Puts in cache if an item does not exist with the name in that region. - *

- * @param name - * @param obj - * @throws CacheException - */ - void putSafe( K name, V obj ) - throws CacheException; - - /** - * Puts and/or overrides an element with the name in that region. - *

- * @param name - * @param obj - * @throws CacheException - */ - void put( K name, V obj ) - throws CacheException; - - /** - * Description of the Method - *

- * @param name - * @param obj - * @param attr - * @throws CacheException - */ - void put( K name, V obj, IElementAttributes attr ) - throws CacheException; - - /** - * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other - * attributes. - *

- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No - * defensive copy is made. - *

- * This method is most useful if you want to determine things such as the how long the element - * has been in the cache. - *

- * The last access time in the ElementAttributes should be current. - *

- * @param name Key the object is stored as - * @return The ICacheElement<K, V> if the object is found or null - */ - ICacheElement getCacheElement( K name ); - - /** - * Get multiple elements from the cache based on a set of cache keys. - *

- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other - * attributes. - *

- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No - * defensive copy is made. - *

- * This method is most useful if you want to determine things such as the how long the element - * has been in the cache. - *

- * The last access time in the ElementAttributes should be current. - *

- * @param names set of Object cache keys - * @return a map of Object key to ICacheElement<K, V> element, or empty map if none of the keys are - * present - */ - Map> getCacheElements( Set names ); - - /** - * Get multiple elements from the cache based on a set of cache keys. - *

- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other - * attributes. - *

- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No - * defensive copy is made. - *

- * This method is most useful if you want to determine things such as the how long the element - * has been in the cache. - *

- * The last access time in the ElementAttributes should be current. - *

- * @param pattern key search pattern - * @return a map of Object key to ICacheElement<K, V> element, or empty map if no keys match the - * pattern - */ - Map> getMatchingCacheElements( String pattern ); - - /** - * Remove an object for this key if one exists, else do nothing. - *

- * @param name - * @throws CacheException - */ - void remove( K name ) - throws CacheException; - - /** - * Reset the attributes on the object matching this key name. - *

- * @param name - * @param attributes - * @throws CacheException - */ - void resetElementAttributes( K name, IElementAttributes attributes ) - throws CacheException; - - /** - * Gets the elementAttributes attribute of the ICacheAccess object - *

- * @param name - * @return The elementAttributes value - * @throws CacheException - */ - IElementAttributes getElementAttributes( K name ) - throws CacheException; -} diff --git a/src/org/apache/commons/jcs/access/behavior/ICacheAccessManagement.java b/src/org/apache/commons/jcs/access/behavior/ICacheAccessManagement.java deleted file mode 100644 index 21c01f4b188..00000000000 --- a/src/org/apache/commons/jcs/access/behavior/ICacheAccessManagement.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.apache.commons.jcs.access.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.stats.behavior.ICacheStats; - -/** - * ICacheAccessManagement defines the methods for cache management, cleanup and shutdown. - */ -public interface ICacheAccessManagement -{ - /** - * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown - * command! - *

- * To simply remove all elements from the region use clear(). - */ - void dispose(); - - /** - * Removes all of the elements from a region. - *

- * @throws CacheException - */ - void clear() throws CacheException; - - /** - * GetElementAttributes will return an attribute object describing the current attributes - * associated with the object name. If no name parameter is available, the attributes for the - * region will be returned. The name object must override the Object.equals and Object.hashCode - * methods. - *

- * @return The elementAttributes value - * @throws CacheException - */ - IElementAttributes getDefaultElementAttributes() - throws CacheException; - - /** - * This method is does not reset the attributes for items already in the cache. It could - * potentially do this for items in memory, and maybe on disk (which would be slow) but not - * remote items. Rather than have unpredictable behavior, this method just sets the default - * attributes. Items subsequently put into the cache will use these defaults if they do not - * specify specific attributes. - *

- * @param attr the default attributes. - * @throws CacheException if something goes wrong. - */ - void setDefaultElementAttributes( IElementAttributes attr ) throws CacheException; - - /** - * Gets the ICompositeCacheAttributes of the cache region - *

- * @return ICompositeCacheAttributes - */ - ICompositeCacheAttributes getCacheAttributes(); - - /** - * Sets the ICompositeCacheAttributes of the cache region - *

- * @param cattr The new ICompositeCacheAttribute value - */ - void setCacheAttributes( ICompositeCacheAttributes cattr ); - - /** - * This instructs the memory cache to remove the numberToFree according to its eviction - * policy. For example, the LRUMemoryCache will remove the numberToFree least recently - * used items. These will be spooled to disk if a disk auxiliary is available. - *

- * @param numberToFree - * @return the number that were removed. if you ask to free 5, but there are only 3, you will - * get 3. - * @throws CacheException - */ - int freeMemoryElements( int numberToFree ) - throws CacheException; - - /** - * This returns the ICacheStats object with information on this region and its auxiliaries. - *

- * This data can be formatted as needed. - *

- * @return ICacheStats - */ - ICacheStats getStatistics(); - - /** - * @return A String version of the stats. - */ - String getStats(); -} diff --git a/src/org/apache/commons/jcs/access/behavior/IGroupCacheAccess.java b/src/org/apache/commons/jcs/access/behavior/IGroupCacheAccess.java deleted file mode 100644 index 4527d247d72..00000000000 --- a/src/org/apache/commons/jcs/access/behavior/IGroupCacheAccess.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.apache.commons.jcs.access.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; - -import java.util.Set; - -/** - * IGroupCacheAccess defines group specific behavior for the client access - * classes. - */ -public interface IGroupCacheAccess - extends ICacheAccessManagement -{ - /** - * Gets the g attribute of the IGroupCacheAccess object - *

- * @param name - * @param group - * the name of the group to associate this with. - * @return The object that is keyed by the name in the group - */ - V getFromGroup( K name, String group ); - - /** - * Puts an item in the cache associated with this group. - *

- * @param key - * @param group - * @param obj - * @throws CacheException - */ - void putInGroup( K key, String group, V obj ) - throws CacheException; - - /** - * Put in the cache associated with this group using these attributes. - *

- * @param key - * @param group - * @param obj - * @param attr - * @throws CacheException - */ - void putInGroup( K key, String group, V obj, IElementAttributes attr ) - throws CacheException; - - /** - * Remove the item from this group in this region by this name. - *

- * @param name - * @param group - */ - void removeFromGroup( K name, String group ); - - /** - * Gets the set of keys of objects currently in the group - *

- * @param group - * @return the set of group keys. - */ - Set getGroupKeys( String group ); - - /** - * Invalidates a group - *

- * @param group - */ - void invalidateGroup( String group ); -} diff --git a/src/org/apache/commons/jcs/access/exception/CacheException.java b/src/org/apache/commons/jcs/access/exception/CacheException.java deleted file mode 100644 index 78479b10972..00000000000 --- a/src/org/apache/commons/jcs/access/exception/CacheException.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.apache.commons.jcs.access.exception; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This is the most general exception the cache throws. - */ -public class CacheException - extends RuntimeException -{ - /** Don't change. */ - private static final long serialVersionUID = 8725795372935590265L; - - /** - * Default - */ - public CacheException() - { - super(); - } - - /** - * Constructor for the CacheException object - * @param nested a nested exception - */ - public CacheException( Throwable nested ) - { - super(nested); - } - - /** - * Constructor for the CacheException object - * @param message the exception message - */ - public CacheException( String message ) - { - super(message); - } - - /** - * Constructor for the CacheException object - * @param message the exception message - * @param nested a nested exception - */ - public CacheException(String message, Throwable nested) - { - super(message, nested); - } -} diff --git a/src/org/apache/commons/jcs/access/exception/ConfigurationException.java b/src/org/apache/commons/jcs/access/exception/ConfigurationException.java deleted file mode 100644 index 03f4890bdd3..00000000000 --- a/src/org/apache/commons/jcs/access/exception/ConfigurationException.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.apache.commons.jcs.access.exception; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** Thrown if there is some severe configuration problem that makes the cache nonfunctional. */ -public class ConfigurationException - extends CacheException -{ - /** Don't change. */ - private static final long serialVersionUID = 6881044536186097055L; - - /** Constructor for the ConfigurationException object */ - public ConfigurationException() - { - super(); - } - - /** - * Constructor for the ConfigurationException object. - *

- * @param message - */ - public ConfigurationException( String message ) - { - super( message ); - } -} diff --git a/src/org/apache/commons/jcs/access/exception/InvalidArgumentException.java b/src/org/apache/commons/jcs/access/exception/InvalidArgumentException.java deleted file mode 100644 index cfb44354f48..00000000000 --- a/src/org/apache/commons/jcs/access/exception/InvalidArgumentException.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.apache.commons.jcs.access.exception; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * InvalidArgumentException is thrown if an argument is passed to the cache that is invalid. For - * instance, null values passed to put result in this exception. - */ -public class InvalidArgumentException - extends CacheException -{ - /** Don't change. */ - private static final long serialVersionUID = -6058373692208755562L; - - /** Constructor for the InvalidArgumentException object */ - public InvalidArgumentException() - { - super(); - } - - /** - * Constructor for the InvalidArgumentException object. - *

- * @param message - */ - public InvalidArgumentException( String message ) - { - super( message ); - } -} diff --git a/src/org/apache/commons/jcs/access/exception/InvalidGroupException.java b/src/org/apache/commons/jcs/access/exception/InvalidGroupException.java deleted file mode 100644 index 870a4021972..00000000000 --- a/src/org/apache/commons/jcs/access/exception/InvalidGroupException.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.apache.commons.jcs.access.exception; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * InvalidGroupException - */ -public class InvalidGroupException - extends CacheException -{ - /** Don't change. */ - private static final long serialVersionUID = -5219807114008843480L; - - /** Constructor for the InvalidGroupException object */ - public InvalidGroupException() - { - super(); - } - - /** - * Constructor for the InvalidGroupException object - *

- * @param message - */ - public InvalidGroupException( String message ) - { - super( message ); - } - -} diff --git a/src/org/apache/commons/jcs/access/exception/InvalidHandleException.java b/src/org/apache/commons/jcs/access/exception/InvalidHandleException.java deleted file mode 100644 index 6b0e6d3ec18..00000000000 --- a/src/org/apache/commons/jcs/access/exception/InvalidHandleException.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.apache.commons.jcs.access.exception; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * InvalidHandleException is not used. - */ -public class InvalidHandleException - extends CacheException -{ - /** Don't change. */ - private static final long serialVersionUID = -5947822454839845924L; - - /** Constructor for the InvalidHandleException object */ - public InvalidHandleException() - { - // nothing - super(); - } - - /** - * Constructor for the InvalidHandleException object. - *

- * @param message - */ - public InvalidHandleException( String message ) - { - super( message ); - } - -} diff --git a/src/org/apache/commons/jcs/access/exception/ObjectExistsException.java b/src/org/apache/commons/jcs/access/exception/ObjectExistsException.java deleted file mode 100644 index edef1a479ce..00000000000 --- a/src/org/apache/commons/jcs/access/exception/ObjectExistsException.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.apache.commons.jcs.access.exception; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * The putSafe method on the JCS convenience class throws this exception if the object is already - * present in the cache. - *

- * I'm removing this exception from normal use. - *

- * The overhead of throwing exceptions and the cumbersomeness of coding around exceptions warrants - * removal. Exceptions like this don't make sense to throw in the course of normal operations to - * signify a normal and expected condition. Returning null if an object isn't found is sufficient. - */ -public class ObjectExistsException - extends CacheException -{ - /** Don't change. */ - private static final long serialVersionUID = -3779745827993383872L; - - /** Constructor for the ObjectExistsException object */ - public ObjectExistsException() - { - super(); - } - - /** - * Constructor for the ObjectExistsException object - * @param message - */ - public ObjectExistsException( String message ) - { - super( message ); - } - -} diff --git a/src/org/apache/commons/jcs/access/exception/ObjectNotFoundException.java b/src/org/apache/commons/jcs/access/exception/ObjectNotFoundException.java deleted file mode 100644 index 8dca2de8018..00000000000 --- a/src/org/apache/commons/jcs/access/exception/ObjectNotFoundException.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.apache.commons.jcs.access.exception; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * ObjectNotFoundException - *

- * TODO see if we can remove this. - *

- * This is thrown from the composite cache if you as for the element attributes and the element does - * not exist. - */ -public class ObjectNotFoundException - extends CacheException -{ - /** Don't change. */ - private static final long serialVersionUID = 5684353421076546842L; - - /** Constructor for the ObjectNotFoundException object */ - public ObjectNotFoundException() - { - super(); - } - - /** - * Constructor for the ObjectNotFoundException object - * @param message - */ - public ObjectNotFoundException( String message ) - { - super( message ); - } - -} diff --git a/src/org/apache/commons/jcs/access/package.html b/src/org/apache/commons/jcs/access/package.html deleted file mode 100644 index 477e5cca986..00000000000 --- a/src/org/apache/commons/jcs/access/package.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - Contains classes for accessing the cache. The CacheAccess interface, which - all classes in this package implement, provides all the methods a client - should need to use a Cache. - - diff --git a/src/org/apache/commons/jcs/admin/CacheElementInfo.java b/src/org/apache/commons/jcs/admin/CacheElementInfo.java deleted file mode 100644 index 1c094232307..00000000000 --- a/src/org/apache/commons/jcs/admin/CacheElementInfo.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.apache.commons.jcs.admin; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.beans.ConstructorProperties; - - -/** - * Stores info on a cache element for the template - */ -public class CacheElementInfo -{ - /** element key */ - private final String key; - - /** is it eternal */ - private final boolean eternal; - - /** when it was created */ - private final String createTime; - - /** max life */ - private final long maxLifeSeconds; - - /** when it will expire */ - private final long expiresInSeconds; - - /** - * Parameterized constructor - * - * @param key element key - * @param eternal is it eternal - * @param createTime when it was created - * @param maxLifeSeconds max life - * @param expiresInSeconds when it will expire - */ - @ConstructorProperties({"key", "eternal", "createTime", "maxLifeSeconds", "expiresInSeconds"}) - public CacheElementInfo(String key, boolean eternal, String createTime, - long maxLifeSeconds, long expiresInSeconds) - { - super(); - this.key = key; - this.eternal = eternal; - this.createTime = createTime; - this.maxLifeSeconds = maxLifeSeconds; - this.expiresInSeconds = expiresInSeconds; - } - - /** - * @return a string representation of the key - */ - public String getKey() - { - return this.key; - } - - /** - * @return true if the item does not expire - */ - public boolean isEternal() - { - return this.eternal; - } - - /** - * @return the time the object was created - */ - public String getCreateTime() - { - return this.createTime; - } - - /** - * Ignored if isEternal - * @return the longest this object can live. - */ - public long getMaxLifeSeconds() - { - return this.maxLifeSeconds; - } - - /** - * Ignored if isEternal - * @return how many seconds until this object expires. - */ - public long getExpiresInSeconds() - { - return this.expiresInSeconds; - } - - /** - * @return string info on the item - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nCacheElementInfo " ); - buf.append( "\n Key [" ).append( getKey() ).append( "]" ); - buf.append( "\n Eternal [" ).append( isEternal() ).append( "]" ); - buf.append( "\n CreateTime [" ).append( getCreateTime() ).append( "]" ); - buf.append( "\n MaxLifeSeconds [" ).append( getMaxLifeSeconds() ).append( "]" ); - buf.append( "\n ExpiresInSeconds [" ).append( getExpiresInSeconds() ).append( "]" ); - - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/admin/CacheRegionInfo.java b/src/org/apache/commons/jcs/admin/CacheRegionInfo.java deleted file mode 100644 index 963f5d4b915..00000000000 --- a/src/org/apache/commons/jcs/admin/CacheRegionInfo.java +++ /dev/null @@ -1,180 +0,0 @@ -package org.apache.commons.jcs.admin; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.beans.ConstructorProperties; - - - -/** - * Stores info on a cache region for the template - */ -public class CacheRegionInfo -{ - /** The name of the cache region */ - private final String cacheName; - - /** The size of the cache region */ - private final int cacheSize; - - /** The status of the cache region */ - private final String cacheStatus; - - /** The statistics of the cache region */ - private final String cacheStatistics; - - /** The number of memory hits in the cache region */ - private final int hitCountRam; - - /** The number of auxiliary hits in the cache region */ - private final int hitCountAux; - - /** The number of misses in the cache region because the items were not found */ - private final int missCountNotFound; - - /** The number of misses in the cache region because the items were expired */ - private final int missCountExpired; - - /** The number of bytes counted so far, will be a total of all items */ - private final long byteCount; - - /** - * Parameterized constructor - * - * @param cacheName The name of the cache region - * @param cacheSize The size of the cache region - * @param cacheStatus The status of the cache region - * @param cacheStatistics The statistics of the cache region - * @param hitCountRam The number of memory hits in the cache region - * @param hitCountAux The number of auxiliary hits in the cache region - * @param missCountNotFound The number of misses in the cache region because the items were not found - * @param missCountExpired The number of misses in the cache region because the items were expired - * @param byteCount The number of bytes counted so far, will be a total of all items - */ - @ConstructorProperties({"cacheName", "cacheSize", "cacheStatus", "cacheStatistics", - "hitCountRam", "hitCountAux", "missCountNotFound", "missCountExpired", "byteCount"}) - public CacheRegionInfo(String cacheName, int cacheSize, String cacheStatus, - String cacheStatistics, int hitCountRam, int hitCountAux, - int missCountNotFound, int missCountExpired, long byteCount) - { - super(); - this.cacheName = cacheName; - this.cacheSize = cacheSize; - this.cacheStatus = cacheStatus; - this.cacheStatistics = cacheStatistics; - this.hitCountRam = hitCountRam; - this.hitCountAux = hitCountAux; - this.missCountNotFound = missCountNotFound; - this.missCountExpired = missCountExpired; - this.byteCount = byteCount; - } - - /** - * @return the cacheName - */ - public String getCacheName() - { - return this.cacheName; - } - - /** - * @return the cacheSize - */ - public int getCacheSize() - { - return this.cacheSize; - } - - /** - * @return a status string - */ - public String getCacheStatus() - { - return this.cacheStatus; - } - - /** - * Return the statistics for the region. - *

- * @return String - */ - public String getCacheStatistics() - { - return this.cacheStatistics; - } - - /** - * @return the hitCountRam - */ - public int getHitCountRam() - { - return hitCountRam; - } - - /** - * @return the hitCountAux - */ - public int getHitCountAux() - { - return hitCountAux; - } - - /** - * @return the missCountNotFound - */ - public int getMissCountNotFound() - { - return missCountNotFound; - } - - /** - * @return the missCountExpired - */ - public int getMissCountExpired() - { - return missCountExpired; - } - - /** - * @return total byte count - */ - public long getByteCount() - { - return this.byteCount; - } - - /** - * @return string info on the region - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nCacheRegionInfo " ); - if ( cacheName != null ) - { - buf.append( "\n CacheName [" + cacheName + "]" ); - buf.append( "\n Status [" + cacheStatus + "]" ); - } - buf.append( "\n ByteCount [" + getByteCount() + "]" ); - - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/admin/CountingOnlyOutputStream.java b/src/org/apache/commons/jcs/admin/CountingOnlyOutputStream.java deleted file mode 100644 index ea0baf8d032..00000000000 --- a/src/org/apache/commons/jcs/admin/CountingOnlyOutputStream.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.apache.commons.jcs.admin; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Keeps track of the number of bytes written to it, but doesn't write them anywhere. - */ -public class CountingOnlyOutputStream - extends OutputStream -{ - /** number of bytes passed through */ - private int count; // TODO should this be long? - - /** - * count as we write. - *

- * @param b - * @throws IOException - */ - @Override - public void write( byte[] b ) - throws IOException - { - this.count += b.length; - } - - /** - * count as we write. - *

- * @param b - * @param off - * @param len - * @throws IOException - */ - @Override - public void write( byte[] b, int off, int len ) - throws IOException - { - this.count += len; - } - - /** - * count as we write. - *

- * @param b - * @throws IOException - */ - @Override - public void write( int b ) - throws IOException - { - this.count++; - } - - /** - * The number of bytes that have passed through this stream. - *

- * @return int - */ - public int getCount() - { - return this.count; - } -} diff --git a/src/org/apache/commons/jcs/admin/JCSAdmin.jsp b/src/org/apache/commons/jcs/admin/JCSAdmin.jsp deleted file mode 100644 index d92b0af8dd3..00000000000 --- a/src/org/apache/commons/jcs/admin/JCSAdmin.jsp +++ /dev/null @@ -1,310 +0,0 @@ -<%-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---%> -<%@page import="org.apache.commons.jcs.JCS"%> -<%@page import="org.apache.commons.jcs.access.CacheAccess" %> -<%@page import="org.apache.commons.jcs.admin.CacheElementInfo" %> -<%@page import="org.apache.commons.jcs.admin.CacheRegionInfo" %> -<%@page import="java.io.Serializable" %> -<%@page import="java.util.HashMap" %> - - - - - - - - - JCS Admin Servlet - - - - - -<% - String CACHE_NAME_PARAM = "cacheName"; - String ACTION_PARAM = "action"; - String CLEAR_ALL_REGIONS_ACTION = "clearAllRegions"; - String CLEAR_REGION_ACTION = "clearRegion"; - String REMOVE_ACTION = "remove"; - String DETAIL_ACTION = "detail"; - String REGION_SUMMARY_ACTION = "regionSummary"; - String ITEM_ACTION = "item"; - String KEY_PARAM = "key"; - String SILENT_PARAM = "silent"; - - String DEFAULT_TEMPLATE_NAME = "DEFAULT"; - String REGION_DETAIL_TEMPLATE_NAME = "DETAIL"; - String ITEM_TEMPLATE_NAME = "ITEM"; - String REGION_SUMMARY_TEMPLATE_NAME = "SUMMARY"; - - String templateName = DEFAULT_TEMPLATE_NAME; - - HashMap context = new HashMap(); - - // Get cacheName for actions from request (might be null) - String cacheName = request.getParameter( CACHE_NAME_PARAM ); - - if ( cacheName != null ) - { - cacheName = cacheName.trim(); - } - - // If an action was provided, handle it - String action = request.getParameter( ACTION_PARAM ); - - if ( action != null ) - { - if ( action.equals( CLEAR_ALL_REGIONS_ACTION ) ) - { - jcsBean.clearAllRegions(); - } - else if ( action.equals( CLEAR_REGION_ACTION ) ) - { - if ( cacheName == null ) - { - // Not Allowed - } - else - { - jcsBean.clearRegion( cacheName ); - } - } - else if ( action.equals( REMOVE_ACTION ) ) - { - String[] keys = request.getParameterValues( KEY_PARAM ); - - for ( int i = 0; i < keys.length; i++ ) - { - jcsBean.removeItem( cacheName, keys[ i ] ); - } - - templateName = REGION_DETAIL_TEMPLATE_NAME; - } - else if ( action.equals( DETAIL_ACTION ) ) - { - templateName = REGION_DETAIL_TEMPLATE_NAME; - } - else if ( action.equals( ITEM_ACTION ) ) - { - templateName = ITEM_TEMPLATE_NAME; - } - else if ( action.equals( REGION_SUMMARY_ACTION ) ) - { - templateName = REGION_SUMMARY_TEMPLATE_NAME; - } - } - - if ( request.getParameter( SILENT_PARAM ) != null ) - { - // If silent parameter was passed, no output should be produced. - //return null; - } - else - { - // Populate the context based on the template - if ( templateName == REGION_DETAIL_TEMPLATE_NAME ) - { - //context.put( "cacheName", cacheName ); - context.put( "elementInfoRecords", jcsBean.buildElementInfo( cacheName ) ); - } - else if ( templateName == DEFAULT_TEMPLATE_NAME ) - { - context.put( "cacheInfoRecords", jcsBean.buildCacheInfo() ); - } - } - -/////////////////////////////////////////////////////////////////////////////////// - //handle display - - if ( templateName == ITEM_TEMPLATE_NAME ) - { - String key = request.getParameter( KEY_PARAM ); - - if ( key != null ) - { - key = key.trim(); - } - - CacheAccess cache = JCS.getInstance( cacheName ); - org.apache.commons.jcs.engine.behavior.ICacheElement element = cache.getCacheElement( key ); -%> -

Item for key [<%=key%>] in region [<%=cacheName%>]

- -Region Detail -| All Regions - -
-	<%=element%>
-  
-<% - } - else if ( templateName == REGION_SUMMARY_TEMPLATE_NAME ) - { -%> - -

Summary for region [<%=cacheName%>]

- -All Regions - -<% - CacheAccess cache = JCS.getInstance( cacheName ); - String stats = cache.getStats(); -%> - -
- Stats for region [<%=cacheName%>] - -
-    	<%=stats%>
-    
- -<% - } - else if ( templateName == REGION_DETAIL_TEMPLATE_NAME ) - { -%> - -

Detail for region [<%=cacheName%>]

- -All Regions - - - - - - - - - -<% - CacheElementInfo[] list = (CacheElementInfo[]) context.get( "elementInfoRecords" ); - for (CacheElementInfo element : list) - { -%> - - - - - - - - -<% - } - - CacheAccess cache = JCS.getInstance( cacheName ); - String stats = cache.getStats(); -%> -
Key Eternal? Create time Max Life (s) Till Expiration (s)
<%=element.getKey()%> <%=element.isEternal()%> <%=element.getCreateTime()%> <%=element.getMaxLifeSeconds()%> <%=element.getExpiresInSeconds()%> - View - | Remove -
- -
- Stats for region [<%=cacheName%>] - -
-    	<%=stats%>
-    
-<% - } - else - { -%> - -

Cache Regions

- -

-These are the regions which are currently defined in the cache. 'Items' and -'Bytes' refer to the elements currently in memory (not spooled). You can clear -all items for a region by selecting 'Remove all' next to the desired region -below. You can also Clear all regions -which empties the entire cache. -

-

-

- - Retrieve (key)   - (region) - -
-

- - - - - - - - - - - - - -<% - CacheRegionInfo[] list = (CacheRegionInfo[]) context.get( "cacheInfoRecords" ); - for (CacheRegionInfo record : listSelect) - { -%> - - - - - - - - - - - -<% - } -%> -
Cache Name Items Bytes Status Memory Hits Aux Hits Not Found Misses Expired Misses
<%=record.getCacheName()%> <%=record.getCacheSize()%> <%=record.getByteCount()%> <%=record.getCacheStatus()%> <%=record.getHitCountRam()%> <%=record.getHitCountAux()%> <%=record.getMissCountNotFound()%> <%=record.getMissCountExpired()%> - Summary - | Detail - | Clear -
-<% - } -%> - - - - - diff --git a/src/org/apache/commons/jcs/admin/JCSAdminBean.java b/src/org/apache/commons/jcs/admin/JCSAdminBean.java deleted file mode 100644 index 52476c86495..00000000000 --- a/src/org/apache/commons/jcs/admin/JCSAdminBean.java +++ /dev/null @@ -1,436 +0,0 @@ -package org.apache.commons.jcs.admin; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheServer; -import org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheServerFactory; -import org.apache.commons.jcs.engine.CacheElementSerialized; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.CompositeCacheManager; -import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache; - -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.text.DateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.LinkedList; -import java.util.Set; - -/** - * A servlet which provides HTTP access to JCS. Allows a summary of regions to be viewed, and - * removeAll to be run on individual regions or all regions. Also provides the ability to remove - * items (any number of key arguments can be provided with action 'remove'). Should be initialized - * with a properties file that provides at least a classpath resource loader. - */ -public class JCSAdminBean implements JCSJMXBean -{ - /** The cache manager. */ - private final CompositeCacheManager cacheHub; - - /** - * Default constructor - */ - public JCSAdminBean() - { - super(); - try - { - this.cacheHub = CompositeCacheManager.getInstance(); - } - catch (CacheException e) - { - throw new RuntimeException("Could not retrieve cache manager instance", e); - } - } - - /** - * Parameterized constructor - * - * @param cacheHub the cache manager instance - */ - public JCSAdminBean(CompositeCacheManager cacheHub) - { - super(); - this.cacheHub = cacheHub; - } - - /** - * Builds up info about each element in a region. - *

- * @param cacheName - * @return Array of CacheElementInfo objects - * @throws Exception - */ - @Override - public CacheElementInfo[] buildElementInfo( String cacheName ) - throws Exception - { - CompositeCache cache = cacheHub.getCache( cacheName ); - - Serializable[] keys = cache.getMemoryCache().getKeySet().toArray(new Serializable[0]); - - // Attempt to sort keys according to their natural ordering. If that - // fails, get the key array again and continue unsorted. - try - { - Arrays.sort( keys ); - } - catch ( Exception e ) - { - keys = cache.getMemoryCache().getKeySet().toArray(new Serializable[0]); - } - - LinkedList records = new LinkedList(); - - ICacheElement element; - IElementAttributes attributes; - CacheElementInfo elementInfo; - - DateFormat format = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT ); - - long now = System.currentTimeMillis(); - - for (Serializable key : keys) - { - element = cache.getMemoryCache().getQuiet( key ); - - attributes = element.getElementAttributes(); - - elementInfo = new CacheElementInfo( - String.valueOf( key ), - attributes.getIsEternal(), - format.format(new Date(attributes.getCreateTime())), - attributes.getMaxLife(), - (now - attributes.getCreateTime() - attributes.getMaxLife() * 1000 ) / -1000); - - records.add( elementInfo ); - } - - return records.toArray(new CacheElementInfo[0]); - } - - /** - * Builds up data on every region. - *

- * TODO we need a most light weight method that does not count bytes. The byte counting can - * really swamp a server. - * @return list of CacheRegionInfo objects - * @throws Exception - */ - @Override - public CacheRegionInfo[] buildCacheInfo() - throws Exception - { - String[] cacheNames = cacheHub.getCacheNames(); - - Arrays.sort( cacheNames ); - - LinkedList cacheInfo = new LinkedList(); - - CacheRegionInfo regionInfo; - CompositeCache cache; - - for ( int i = 0; i < cacheNames.length; i++ ) - { - cache = cacheHub.getCache( cacheNames[i] ); - - regionInfo = new CacheRegionInfo( - cache.getCacheName(), - cache.getSize(), - cache.getStatus().toString(), - cache.getStats(), - cache.getHitCountRam(), - cache.getHitCountAux(), - cache.getMissCountNotFound(), - cache.getMissCountExpired(), - getByteCount( cache )); - - cacheInfo.add( regionInfo ); - } - - return cacheInfo.toArray(new CacheRegionInfo[0]); - } - - - /** - * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in - * the region or an error occurs, suppresses exceptions and returns 0. - *

- * - * @return int The size of the region in bytes. - */ - @Override - public int getByteCount(String cacheName) - { - return getByteCount(cacheHub.getCache(cacheName)); - } - - /** - * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in - * the region or an error occurs, suppresses exceptions and returns 0. - *

- * - * @return int The size of the region in bytes. - */ - public int getByteCount(CompositeCache cache) - { - if (cache == null) - { - throw new IllegalArgumentException("The cache object specified was null."); - } - - long size = 0; - IMemoryCache memCache = cache.getMemoryCache(); - - for (K key : memCache.getKeySet()) - { - ICacheElement ice = null; - try - { - ice = memCache.get(key); - } - catch (IOException e) - { - throw new RuntimeException("IOException while trying to get a cached element", e); - } - - if (ice == null) - { - continue; - } - - if (ice instanceof CacheElementSerialized) - { - size = size + ((CacheElementSerialized) ice).getSerializedValue().length; - } - else - { - Object element = ice.getVal(); - - //CountingOnlyOutputStream: Keeps track of the number of bytes written to it, but doesn't write them anywhere. - CountingOnlyOutputStream counter = new CountingOnlyOutputStream(); - ObjectOutputStream out = null; - try - { - out = new ObjectOutputStream(counter); - out.writeObject(element); - } - catch (IOException e) - { - throw new RuntimeException("IOException while trying to measure the size of the cached element", e); - } - finally - { - try - { - if (out != null) - { - out.close(); - } - } - catch (IOException e) - { - // ignore - } - try - { - counter.close(); - } - catch (IOException e) - { - // ignore - } - } - - // 4 bytes lost for the serialization header - size = size + counter.getCount() - 4; - } - } - - if (size > Integer.MAX_VALUE) - { - throw new IllegalStateException("The size of cache " + cache.getCacheName() + " (" + size + " bytes) is too large to be represented as an integer."); - } - - return (int) size; - } - - /** - * Clears all regions in the cache. - *

- * If this class is running within a remote cache server, clears all regions via the RemoteCacheServer - * API, so that removes will be broadcast to client machines. Otherwise clears all regions in the cache directly via - * the usual cache API. - */ - @Override - public void clearAllRegions() throws IOException - { - if (RemoteCacheServerFactory.getRemoteCacheServer() == null) - { - // Not running in a remote cache server. - // Remove objects from the cache directly, as no need to broadcast removes to client machines... - - String[] names = cacheHub.getCacheNames(); - - for (int i = 0; i < names.length; i++) - { - cacheHub.getCache(names[i]).removeAll(); - } - } - else - { - // Running in a remote cache server. - // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines... - try - { - String[] cacheNames = cacheHub.getCacheNames(); - - // Call remoteCacheServer.removeAll(String) for each cacheName... - RemoteCacheServer remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer(); - for (int i = 0; i < cacheNames.length; i++) - { - String cacheName = cacheNames[i]; - remoteCacheServer.removeAll(cacheName); - } - } - catch (IOException e) - { - throw new IllegalStateException("Failed to remove all elements from all cache regions: " + e, e); - } - } - } - - /** - * Clears a particular cache region. - *

- * If this class is running within a remote cache server, clears the region via the RemoteCacheServer - * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual - * cache API. - */ - @Override - public void clearRegion(String cacheName) throws IOException - { - if (cacheName == null) - { - throw new IllegalArgumentException("The cache name specified was null."); - } - if (RemoteCacheServerFactory.getRemoteCacheServer() == null) - { - // Not running in a remote cache server. - // Remove objects from the cache directly, as no need to broadcast removes to client machines... - cacheHub.getCache(cacheName).removeAll(); - } - else - { - // Running in a remote cache server. - // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines... - try - { - // Call remoteCacheServer.removeAll(String)... - RemoteCacheServer remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer(); - remoteCacheServer.removeAll(cacheName); - } - catch (IOException e) - { - throw new IllegalStateException("Failed to remove all elements from cache region [" + cacheName + "]: " + e, e); - } - } - } - - /** - * Removes a particular item from a particular region. - *

- * If this class is running within a remote cache server, removes the item via the RemoteCacheServer - * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual - * cache API. - * - * @param cacheName - * @param key - * - * @throws IOException - */ - @Override - public void removeItem(String cacheName, String key) throws IOException - { - if (cacheName == null) - { - throw new IllegalArgumentException("The cache name specified was null."); - } - if (key == null) - { - throw new IllegalArgumentException("The key specified was null."); - } - if (RemoteCacheServerFactory.getRemoteCacheServer() == null) - { - // Not running in a remote cache server. - // Remove objects from the cache directly, as no need to broadcast removes to client machines... - cacheHub.getCache(cacheName).remove(key); - } - else - { - // Running in a remote cache server. - // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines... - try - { - Object keyToRemove = null; - CompositeCache cache = CompositeCacheManager.getInstance().getCache(cacheName); - - // A String key was supplied, but to remove elements via the RemoteCacheServer API, we need the - // actual key object as stored in the cache (i.e. a Serializable object). To find the key in this form, - // we iterate through all keys stored in the memory cache until we find one whose toString matches - // the string supplied... - Set allKeysInCache = cache.getMemoryCache().getKeySet(); - for (Object keyInCache : allKeysInCache) - { - if (keyInCache.toString().equals(key)) - { - if (keyToRemove == null) - { - keyToRemove = keyInCache; - } - else - { - // A key matching the one specified was already found... - throw new IllegalStateException("Unexpectedly found duplicate keys in the cache region matching the key specified."); - } - } - } - if (keyToRemove == null) - { - throw new IllegalStateException("No match for this key could be found in the set of keys retrieved from the memory cache."); - } - // At this point, we have retrieved the matching K key. - - // Call remoteCacheServer.remove(String, Serializable)... - RemoteCacheServer remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer(); - remoteCacheServer.remove(cacheName, key); - } - catch (Exception e) - { - throw new IllegalStateException("Failed to remove element with key [" + key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e); - } - } - } -} diff --git a/src/org/apache/commons/jcs/admin/JCSJMXBean.java b/src/org/apache/commons/jcs/admin/JCSJMXBean.java deleted file mode 100644 index 4ad4b7ebf28..00000000000 --- a/src/org/apache/commons/jcs/admin/JCSJMXBean.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.apache.commons.jcs.admin; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import javax.management.MXBean; -import java.io.IOException; - -/** - * A MXBean to expose the JCS statistics to JMX - */ -@MXBean -public interface JCSJMXBean -{ - /** - * Builds up info about each element in a region. - *

- * @param cacheName - * @return Array of CacheElementInfo objects - * @throws Exception - */ - CacheElementInfo[] buildElementInfo( String cacheName ) throws Exception; - - /** - * Builds up data on every region. - *

- * TODO we need a most light weight method that does not count bytes. The byte counting can - * really swamp a server. - * @return Array of CacheRegionInfo objects - * @throws Exception - */ - CacheRegionInfo[] buildCacheInfo() throws Exception; - - /** - * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in - * the region or an error occurs, suppresses exceptions and returns 0. - *

- * - * @return int The size of the region in bytes. - */ - int getByteCount(String cacheName); - - /** - * Clears all regions in the cache. - *

- * If this class is running within a remote cache server, clears all regions via the RemoteCacheServer - * API, so that removes will be broadcast to client machines. Otherwise clears all regions in the cache directly via - * the usual cache API. - */ - void clearAllRegions() throws IOException; - - /** - * Clears a particular cache region. - *

- * If this class is running within a remote cache server, clears the region via the RemoteCacheServer - * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual - * cache API. - */ - void clearRegion(String cacheName) throws IOException; - - /** - * Removes a particular item from a particular region. - *

- * If this class is running within a remote cache server, removes the item via the RemoteCacheServer - * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual - * cache API. - * - * @param cacheName - * @param key - * - * @throws IOException - */ - void removeItem(String cacheName, String key) throws IOException; -} diff --git a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCache.java b/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCache.java deleted file mode 100644 index f66d3f58c6f..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCache.java +++ /dev/null @@ -1,210 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.CacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.engine.match.KeyMatcherPatternImpl; -import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher; -import org.apache.commons.jcs.utils.serialization.StandardSerializer; - -/** This holds convenience methods used by most auxiliary caches. */ -public abstract class AbstractAuxiliaryCache - implements AuxiliaryCache -{ - /** An optional event logger */ - private ICacheEventLogger cacheEventLogger; - - /** The serializer. Uses a standard serializer by default. */ - private IElementSerializer elementSerializer = new StandardSerializer(); - - /** Key matcher used by the getMatching API */ - private IKeyMatcher keyMatcher = new KeyMatcherPatternImpl(); - - /** - * Logs an event if an event logger is configured. - *

- * @param item - * @param eventName - * @return ICacheEvent - */ - protected ICacheEvent createICacheEvent( ICacheElement item, String eventName ) - { - if ( cacheEventLogger == null ) - { - return new CacheEvent(); - } - String diskLocation = getEventLoggingExtraInfo(); - String regionName = null; - K key = null; - if ( item != null ) - { - regionName = item.getCacheName(); - key = item.getKey(); - } - return cacheEventLogger.createICacheEvent( getAuxiliaryCacheAttributes().getName(), regionName, eventName, - diskLocation, key ); - } - - /** - * Logs an event if an event logger is configured. - *

- * @param regionName - * @param key - * @param eventName - * @return ICacheEvent - */ - protected ICacheEvent createICacheEvent( String regionName, T key, String eventName ) - { - if ( cacheEventLogger == null ) - { - return new CacheEvent(); - } - String diskLocation = getEventLoggingExtraInfo(); - return cacheEventLogger.createICacheEvent( getAuxiliaryCacheAttributes().getName(), regionName, eventName, - diskLocation, key ); - - } - - /** - * Logs an event if an event logger is configured. - *

- * @param cacheEvent - */ - protected void logICacheEvent( ICacheEvent cacheEvent ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logICacheEvent( cacheEvent ); - } - } - - /** - * Logs an event if an event logger is configured. - *

- * @param source - * @param eventName - * @param optionalDetails - */ - protected void logApplicationEvent( String source, String eventName, String optionalDetails ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails ); - } - } - - /** - * Logs an event if an event logger is configured. - *

- * @param source - * @param eventName - * @param errorMessage - */ - protected void logError( String source, String eventName, String errorMessage ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logError( source, eventName, errorMessage ); - } - } - - /** - * Gets the extra info for the event log. - *

- * @return IP, or disk location, etc. - */ - public abstract String getEventLoggingExtraInfo(); - - /** - * Allows it to be injected. - *

- * @param cacheEventLogger - */ - @Override - public void setCacheEventLogger( ICacheEventLogger cacheEventLogger ) - { - this.cacheEventLogger = cacheEventLogger; - } - - /** - * Allows it to be injected. - *

- * @return cacheEventLogger - */ - public ICacheEventLogger getCacheEventLogger() - { - return this.cacheEventLogger; - } - - /** - * Allows you to inject a custom serializer. A good example would be a compressing standard - * serializer. - *

- * Does not allow you to set it to null. - *

- * @param elementSerializer - */ - @Override - public void setElementSerializer( IElementSerializer elementSerializer ) - { - if ( elementSerializer != null ) - { - this.elementSerializer = elementSerializer; - } - } - - /** - * Allows it to be injected. - *

- * @return elementSerializer - */ - public IElementSerializer getElementSerializer() - { - return this.elementSerializer; - } - - /** - * Sets the key matcher used by get matching. - *

- * @param keyMatcher - */ - @Override - public void setKeyMatcher( IKeyMatcher keyMatcher ) - { - if ( keyMatcher != null ) - { - this.keyMatcher = keyMatcher; - } - } - - /** - * Returns the key matcher used by get matching. - *

- * @return keyMatcher - */ - public IKeyMatcher getKeyMatcher() - { - return this.keyMatcher; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheAttributes.java deleted file mode 100644 index e268c601e60..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheAttributes.java +++ /dev/null @@ -1,146 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This has common attributes used by all auxiliaries. - */ -public abstract class AbstractAuxiliaryCacheAttributes - implements AuxiliaryCacheAttributes -{ - /** Don't change */ - private static final long serialVersionUID = -6594609334959187673L; - - /** cacheName */ - private String cacheName; - - /** name */ - private String name; - - /** eventQueueType -- pooled, or single threaded */ - private ICacheEventQueue.QueueType eventQueueType; - - /** Named when pooled */ - private String eventQueuePoolName; - - /** - * @param name - */ - @Override - public void setCacheName( String name ) - { - this.cacheName = name; - } - - /** - * Gets the cacheName attribute of the AuxiliaryCacheAttributes object - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return this.cacheName; - } - - /** - * This is the name of the auxiliary in configuration file. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes#setName(java.lang.String) - */ - @Override - public void setName( String s ) - { - this.name = s; - } - - /** - * Gets the name attribute of the AuxiliaryCacheAttributes object - *

- * @return The name value - */ - @Override - public String getName() - { - return this.name; - } - - /** - * SINGLE is the default. If you choose POOLED, the value of EventQueuePoolName will be used - *

- * @param queueType SINGLE or POOLED - */ - @Override - public void setEventQueueType( ICacheEventQueue.QueueType queueType ) - { - this.eventQueueType = queueType; - } - - /** - * @return SINGLE or POOLED - */ - @Override - public ICacheEventQueue.QueueType getEventQueueType() - { - return eventQueueType; - } - - /** - * If you choose a POOLED event queue type, the value of EventQueuePoolName will be used. This - * is ignored if the pool type is SINGLE - *

- * @param s SINGLE or POOLED - */ - @Override - public void setEventQueuePoolName( String s ) - { - eventQueuePoolName = s; - } - - /** - * Sets the pool name to use. If a pool is not found by this name, the thread pool manager will - * return a default configuration. - *

- * @return name of thread pool to use for this auxiliary - */ - @Override - public String getEventQueuePoolName() - { - return eventQueuePoolName; - } - - /** - * @see java.lang.Object#clone() - */ - @Override - public AbstractAuxiliaryCacheAttributes clone() - { - try - { - return (AbstractAuxiliaryCacheAttributes)super.clone(); - } - catch (CloneNotSupportedException e) - { - throw new RuntimeException("Clone not supported. This should never happen.", e); - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheEventLogging.java b/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheEventLogging.java deleted file mode 100644 index 1147e08b6b6..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheEventLogging.java +++ /dev/null @@ -1,353 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; - -import java.io.IOException; -import java.io.Serializable; -import java.util.Map; -import java.util.Set; - -/** - * All ICacheEvents are defined as final. Children must implement process events. These are wrapped - * in event log parent calls. - * - * You can override the public method, but if you don't, the default will call getWithTiming. - */ -public abstract class AbstractAuxiliaryCacheEventLogging - extends AbstractAuxiliaryCache -{ - /** - * Puts an item into the cache. - * - * @param cacheElement - * @throws IOException - */ - @Override - public void update( ICacheElement cacheElement ) - throws IOException - { - updateWithEventLogging( cacheElement ); - } - - /** - * Puts an item into the cache. Wrapped in logging. - * - * @param cacheElement - * @throws IOException - */ - protected final void updateWithEventLogging( ICacheElement cacheElement ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheElement, ICacheEventLogger.UPDATE_EVENT ); - try - { - processUpdate( cacheElement ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Implementation of put. - * - * @param cacheElement - * @throws IOException - */ - protected abstract void processUpdate( ICacheElement cacheElement ) - throws IOException; - - /** - * Gets the item from the cache. - * - * @param key - * @return ICacheElement, a wrapper around the key, value, and attributes - * @throws IOException - */ - @Override - public ICacheElement get( K key ) - throws IOException - { - return getWithEventLogging( key ); - } - - /** - * Gets the item from the cache. Wrapped in logging. - * - * @param key - * @return ICacheElement, a wrapper around the key, value, and attributes - * @throws IOException - */ - protected final ICacheElement getWithEventLogging( K key ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( getCacheName(), key, ICacheEventLogger.GET_EVENT ); - try - { - return processGet( key ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Implementation of get. - * - * @param key - * @return ICacheElement, a wrapper around the key, value, and attributes - * @throws IOException - */ - protected abstract ICacheElement processGet( K key ) - throws IOException; - - /** - * Gets multiple items from the cache based on the given set of keys. - * - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple(Set keys) - throws IOException - { - return getMultipleWithEventLogging( keys ); - } - - /** - * Gets multiple items from the cache based on the given set of keys. - * - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - protected final Map> getMultipleWithEventLogging(Set keys ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( getCacheName(), (Serializable) keys, - ICacheEventLogger.GETMULTIPLE_EVENT ); - try - { - return processGetMultiple( keys ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Implementation of getMultiple. - * - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - protected abstract Map> processGetMultiple(Set keys) - throws IOException; - - /** - * Gets items from the cache matching the given pattern. Items from memory will replace those - * from remote sources. - * - * This only works with string keys. It's too expensive to do a toString on every key. - * - * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk - * cache will convert * to % and . to _ - * - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data matching the pattern. - * @throws IOException - */ - @Override - public Map> getMatching( String pattern ) - throws IOException - { - return getMatchingWithEventLogging( pattern ); - } - - /** - * Gets mmatching items from the cache based on the given pattern. - * - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data matching the pattern. - * @throws IOException - */ - protected final Map> getMatchingWithEventLogging( String pattern ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( getCacheName(), pattern, ICacheEventLogger.GETMATCHING_EVENT ); - try - { - return processGetMatching( pattern ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Implementation of getMatching. - * - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data matching the pattern. - * @throws IOException - */ - protected abstract Map> processGetMatching( String pattern ) - throws IOException; - - /** - * Removes the item from the cache. Wraps the remove in event logs. - * - * @param key - * @return boolean, whether or not the item was removed - * @throws IOException - */ - @Override - public boolean remove( K key ) - throws IOException - { - return removeWithEventLogging( key ); - } - - /** - * Removes the item from the cache. Wraps the remove in event logs. - * - * @param key - * @return boolean, whether or not the item was removed - * @throws IOException - */ - protected final boolean removeWithEventLogging( K key ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( getCacheName(), key, ICacheEventLogger.REMOVE_EVENT ); - try - { - return processRemove( key ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Specific implementation of remove. - * - * @param key - * @return boolean, whether or not the item was removed - * @throws IOException - */ - protected abstract boolean processRemove( K key ) - throws IOException; - - /** - * Removes all from the region. Wraps the removeAll in event logs. - * - * @throws IOException - */ - @Override - public void removeAll() - throws IOException - { - removeAllWithEventLogging(); - } - - /** - * Removes all from the region. Wraps the removeAll in event logs. - * - * @throws IOException - */ - protected final void removeAllWithEventLogging() - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( getCacheName(), "all", ICacheEventLogger.REMOVEALL_EVENT ); - try - { - processRemoveAll(); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Specific implementation of removeAll. - * - * @throws IOException - */ - protected abstract void processRemoveAll() - throws IOException; - - /** - * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie. - * - * @throws IOException - */ - @Override - public void dispose() - throws IOException - { - disposeWithEventLogging(); - } - - /** - * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie. - * Wraps the removeAll in event logs. - * - * @throws IOException - */ - protected final void disposeWithEventLogging() - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( getCacheName(), "none", ICacheEventLogger.DISPOSE_EVENT ); - try - { - processDispose(); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Specific implementation of dispose. - * - * @throws IOException - */ - protected abstract void processDispose() - throws IOException; -} diff --git a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheFactory.java deleted file mode 100644 index 657015e29fe..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheFactory.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheFactory; - -/** - * Base class for auxiliary cache factories. - */ -public abstract class AbstractAuxiliaryCacheFactory - implements AuxiliaryCacheFactory -{ - /** The auxiliary name. The composite cache manager keeps this in a map, keyed by name. */ - private String name = this.getClass().getSimpleName(); - - /** - * Initialize this factory - */ - @Override - public void initialize() - { - // empty - } - - /** - * Dispose of this factory, clean up shared resources - */ - @Override - public void dispose() - { - // empty - } - - /** - * Gets the name attribute of the DiskCacheFactory object - *

- * @return The name value - */ - @Override - public String getName() - { - return this.name; - } - - /** - * Sets the name attribute of the DiskCacheFactory object - *

- * @param name The new name value - */ - @Override - public void setName( String name ) - { - this.name = name; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java b/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java deleted file mode 100644 index 4a3e3debc2f..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java +++ /dev/null @@ -1,206 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Used to monitor and repair any failed connection for the lateral cache service. By default the - * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an - * error. Upon the notification of a connection error, the monitor changes to operate in a time - * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed - * connections are restored, it changes back to the failure driven mode. - */ -public abstract class AbstractAuxiliaryCacheMonitor extends Thread -{ - /** The logger */ - protected final Log log = LogFactory.getLog( this.getClass() ); - - /** How long to wait between runs */ - protected static long idlePeriod = 20 * 1000; - - /** - * Must make sure AbstractAuxiliaryCacheMonitor is started before any error can be detected! - */ - protected AtomicBoolean allright = new AtomicBoolean(true); - - /** - * shutdown flag - */ - private AtomicBoolean shutdown = new AtomicBoolean(false); - - /** Synchronization helper lock */ - private Lock lock = new ReentrantLock(); - - /** Synchronization helper condition */ - private Condition trigger = lock.newCondition(); - - /** - * Constructor - * - * @param name the thread name - */ - public AbstractAuxiliaryCacheMonitor(String name) - { - super(name); - } - - /** - * Configures the idle period between repairs. - *

- * @param idlePeriod The new idlePeriod value - */ - public static void setIdlePeriod( long idlePeriod ) - { - if ( idlePeriod > AbstractAuxiliaryCacheMonitor.idlePeriod ) - { - AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod; - } - } - - /** - * Notifies the cache monitor that an error occurred, and kicks off the error recovery process. - */ - public void notifyError() - { - if (allright.compareAndSet(true, false)) - { - signalTrigger(); - } - } - - /** - * Notifies the cache monitor that the service shall shut down - */ - public void notifyShutdown() - { - if (shutdown.compareAndSet(false, true)) - { - signalTrigger(); - } - } - - // Trigger continuation of loop - private void signalTrigger() - { - try - { - lock.lock(); - trigger.signal(); - } - finally - { - lock.unlock(); - } - } - - /** - * Clean up all resources before shutdown - */ - protected abstract void dispose(); - - /** - * do actual work - */ - protected abstract void doWork(); - - /** - * Main processing method for the AbstractAuxiliaryCacheMonitor object - */ - @Override - public void run() - { - do - { - if ( log.isDebugEnabled() ) - { - if ( allright.get() ) - { - log.debug( "ERROR DRIVEN MODE: allright = true, cache monitor will wait for an error." ); - } - else - { - log.debug( "ERROR DRIVEN MODE: allright = false cache monitor running." ); - } - } - - if ( allright.get() ) - { - // Failure driven mode. - try - { - lock.lock(); - trigger.await(); - // wake up only if there is an error. - } - catch ( InterruptedException ignore ) - { - //no op, this is expected - } - finally - { - lock.unlock(); - } - } - - // check for requested shutdown - if ( shutdown.get() ) - { - log.info( "Shutting down cache monitor" ); - dispose(); - return; - } - - // The "allright" flag must be false here. - // Simply presume we can fix all the errors until proven otherwise. - allright.set(true); - - if ( log.isDebugEnabled() ) - { - log.debug( "Cache monitor running." ); - } - - doWork(); - - try - { - // don't want to sleep after waking from an error - // run immediately and sleep here. - if ( log.isDebugEnabled() ) - { - log.debug( "Cache monitor sleeping for " + idlePeriod + " between runs." ); - } - - Thread.sleep( idlePeriod ); - } - catch ( InterruptedException ex ) - { - // ignore; - } - } - while ( true ); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCache.java b/src/org/apache/commons/jcs/auxiliary/AuxiliaryCache.java deleted file mode 100644 index 3bc3a5248c6..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCache.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.engine.stats.behavior.IStats; - -import java.io.IOException; -import java.util.Set; - -/** - * Tag interface for auxiliary caches. Currently this provides no additional methods over what is in - * ICache, but I anticipate that will change. For example, there will be a mechanism for determining - * the type (disk/lateral/remote) of the auxiliary here -- and the existing getCacheType will be - * removed from ICache. - */ -public interface AuxiliaryCache - extends ICache -{ - /** - * Get a set of the keys for all elements in the auxiliary cache. - *

- * @return a set of the key type - * TODO This should probably be done in chunks with a range passed in. This - * will be a problem if someone puts a 1,000,000 or so items in a - * region. - * @throws IOException if access to the auxiliary cache fails - */ - Set getKeySet() throws IOException; - - /** - * @return the historical and statistical data for a region's auxiliary cache. - */ - IStats getStatistics(); - - /** - * This returns the generic attributes for an auxiliary cache. Most implementations will cast - * this to a more specific type. - *

- * @return the attributes for the auxiliary cache - */ - AuxiliaryCacheAttributes getAuxiliaryCacheAttributes(); - - /** - * Allows you to inject a custom serializer. A good example would be a compressing standard - * serializer. - *

- * @param elementSerializer - */ - void setElementSerializer( IElementSerializer elementSerializer ); - - /** - * Every Auxiliary must allow for the use of an event logger. - *

- * @param cacheEventLogger - */ - void setCacheEventLogger( ICacheEventLogger cacheEventLogger ); -} diff --git a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheAttributes.java deleted file mode 100644 index f962cd278dc..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheAttributes.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; - -/** - * This is a nominal interface that auxiliary cache attributes should implement. This allows the - * auxiliary mangers to share a common interface. - */ -public interface AuxiliaryCacheAttributes - extends Serializable, Cloneable -{ - /** - * Sets the name of the cache, referenced by the appropriate manager. - *

- * @param s The new cacheName value - */ - void setCacheName( String s ); - - /** - * Gets the cacheName attribute of the AuxiliaryCacheAttributes object - *

- * @return The cacheName value - */ - String getCacheName(); - - /** - * Name known by by configurator - *

- * @param s The new name value - */ - void setName( String s ); - - /** - * Gets the name attribute of the AuxiliaryCacheAttributes object - *

- * @return The name value - */ - String getName(); - - /** - * SINGLE is the default. If you choose POOLED, the value of EventQueuePoolName will be used - *

- * @param s SINGLE or POOLED - */ - void setEventQueueType( ICacheEventQueue.QueueType s ); - - /** - * @return SINGLE or POOLED - */ - ICacheEventQueue.QueueType getEventQueueType(); - - /** - * If you choose a POOLED event queue type, the value of EventQueuePoolName will be used. This - * is ignored if the pool type is SINGLE - *

- * @param s SINGLE or POOLED - */ - void setEventQueuePoolName( String s ); - - /** - * Sets the pool name to use. If a pool is not found by this name, the thread pool manager will - * return a default configuration. - *

- * @return name of thread pool to use for this auxiliary - */ - String getEventQueuePoolName(); - - /** - * Clone object - */ - AuxiliaryCacheAttributes clone(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfigurator.java b/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfigurator.java deleted file mode 100644 index 1a87313ecbd..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfigurator.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.utils.config.OptionConverter; -import org.apache.commons.jcs.utils.config.PropertySetter; -import org.apache.commons.jcs.utils.serialization.StandardSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.Properties; - -/** - * Configuration util for auxiliary caches. I plan to move the auxiliary configuration from the - * composite cache configurator here. - */ -public class AuxiliaryCacheConfigurator -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( AuxiliaryCacheConfigurator.class ); - - /** .attributes */ - public static final String ATTRIBUTE_PREFIX = ".attributes"; - - /** - * jcs.auxiliary.NAME.cacheeventlogger=CLASSNAME - *

- * jcs.auxiliary.NAME.cacheeventlogger.attributes.CUSTOMPROPERTY=VALUE - */ - public static final String CACHE_EVENT_LOGGER_PREFIX = ".cacheeventlogger"; - - /** - * jcs.auxiliary.NAME.serializer=CLASSNAME - *

- * jcs.auxiliary.NAME.serializer.attributes.CUSTOMPROPERTY=VALUE - */ - public static final String SERIALIZER_PREFIX = ".serializer"; - - /** - * Parses the event logger config, if there is any for the auxiliary. - *

- * @param props - * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName - * @return cacheEventLogger - */ - public static ICacheEventLogger parseCacheEventLogger( Properties props, String auxPrefix ) - { - ICacheEventLogger cacheEventLogger = null; - - // auxFactory was not previously initialized. - String eventLoggerClassName = auxPrefix + CACHE_EVENT_LOGGER_PREFIX; - cacheEventLogger = OptionConverter.instantiateByKey( props, eventLoggerClassName, null ); - if ( cacheEventLogger != null ) - { - String cacheEventLoggerAttributePrefix = auxPrefix + CACHE_EVENT_LOGGER_PREFIX + ATTRIBUTE_PREFIX; - PropertySetter.setProperties( cacheEventLogger, props, cacheEventLoggerAttributePrefix + "." ); - if ( log.isInfoEnabled() ) - { - log.info( "Using custom cache event logger [" + cacheEventLogger + "] for auxiliary [" + auxPrefix - + "]" ); - } - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "No cache event logger defined for auxiliary [" + auxPrefix + "]" ); - } - } - return cacheEventLogger; - } - - /** - * Parses the element config, if there is any for the auxiliary. - *

- * @param props - * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName - * @return cacheEventLogger - */ - public static IElementSerializer parseElementSerializer( Properties props, String auxPrefix ) - { - // TODO take in the entire prop key - IElementSerializer elementSerializer = null; - - // auxFactory was not previously initialized. - String elementSerializerClassName = auxPrefix + SERIALIZER_PREFIX; - elementSerializer = OptionConverter.instantiateByKey( props, elementSerializerClassName, null ); - if ( elementSerializer != null ) - { - String attributePrefix = auxPrefix + SERIALIZER_PREFIX + ATTRIBUTE_PREFIX; - PropertySetter.setProperties( elementSerializer, props, attributePrefix + "." ); - if ( log.isInfoEnabled() ) - { - log.info( "Using custom element serializer [" + elementSerializer + "] for auxiliary [" + auxPrefix - + "]" ); - } - } - else - { - // use the default standard serializer - elementSerializer = new StandardSerializer(); - if ( log.isInfoEnabled() ) - { - log.info( "Using standard serializer [" + elementSerializer + "] for auxiliary [" + auxPrefix + "]" ); - } - } - return elementSerializer; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheFactory.java deleted file mode 100644 index 8175c4a6947..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/AuxiliaryCacheFactory.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.apache.commons.jcs.auxiliary; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; - -/** - * All auxiliary caches must have a factory that the cache configurator can use to create instances. - */ -public interface AuxiliaryCacheFactory -{ - /** - * Creates an auxiliary using the supplied attributes. Adds it to the composite cache manager. - * - * @param attr - * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is - * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier to - * test. - * @param cacheEventLogger - * @param elementSerializer - * @return AuxiliaryCache - * @throws Exception if cache instance could not be created - */ - AuxiliaryCache createCache( - AuxiliaryCacheAttributes attr, ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - throws Exception; - - /** - * Initialize this factory - */ - void initialize(); - - /** - * Dispose of this factory, clean up shared resources - */ - void dispose(); - - /** - * Sets the name attribute of the AuxiliaryCacheFactory object - * - * @param s The new name value - */ - void setName( String s ); - - /** - * Gets the name attribute of the AuxiliaryCacheFactory object - * - * @return The name value - */ - String getName(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCache.java b/src/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCache.java deleted file mode 100644 index 9533171fbcd..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCache.java +++ /dev/null @@ -1,884 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheEventLogging; -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes; -import org.apache.commons.jcs.engine.CacheEventQueueFactory; -import org.apache.commons.jcs.engine.CacheInfo; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.jcs.utils.struct.LRUMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Abstract class providing a base implementation of a disk cache, which can be easily extended to - * implement a disk cache for a specific persistence mechanism. - * - * When implementing the abstract methods note that while this base class handles most things, it - * does not acquire or release any locks. Implementations should do so as necessary. This is mainly - * done to minimize the time spent in critical sections. - * - * Error handling in this class needs to be addressed. Currently if an exception is thrown by the - * persistence mechanism, this class destroys the event queue. Should it also destroy purgatory? - * Should it dispose itself? - */ -public abstract class AbstractDiskCache - extends AbstractAuxiliaryCacheEventLogging -{ - /** The logger */ - private static final Log log = LogFactory.getLog( AbstractDiskCache.class ); - - /** Generic disk cache attributes */ - private IDiskCacheAttributes diskCacheAttributes = null; - - /** - * Map where elements are stored between being added to this cache and actually spooled to disk. - * This allows puts to the disk cache to return quickly, and the more expensive operation of - * serializing the elements to persistent storage queued for later. - * - * If the elements are pulled into the memory cache while the are still in purgatory, writing to - * disk can be canceled. - */ - private Map> purgatory; - - /** - * The CacheEventQueue where changes will be queued for asynchronous updating of the persistent - * storage. - */ - private ICacheEventQueue cacheEventQueue; - - /** - * Indicates whether the cache is 'alive': initialized, but not yet disposed. Child classes must - * set this to true. - */ - private boolean alive = false; - - /** Every cache will have a name, subclasses must set this when they are initialized. */ - private String cacheName; - - /** DEBUG: Keeps a count of the number of purgatory hits for debug messages */ - private int purgHits = 0; - - /** - * We lock here, so that we cannot get an update after a remove all. an individual removal locks - * the item. - */ - private final ReentrantReadWriteLock removeAllLock = new ReentrantReadWriteLock(); - - // ----------------------------------------------------------- constructors - - /** - * Construct the abstract disk cache, create event queues and purgatory. Child classes should - * set the alive flag to true after they are initialized. - * - * @param attr - */ - protected AbstractDiskCache( IDiskCacheAttributes attr ) - { - this.diskCacheAttributes = attr; - this.cacheName = attr.getCacheName(); - - // create queue - CacheEventQueueFactory fact = new CacheEventQueueFactory(); - this.cacheEventQueue = fact.createCacheEventQueue( new MyCacheListener(), CacheInfo.listenerId, cacheName, - diskCacheAttributes.getEventQueuePoolName(), - diskCacheAttributes.getEventQueueType() ); - - // create purgatory - initPurgatory(); - } - - /** - * @return true if the cache is alive - */ - public boolean isAlive() - { - return alive; - } - - /** - * @param alive set the alive status - */ - public void setAlive(boolean alive) - { - this.alive = alive; - } - - /** - * Purgatory size of -1 means to use a HashMap with no size limit. Anything greater will use an - * LRU map of some sort. - * - * TODO Currently setting this to 0 will cause nothing to be put to disk, since it will assume - * that if an item is not in purgatory, then it must have been plucked. We should make 0 - * work, a way to not use purgatory. - */ - private void initPurgatory() - { - // we need this so we can stop the updates from happening after a - // removeall - removeAllLock.writeLock().lock(); - - try - { - synchronized (this) - { - if ( diskCacheAttributes.getMaxPurgatorySize() >= 0 ) - { - purgatory = new LRUMap>( diskCacheAttributes.getMaxPurgatorySize() ); - } - else - { - purgatory = new HashMap>(); - } - } - } - finally - { - removeAllLock.writeLock().unlock(); - } - } - - // ------------------------------------------------------- interface ICache - - /** - * Adds the provided element to the cache. Element will be added to purgatory, and then queued - * for later writing to the serialized storage mechanism. - * - * An update results in a put event being created. The put event will call the handlePut method - * defined here. The handlePut method calls the implemented doPut on the child. - * - * @param cacheElement - * @throws IOException - * @see org.apache.commons.jcs.engine.behavior.ICache#update - */ - @Override - public final void update( ICacheElement cacheElement ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "Putting element in purgatory, cacheName: " + cacheName + ", key: " + cacheElement.getKey() ); - } - - try - { - // Wrap the CacheElement in a PurgatoryElement - PurgatoryElement pe = new PurgatoryElement( cacheElement ); - - // Indicates the the element is eligible to be spooled to disk, - // this will remain true unless the item is pulled back into - // memory. - pe.setSpoolable( true ); - - // Add the element to purgatory - synchronized ( purgatory ) - { - purgatory.put( pe.getKey(), pe ); - } - - // Queue element for serialization - cacheEventQueue.addPutEvent( pe ); - } - catch ( IOException ex ) - { - log.error( "Problem adding put event to queue.", ex ); - - cacheEventQueue.destroy(); - } - } - - /** - * Check to see if the item is in purgatory. If so, return it. If not, check to see if we have - * it on disk. - * - * @param key - * @return ICacheElement<K, V> or null - * @see AuxiliaryCache#get - */ - @Override - public final ICacheElement get( K key ) - { - // If not alive, always return null. - - if ( !alive ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "get was called, but the disk cache is not alive." ); - } - return null; - } - - PurgatoryElement pe = null; - synchronized ( purgatory ) - { - pe = purgatory.get( key ); - } - - // If the element was found in purgatory - if ( pe != null ) - { - purgHits++; - - if ( log.isDebugEnabled() ) - { - if ( purgHits % 100 == 0 ) - { - log.debug( "Purgatory hits = " + purgHits ); - } - } - - // Since the element will go back to the memory cache, we could set - // spoolable to false, which will prevent the queue listener from - // serializing the element. This would not match the disk cache - // behavior and the behavior of other auxiliaries. Gets never remove - // items from auxiliaries. - // Beyond consistency, the items should stay in purgatory and get - // spooled since the mem cache may be set to 0. If an item is - // active, it will keep getting put into purgatory and removed. The - // CompositeCache now does not put an item to memory from disk if - // the size is 0. - // Do not set spoolable to false. Just let it go to disk. This - // will allow the memory size = 0 setting to work well. - - if ( log.isDebugEnabled() ) - { - log.debug( "Found element in purgatory, cacheName: " + cacheName + ", key: " + key ); - } - - return pe.getCacheElement(); - } - - // If we reach this point, element was not found in purgatory, so get - // it from the cache. - try - { - return doGet( key ); - } - catch ( Exception e ) - { - log.error( e ); - - cacheEventQueue.destroy(); - } - - return null; - } - - /** - * Gets items from the cache matching the given pattern. Items from memory will replace those - * from remote sources. - * - * This only works with string keys. It's too expensive to do a toString on every key. - * - * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk - * cache will convert * to % and . to _ - * - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data matching the pattern. - * @throws IOException - */ - @Override - public Map> getMatching( String pattern ) - throws IOException - { - // Get the keys from purgatory - Set keyArray = null; - - // this avoids locking purgatory, but it uses more memory - synchronized ( purgatory ) - { - keyArray = new HashSet(purgatory.keySet()); - } - - Set matchingKeys = getKeyMatcher().getMatchingKeysFromArray( pattern, keyArray ); - - // call getMultiple with the set - Map> result = processGetMultiple( matchingKeys ); - - // Get the keys from disk - Map> diskMatches = doGetMatching( pattern ); - - result.putAll( diskMatches ); - - return result; - } - - /** - * Gets multiple items from the cache based on the given set of keys. - * - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - */ - @Override - public Map> processGetMultiple(Set keys) - { - Map> elements = new HashMap>(); - - if ( keys != null && !keys.isEmpty() ) - { - for (K key : keys) - { - ICacheElement element = get( key ); - - if ( element != null ) - { - elements.put( key, element ); - } - } - } - - return elements; - } - - /** - * The keys in the cache. - * - * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public abstract Set getKeySet() throws IOException; - - /** - * Removes are not queued. A call to remove is immediate. - * - * @param key - * @return whether the item was present to be removed. - * @throws IOException - * @see org.apache.commons.jcs.engine.behavior.ICache#remove - */ - @Override - public final boolean remove( K key ) - throws IOException - { - PurgatoryElement pe = null; - - synchronized ( purgatory ) - { - // I'm getting the object, so I can lock on the element - // Remove element from purgatory if it is there - pe = purgatory.get( key ); - } - - if ( pe != null ) - { - synchronized ( pe.getCacheElement() ) - { - synchronized ( purgatory ) - { - purgatory.remove( key ); - } - - // no way to remove from queue, just make sure it doesn't get on - // disk and then removed right afterwards - pe.setSpoolable( false ); - - // Remove from persistent store immediately - doRemove( key ); - } - } - else - { - // Remove from persistent store immediately - doRemove( key ); - } - - return false; - } - - /** - * @throws IOException - * @see org.apache.commons.jcs.engine.behavior.ICache#removeAll - */ - @Override - public final void removeAll() - throws IOException - { - if ( this.diskCacheAttributes.isAllowRemoveAll() ) - { - // Replace purgatory with a new empty hashtable - initPurgatory(); - - // Remove all from persistent store immediately - doRemoveAll(); - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "RemoveAll was requested but the request was not fulfilled: allowRemoveAll is set to false." ); - } - } - } - - /** - * Adds a dispose request to the disk cache. - * - * Disposal proceeds in several steps. - *

    - *
  1. Prior to this call the Composite cache dumped the memory into the disk cache. If it is - * large then we need to wait for the event queue to finish.
  2. - *
  3. Wait until the event queue is empty of until the configured ShutdownSpoolTimeLimit is - * reached.
  4. - *
  5. Call doDispose on the concrete impl.
  6. - *
- * @throws IOException - */ - @Override - public final void dispose() - throws IOException - { - Runnable disR = new Runnable() - { - @Override - public void run() - { - boolean keepGoing = true; - // long total = 0; - long interval = 100; - while ( keepGoing ) - { - keepGoing = !cacheEventQueue.isEmpty(); - try - { - Thread.sleep( interval ); - // total += interval; - // log.info( "total = " + total ); - } - catch ( InterruptedException e ) - { - break; - } - } - log.info( "No longer waiting for event queue to finish: " + cacheEventQueue.getStatistics() ); - } - }; - Thread t = new Thread( disR ); - t.start(); - // wait up to 60 seconds for dispose and then quit if not done. - try - { - t.join( this.diskCacheAttributes.getShutdownSpoolTimeLimit() * 1000L ); - } - catch ( InterruptedException ex ) - { - log.error( "The Shutdown Spool Process was interrupted.", ex ); - } - - log.info( "In dispose, destroying event queue." ); - // This stops the processor thread. - cacheEventQueue.destroy(); - - // Invoke any implementation specific disposal code - // need to handle the disposal first. - doDispose(); - - alive = false; - } - - /** - * @return the region name. - * @see ICache#getCacheName - */ - @Override - public String getCacheName() - { - return cacheName; - } - - /** - * Gets basic stats for the abstract disk cache. - * - * @return String - */ - @Override - public String getStats() - { - return getStatistics().toString(); - } - - /** - * Returns semi-structured data. - * - * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getStatistics() - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Abstract Disk Cache" ); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "Purgatory Hits", Integer.valueOf(purgHits) ) ); - elems.add(new StatElement( "Purgatory Size", Integer.valueOf(purgatory.size()) ) ); - - // get the stats from the event queue too - IStats eqStats = this.cacheEventQueue.getStatistics(); - elems.addAll(eqStats.getStatElements()); - - stats.setStatElements( elems ); - - return stats; - } - - /** - * @return the status -- alive or disposed from CacheConstants - * @see ICache#getStatus - */ - @Override - public CacheStatus getStatus() - { - return ( alive ? CacheStatus.ALIVE : CacheStatus.DISPOSED ); - } - - /** - * Size cannot be determined without knowledge of the cache implementation, so subclasses will - * need to implement this method. - * - * @return the number of items. - * @see ICache#getSize - */ - @Override - public abstract int getSize(); - - /** - * @see org.apache.commons.jcs.engine.behavior.ICacheType#getCacheType - * @return Always returns DISK_CACHE since subclasses should all be of that type. - */ - @Override - public CacheType getCacheType() - { - return CacheType.DISK_CACHE; - } - - /** - * Cache that implements the CacheListener interface, and calls appropriate methods in its - * parent class. - */ - protected class MyCacheListener - implements ICacheListener - { - /** Id of the listener */ - private long listenerId = 0; - - /** - * @return cacheElement.getElementAttributes(); - * @throws IOException - * @see ICacheListener#getListenerId - */ - @Override - public long getListenerId() - throws IOException - { - return this.listenerId; - } - - /** - * @param id - * @throws IOException - * @see ICacheListener#setListenerId - */ - @Override - public void setListenerId( long id ) - throws IOException - { - this.listenerId = id; - } - - /** - * @param element - * @throws IOException - * @see ICacheListener#handlePut NOTE: This checks if the element is a puratory element and - * behaves differently depending. However since we have control over how elements are - * added to the cache event queue, that may not be needed ( they are always - * PurgatoryElements ). - */ - @Override - public void handlePut( ICacheElement element ) - throws IOException - { - if ( alive ) - { - // If the element is a PurgatoryElement we must check to see - // if it is still spoolable, and remove it from purgatory. - if ( element instanceof PurgatoryElement ) - { - PurgatoryElement pe = (PurgatoryElement) element; - - synchronized ( pe.getCacheElement() ) - { - // TODO consider a timeout. - // we need this so that we can have multiple update - // threads and still have removeAll requests come in that - // always win - removeAllLock.readLock().lock(); - - try - { - // TODO consider changing purgatory sync - // String keyAsString = element.getKey().toString(); - synchronized ( purgatory ) - { - // If the element has already been removed from - // purgatory do nothing - if ( !purgatory.containsKey( pe.getKey() ) ) - { - return; - } - - element = pe.getCacheElement(); - } - - // I took this out of the purgatory sync block. - // If the element is still eligible, spool it. - if ( pe.isSpoolable() ) - { - doUpdate( element ); - } - } - finally - { - removeAllLock.readLock().unlock(); - } - - synchronized ( purgatory ) - { - // After the update has completed, it is safe to - // remove the element from purgatory. - purgatory.remove( element.getKey() ); - } - } - } - else - { - // call the child's implementation - doUpdate( element ); - } - } - else - { - /* - * The cache is not alive, hence the element should be removed from purgatory. All - * elements should be removed eventually. Perhaps, the alive check should have been - * done before it went in the queue. This block handles the case where the disk - * cache fails during normal operations. - */ - synchronized ( purgatory ) - { - purgatory.remove( element.getKey() ); - } - } - } - - /** - * @param cacheName - * @param key - * @throws IOException - * @see ICacheListener#handleRemove - */ - @Override - public void handleRemove( String cacheName, K key ) - throws IOException - { - if ( alive ) - { - if ( doRemove( key ) ) - { - log.debug( "Element removed, key: " + key ); - } - } - } - - /** - * @param cacheName - * @throws IOException - * @see ICacheListener#handleRemoveAll - */ - @Override - public void handleRemoveAll( String cacheName ) - throws IOException - { - if ( alive ) - { - doRemoveAll(); - } - } - - /** - * @param cacheName - * @throws IOException - * @see ICacheListener#handleDispose - */ - @Override - public void handleDispose( String cacheName ) - throws IOException - { - if ( alive ) - { - doDispose(); - } - } - } - - /** - * Before the event logging layer, the subclasses implemented the do* methods. Now the do* - * methods call the *WithEventLogging method on the super. The *WithEventLogging methods call - * the abstract process* methods. The children implement the process methods. - * - * ex. doGet calls getWithEventLogging, which calls processGet - */ - - /** - * Get a value from the persistent store. - * - * Before the event logging layer, the subclasses implemented the do* methods. Now the do* - * methods call the *EventLogging method on the super. The *WithEventLogging methods call the - * abstract process* methods. The children implement the process methods. - * - * @param key Key to locate value for. - * @return An object matching key, or null. - * @throws IOException - */ - protected final ICacheElement doGet( K key ) - throws IOException - { - return super.getWithEventLogging( key ); - } - - /** - * Get a value from the persistent store. - * - * Before the event logging layer, the subclasses implemented the do* methods. Now the do* - * methods call the *EventLogging method on the super. The *WithEventLogging methods call the - * abstract process* methods. The children implement the process methods. - * - * @param pattern Used to match keys. - * @return A map of matches.. - * @throws IOException - */ - protected final Map> doGetMatching( String pattern ) - throws IOException - { - return super.getMatchingWithEventLogging( pattern ); - } - - /** - * Add a cache element to the persistent store. - * - * Before the event logging layer, the subclasses implemented the do* methods. Now the do* - * methods call the *EventLogging method on the super. The *WithEventLogging methods call the - * abstract process* methods. The children implement the process methods. - * - * @param cacheElement - * @throws IOException - */ - protected final void doUpdate( ICacheElement cacheElement ) - throws IOException - { - super.updateWithEventLogging( cacheElement ); - } - - /** - * Remove an object from the persistent store if found. - * - * Before the event logging layer, the subclasses implemented the do* methods. Now the do* - * methods call the *EventLogging method on the super. The *WithEventLogging methods call the - * abstract process* methods. The children implement the process methods. - * - * @param key Key of object to remove. - * @return whether or no the item was present when removed - * @throws IOException - */ - protected final boolean doRemove( K key ) - throws IOException - { - return super.removeWithEventLogging( key ); - } - - /** - * Remove all objects from the persistent store. - * - * Before the event logging layer, the subclasses implemented the do* methods. Now the do* - * methods call the *EventLogging method on the super. The *WithEventLogging methods call the - * abstract process* methods. The children implement the process methods. - * - * @throws IOException - */ - protected final void doRemoveAll() - throws IOException - { - super.removeAllWithEventLogging(); - } - - /** - * Dispose of the persistent store. Note that disposal of purgatory and setting alive to false - * does NOT need to be done by this method. - * - * Before the event logging layer, the subclasses implemented the do* methods. Now the do* - * methods call the *EventLogging method on the super. The *WithEventLogging methods call the - * abstract process* methods. The children implement the process methods. - * - * @throws IOException - */ - protected final void doDispose() - throws IOException - { - super.disposeWithEventLogging(); - } - - /** - * Gets the extra info for the event log. - * - * @return disk location - */ - @Override - public String getEventLoggingExtraInfo() - { - return getDiskLocation(); - } - - /** - * This is used by the event logging. - * - * @return the location of the disk, either path or ip. - */ - protected abstract String getDiskLocation(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java deleted file mode 100644 index 7d5ca707ce6..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java +++ /dev/null @@ -1,221 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.File; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This has common attributes that any conceivable disk cache would need. - */ -public abstract class AbstractDiskCacheAttributes extends AbstractAuxiliaryCacheAttributes implements IDiskCacheAttributes -{ - /** Don't change. */ - private static final long serialVersionUID = 8306631920391711229L; - - /** The logger */ - private static final Log log = LogFactory.getLog(AbstractDiskCacheAttributes.class); - - /** path to disk */ - private File diskPath; - - /** if this is false, we will not execute remove all */ - private boolean allowRemoveAll = true; - - /** default to 5000 */ - private int maxPurgatorySize = MAX_PURGATORY_SIZE_DEFAULT; - - /** Default amount of time to allow for key persistence on shutdown */ - private static final int DEFAULT_shutdownSpoolTimeLimit = 60; - - /** - * This default determines how long the shutdown will wait for the key spool and data defrag to - * finish. - */ - private int shutdownSpoolTimeLimit = DEFAULT_shutdownSpoolTimeLimit; - - /** Type of disk limit: SIZE or COUNT */ - private DiskLimitType diskLimitType = DiskLimitType.COUNT; - - /** - * Sets the diskPath attribute of the DiskCacheAttributes object - *

- * - * @param path - * The new diskPath value - */ - @Override - public void setDiskPath(String path) - { - setDiskPath(new File(path)); - } - - /** - * Sets the diskPath attribute of the DiskCacheAttributes object - *

- * - * @param diskPath - * The new diskPath value - */ - public void setDiskPath(File diskPath) - { - this.diskPath = diskPath; - boolean result = this.diskPath.isDirectory(); - - if (!result) - { - result = this.diskPath.mkdirs(); - } - if (!result) - { - log.error("Failed to create directory " + diskPath); - } - } - - /** - * Gets the diskPath attribute of the attributes object - *

- * - * @return The diskPath value - */ - @Override - public File getDiskPath() - { - return this.diskPath; - } - - /** - * Gets the maxKeySize attribute of the DiskCacheAttributes object - *

- * - * @return The maxPurgatorySize value - */ - @Override - public int getMaxPurgatorySize() - { - return maxPurgatorySize; - } - - /** - * Sets the maxPurgatorySize attribute of the DiskCacheAttributes object - *

- * - * @param maxPurgatorySize - * The new maxPurgatorySize value - */ - @Override - public void setMaxPurgatorySize(int maxPurgatorySize) - { - this.maxPurgatorySize = maxPurgatorySize; - } - - /** - * Get the amount of time in seconds we will wait for elements to move to disk during shutdown - * for a particular region. - *

- * - * @return the time in seconds. - */ - @Override - public int getShutdownSpoolTimeLimit() - { - return this.shutdownSpoolTimeLimit; - } - - /** - * Sets the amount of time in seconds we will wait for elements to move to disk during shutdown - * for a particular region. - *

- * This is how long we give the event queue to empty. - *

- * The default is 60 seconds. - *

- * - * @param shutdownSpoolTimeLimit - * the time in seconds - */ - @Override - public void setShutdownSpoolTimeLimit(int shutdownSpoolTimeLimit) - { - this.shutdownSpoolTimeLimit = shutdownSpoolTimeLimit; - } - - /** - * @param allowRemoveAll - * The allowRemoveAll to set. - */ - @Override - public void setAllowRemoveAll(boolean allowRemoveAll) - { - this.allowRemoveAll = allowRemoveAll; - } - - /** - * @return Returns the allowRemoveAll. - */ - @Override - public boolean isAllowRemoveAll() - { - return allowRemoveAll; - } - - /** - * Includes the common attributes for a debug message. - *

- * - * @return String - */ - @Override - public String toString() - { - StringBuilder str = new StringBuilder(); - str.append("AbstractDiskCacheAttributes "); - str.append("\n diskPath = " + getDiskPath()); - str.append("\n maxPurgatorySize = " + getMaxPurgatorySize()); - str.append("\n allowRemoveAll = " + isAllowRemoveAll()); - str.append("\n ShutdownSpoolTimeLimit = " + getShutdownSpoolTimeLimit()); - return str.toString(); - } - - @Override - public void setDiskLimitType(DiskLimitType diskLimitType) - { - this.diskLimitType = diskLimitType; - } - - @Override - public void setDiskLimitTypeName(String diskLimitTypeName) - { - if (diskLimitTypeName != null) - { - diskLimitType = DiskLimitType.valueOf(diskLimitTypeName.trim()); - } - } - - @Override - public DiskLimitType getDiskLimitType() - { - return diskLimitType; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/PurgatoryElement.java b/src/org/apache/commons/jcs/auxiliary/disk/PurgatoryElement.java deleted file mode 100644 index db257bd13a5..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/PurgatoryElement.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.CacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; - -/** - * Implementation of cache elements in purgatory. - * - * Elements are stored in purgatory when they are spooled to the auxiliary cache, but have not yet - * been written to disk. - */ -public class PurgatoryElement - extends CacheElement -{ - /** Don't change */ - private static final long serialVersionUID = -8152034342684135628L; - - /** Is the element ready to be spooled? */ - private boolean spoolable = false; - - /** Wrapped cache Element */ - private ICacheElement cacheElement; - - /** - * Constructor for the PurgatoryElement<K, V> object - * - * @param cacheElement CacheElement - */ - public PurgatoryElement( ICacheElement cacheElement ) - { - super(cacheElement.getCacheName(), - cacheElement.getKey(), cacheElement.getVal(), - cacheElement.getElementAttributes()); - this.cacheElement = cacheElement; - } - - /** - * Gets the spoolable property. - * - * @return The spoolable value - */ - public boolean isSpoolable() - { - return spoolable; - } - - /** - * Sets the spoolable property. - * - * @param spoolable The new spoolable value - */ - public void setSpoolable( boolean spoolable ) - { - this.spoolable = spoolable; - } - - /** - * Get the wrapped cache element. - * - * @return ICacheElement - */ - public ICacheElement getCacheElement() - { - return cacheElement; - } - - // ------------------------------------------------ interface ICacheElement - - /** - * @return cacheElement.getCacheName(); - * @see ICacheElement#getCacheName - */ - @Override - public String getCacheName() - { - return cacheElement.getCacheName(); - } - - /** - * @return cacheElement.getKey(); - * @see ICacheElement#getKey - */ - @Override - public K getKey() - { - return cacheElement.getKey(); - } - - /** - * @return cacheElement.getVal(); - * @see ICacheElement#getVal - */ - @Override - public V getVal() - { - return cacheElement.getVal(); - } - - /** - * @return cacheElement.getElementAttributes(); - * @see ICacheElement#getElementAttributes - */ - @Override - public IElementAttributes getElementAttributes() - { - return cacheElement.getElementAttributes(); - } - - /** - * @param attr - * @see ICacheElement#setElementAttributes - */ - @Override - public void setElementAttributes( IElementAttributes attr ) - { - cacheElement.setElementAttributes( attr ); - } - - /** - * @return debug string - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "[PurgatoryElement: " ); - buf.append( " isSpoolable = " + isSpoolable() ); - buf.append( " CacheElement = " + getCacheElement() ); - buf.append( " CacheName = " + getCacheName() ); - buf.append( " Key = " + getKey() ); - buf.append( " Value = " + getVal() ); - buf.append( " ElementAttributes = " + getElementAttributes() ); - buf.append( "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java deleted file mode 100644 index f7d32fdc292..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; - -import java.io.File; - -/** - * Common disk cache attributes. - */ -public interface IDiskCacheAttributes - extends AuxiliaryCacheAttributes -{ - enum DiskLimitType { - /** limit elements by count (default) */ - COUNT, - /** limit elements by their size */ - SIZE - } - /** - * This is the default purgatory size limit. Purgatory is the area where - * items to be spooled are temporarily stored. It basically provides access - * to items on the to-be-spooled queue. - */ - int MAX_PURGATORY_SIZE_DEFAULT = 5000; - - /** - * Sets the diskPath attribute of the IJISPCacheAttributes object - *

- * @param path - * The new diskPath value - */ - void setDiskPath( String path ); - - /** - * Gets the diskPath attribute of the attributes object - *

- * @return The diskPath value - */ - File getDiskPath(); - - /** - * Gets the maxKeySize attribute of the DiskCacheAttributes object - *

- * @return The maxPurgatorySize value - */ - int getMaxPurgatorySize(); - - /** - * Sets the maxPurgatorySize attribute of the DiskCacheAttributes object - *

- * @param maxPurgatorySize - * The new maxPurgatorySize value - */ - void setMaxPurgatorySize( int maxPurgatorySize ); - - /** - * Get the amount of time in seconds we will wait for elements to move to - * disk during shutdown for a particular region. - *

- * @return the time in seconds. - */ - int getShutdownSpoolTimeLimit(); - - /** - * Sets the amount of time in seconds we will wait for elements to move to - * disk during shutdown for a particular region. - *

- * This is how long we give the event queue to empty. - *

- * The default is 60 seconds. - *

- * @param shutdownSpoolTimeLimit - * the time in seconds - */ - void setShutdownSpoolTimeLimit( int shutdownSpoolTimeLimit ); - - /** - * If this is true then remove all is not prohibited. - *

- * @return boolean - */ - boolean isAllowRemoveAll(); - - /** - * If this is false, then remove all requests will not be honored. - *

- * This provides a safety mechanism for the persistent store. - *

- * @param allowRemoveAll - */ - void setAllowRemoveAll( boolean allowRemoveAll ); - - /** - * set the type of the limit of the cache size - * @param diskLimitType COUNT - limit by count of the elements, SIZE, limit by sum of element's size - */ - void setDiskLimitType(DiskLimitType diskLimitType); - - /** - * Translates and stores String values of DiskLimitType - * - * Allowed values: "COUNT" and "SIZE" - * @param diskLimitTypeName - */ - void setDiskLimitTypeName(String diskLimitTypeName); - - /** - * - * @return active DiskLimitType - */ - DiskLimitType getDiskLimitType(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDisk.java b/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDisk.java deleted file mode 100644 index 8d3e0465e12..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDisk.java +++ /dev/null @@ -1,525 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.block; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.io.Serializable; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.utils.serialization.StandardSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class manages reading an writing data to disk. When asked to write a value, it returns a - * block array. It can read an object from the block numbers in a byte array. - *

- * @author Aaron Smuts - */ -public class BlockDisk -{ - /** The logger */ - private static final Log log = LogFactory.getLog( BlockDisk.class ); - - /** The size of the header that indicates the amount of data stored in an occupied block. */ - public static final byte HEADER_SIZE_BYTES = 4; - // N.B. 4 bytes is the size used for ByteBuffer.putInt(int value) and ByteBuffer.getInt() - - /** defaults to 4kb */ - private static final int DEFAULT_BLOCK_SIZE_BYTES = 4 * 1024; - - /** Size of the blocks */ - private final int blockSizeBytes; - - /** - * the total number of blocks that have been used. If there are no free, we will use this to - * calculate the position of the next block. - */ - private final AtomicInteger numberOfBlocks = new AtomicInteger(0); - - /** Empty blocks that can be reused. */ - private final ConcurrentLinkedQueue emptyBlocks = new ConcurrentLinkedQueue(); - - /** The serializer. */ - private final IElementSerializer elementSerializer; - - /** Location of the spot on disk */ - private final String filepath; - - /** File channel for multiple concurrent reads and writes */ - private final FileChannel fc; - - /** How many bytes have we put to disk */ - private final AtomicLong putBytes = new AtomicLong(0); - - /** How many items have we put to disk */ - private final AtomicLong putCount = new AtomicLong(0); - - /** - * Constructor for the Disk object - *

- * @param file - * @param elementSerializer - * @throws IOException - */ - public BlockDisk( File file, IElementSerializer elementSerializer ) - throws IOException - { - this( file, DEFAULT_BLOCK_SIZE_BYTES, elementSerializer ); - } - - /** - * Creates the file and set the block size in bytes. - *

- * @param file - * @param blockSizeBytes - * @throws IOException - */ - public BlockDisk( File file, int blockSizeBytes ) - throws IOException - { - this( file, blockSizeBytes, new StandardSerializer() ); - } - - /** - * Creates the file and set the block size in bytes. - *

- * @param file - * @param blockSizeBytes - * @param elementSerializer - * @throws IOException - */ - public BlockDisk( File file, int blockSizeBytes, IElementSerializer elementSerializer ) - throws IOException - { - this.filepath = file.getAbsolutePath(); - RandomAccessFile raf = new RandomAccessFile( filepath, "rw" ); - this.fc = raf.getChannel(); - this.numberOfBlocks.set((int) Math.ceil(1f * this.fc.size() / blockSizeBytes)); - - if ( log.isInfoEnabled() ) - { - log.info( "Constructing BlockDisk, blockSizeBytes [" + blockSizeBytes + "]" ); - } - - this.blockSizeBytes = blockSizeBytes; - this.elementSerializer = elementSerializer; - } - - /** - * Allocate a given number of blocks from the available set - * - * @param numBlocksNeeded - * @return an array of allocated blocks - */ - private int[] allocateBlocks(int numBlocksNeeded) - { - assert numBlocksNeeded >= 1; - - int[] blocks = new int[numBlocksNeeded]; - // get them from the empty list or take the next one - for (int i = 0; i < numBlocksNeeded; i++) - { - Integer emptyBlock = emptyBlocks.poll(); - if (emptyBlock == null) - { - emptyBlock = Integer.valueOf(numberOfBlocks.getAndIncrement()); - } - blocks[i] = emptyBlock.intValue(); - } - - return blocks; - } - - /** - * This writes an object to disk and returns the blocks it was stored in. - *

- * The program flow is as follows: - *

    - *
  1. Serialize the object.
  2. - *
  3. Determine the number of blocks needed.
  4. - *
  5. Look for free blocks in the emptyBlock list.
  6. - *
  7. If there were not enough in the empty list. Take the nextBlock and increment it.
  8. - *
  9. If the data will not fit in one block, create sub arrays.
  10. - *
  11. Write the subarrays to disk.
  12. - *
  13. If the process fails we should decrement the block count if we took from it.
  14. - *
- * @param object - * @return the blocks we used. - * @throws IOException - */ - protected int[] write( Serializable object ) - throws IOException - { - // serialize the object - byte[] data = elementSerializer.serialize(object); - - if ( log.isDebugEnabled() ) - { - log.debug( "write, total pre-chunking data.length = " + data.length ); - } - - this.putBytes.addAndGet(data.length); - this.putCount.incrementAndGet(); - - // figure out how many blocks we need. - int numBlocksNeeded = calculateTheNumberOfBlocksNeeded(data); - - if ( log.isDebugEnabled() ) - { - log.debug( "numBlocksNeeded = " + numBlocksNeeded ); - } - - // allocate blocks - int[] blocks = allocateBlocks(numBlocksNeeded); - - int offset = 0; - final int maxChunkSize = blockSizeBytes - HEADER_SIZE_BYTES; - ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_SIZE_BYTES); - - for (int i = 0; i < numBlocksNeeded; i++) - { - headerBuffer.clear(); - int length = Math.min(maxChunkSize, data.length - offset); - headerBuffer.putInt(length); - - ByteBuffer dataBuffer = ByteBuffer.wrap(data, offset, length); - - long position = calculateByteOffsetForBlockAsLong(blocks[i]); - // write the header - headerBuffer.flip(); - int written = fc.write(headerBuffer, position); - assert written == HEADER_SIZE_BYTES; - - //write the data - written = fc.write(dataBuffer, position + HEADER_SIZE_BYTES); - assert written == length; - - offset += length; - } - - //fc.force(false); - - return blocks; - } - - /** - * Return the amount to put in each block. Fill them all the way, minus the header. - *

- * @param complete - * @param numBlocksNeeded - * @return byte[][] - */ - protected byte[][] getBlockChunks( byte[] complete, int numBlocksNeeded ) - { - byte[][] chunks = new byte[numBlocksNeeded][]; - - if ( numBlocksNeeded == 1 ) - { - chunks[0] = complete; - } - else - { - int maxChunkSize = this.blockSizeBytes - HEADER_SIZE_BYTES; - int totalBytes = complete.length; - int totalUsed = 0; - for ( short i = 0; i < numBlocksNeeded; i++ ) - { - // use the max that can be written to a block or whatever is left in the original - // array - int chunkSize = Math.min( maxChunkSize, totalBytes - totalUsed ); - byte[] chunk = new byte[chunkSize]; - // copy from the used position to the chunk size on the complete array to the chunk - // array. - System.arraycopy( complete, totalUsed, chunk, 0, chunkSize ); - chunks[i] = chunk; - totalUsed += chunkSize; - } - } - - return chunks; - } - - /** - * Reads an object that is located in the specified blocks. - *

- * @param blockNumbers - * @return Serializable - * @throws IOException - * @throws ClassNotFoundException - */ - protected T read( int[] blockNumbers ) - throws IOException, ClassNotFoundException - { - byte[] data = null; - - if ( blockNumbers.length == 1 ) - { - data = readBlock( blockNumbers[0] ); - } - else - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(getBlockSizeBytes()); - // get all the blocks into data - for ( short i = 0; i < blockNumbers.length; i++ ) - { - byte[] chunk = readBlock( blockNumbers[i] ); - baos.write(chunk); - } - - data = baos.toByteArray(); - baos.close(); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "read, total post combination data.length = " + data.length ); - } - - return elementSerializer.deSerialize( data, null ); - } - - /** - * This reads the occupied data in a block. - *

- * The first four bytes of the record should tell us how long it is. The data is read into a - * byte array and then an object is constructed from the byte array. - *

- * @return byte[] - * @param block - * @throws IOException - */ - private byte[] readBlock( int block ) - throws IOException - { - int datalen = 0; - - String message = null; - boolean corrupted = false; - long fileLength = fc.size(); - - long position = calculateByteOffsetForBlockAsLong( block ); -// if ( position > fileLength ) -// { -// corrupted = true; -// message = "Record " + position + " starts past EOF."; -// } -// else - { - ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES); - fc.read(datalength, position); - datalength.flip(); - datalen = datalength.getInt(); - if ( position + datalen > fileLength ) - { - corrupted = true; - message = "Record " + position + " exceeds file length."; - } - } - - if ( corrupted ) - { - log.warn( "\n The file is corrupt: " + "\n " + message ); - throw new IOException( "The File Is Corrupt, need to reset" ); - } - - ByteBuffer data = ByteBuffer.allocate(datalen); - fc.read(data, position + HEADER_SIZE_BYTES); - data.flip(); - - return data.array(); - } - - /** - * Add these blocks to the emptyBlock list. - *

- * @param blocksToFree - */ - protected void freeBlocks( int[] blocksToFree ) - { - if ( blocksToFree != null ) - { - for ( short i = 0; i < blocksToFree.length; i++ ) - { - emptyBlocks.offer( Integer.valueOf( blocksToFree[i] ) ); - } - } - } - - /** - * Calculates the file offset for a particular block. - *

- * @param block number - * @return the byte offset for this block in the file as a long - * @since 2.0 - */ - protected long calculateByteOffsetForBlockAsLong( int block ) - { - return (long) block * blockSizeBytes; - } - - /** - * The number of blocks needed. - *

- * @param data - * @return the number of blocks needed to store the byte array - */ - protected int calculateTheNumberOfBlocksNeeded( byte[] data ) - { - int dataLength = data.length; - - int oneBlock = blockSizeBytes - HEADER_SIZE_BYTES; - - // takes care of 0 = HEADER_SIZE_BYTES + blockSizeBytes - if ( dataLength <= oneBlock ) - { - return 1; - } - - int dividend = dataLength / oneBlock; - - if ( dataLength % oneBlock != 0 ) - { - dividend++; - } - return dividend; - } - - /** - * Returns the file length. - *

- * @return the size of the file. - * @throws IOException - */ - protected long length() - throws IOException - { - return fc.size(); - } - - /** - * Closes the file. - *

- * @throws IOException - */ - protected void close() - throws IOException - { - fc.close(); - } - - /** - * Resets the file. - *

- * @throws IOException - */ - protected synchronized void reset() - throws IOException - { - this.numberOfBlocks.set(0); - this.emptyBlocks.clear(); - fc.truncate(0); - fc.force(true); - } - - /** - * @return Returns the numberOfBlocks. - */ - protected int getNumberOfBlocks() - { - return numberOfBlocks.get(); - } - - /** - * @return Returns the blockSizeBytes. - */ - protected int getBlockSizeBytes() - { - return blockSizeBytes; - } - - /** - * @return Returns the average size of the an element inserted. - */ - protected long getAveragePutSizeBytes() - { - long count = this.putCount.get(); - - if (count == 0 ) - { - return 0; - } - return this.putBytes.get() / count; - } - - /** - * @return Returns the number of empty blocks. - */ - protected int getEmptyBlocks() - { - return this.emptyBlocks.size(); - } - - /** - * For debugging only. - *

- * @return String with details. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nBlock Disk " ); - buf.append( "\n Filepath [" + filepath + "]" ); - buf.append( "\n NumberOfBlocks [" + this.numberOfBlocks.get() + "]" ); - buf.append( "\n BlockSizeBytes [" + this.blockSizeBytes + "]" ); - buf.append( "\n Put Bytes [" + this.putBytes + "]" ); - buf.append( "\n Put Count [" + this.putCount + "]" ); - buf.append( "\n Average Size [" + getAveragePutSizeBytes() + "]" ); - buf.append( "\n Empty Blocks [" + this.getEmptyBlocks() + "]" ); - try - { - buf.append( "\n Length [" + length() + "]" ); - } - catch ( IOException e ) - { - // swallow - } - return buf.toString(); - } - - /** - * This is used for debugging. - *

- * @return the file path. - */ - protected String getFilePath() - { - return filepath; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java b/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java deleted file mode 100644 index 707571b0a02..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java +++ /dev/null @@ -1,791 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.block; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache; -import org.apache.commons.jcs.engine.CacheConstants; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.behavior.IRequireScheduler; -import org.apache.commons.jcs.engine.control.group.GroupAttrName; -import org.apache.commons.jcs.engine.control.group.GroupId; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * There is one BlockDiskCache per region. It manages the key and data store. - *

- * @author Aaron Smuts - */ -public class BlockDiskCache - extends AbstractDiskCache - implements IRequireScheduler -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( BlockDiskCache.class ); - - /** The name to prefix all log messages with. */ - private final String logCacheName; - - /** The name of the file to store data. */ - private final String fileName; - - /** The data access object */ - private BlockDisk dataFile; - - /** Attributes governing the behavior of the block disk cache. */ - private final BlockDiskCacheAttributes blockDiskCacheAttributes; - - /** The root directory for keys and data. */ - private final File rootDirectory; - - /** Store, loads, and persists the keys */ - private BlockDiskKeyStore keyStore; - - /** - * Use this lock to synchronize reads and writes to the underlying storage mechanism. We don't - * need a reentrant lock, since we only lock one level. - */ - private final ReentrantReadWriteLock storageLock = new ReentrantReadWriteLock(); - - private ScheduledFuture future; - - /** - * Constructs the BlockDisk after setting up the root directory. - *

- * @param cacheAttributes - */ - public BlockDiskCache( BlockDiskCacheAttributes cacheAttributes ) - { - this( cacheAttributes, null ); - } - - /** - * Constructs the BlockDisk after setting up the root directory. - *

- * @param cacheAttributes - * @param elementSerializer used if supplied, the super's super will not set a null - */ - public BlockDiskCache( BlockDiskCacheAttributes cacheAttributes, IElementSerializer elementSerializer ) - { - super( cacheAttributes ); - setElementSerializer( elementSerializer ); - - this.blockDiskCacheAttributes = cacheAttributes; - this.logCacheName = "Region [" + getCacheName() + "] "; - - if ( log.isInfoEnabled() ) - { - log.info( logCacheName + "Constructing BlockDiskCache with attributes " + cacheAttributes ); - } - - // Make a clean file name - this.fileName = getCacheName().replaceAll("[^a-zA-Z0-9-_\\.]", "_"); - this.rootDirectory = cacheAttributes.getDiskPath(); - - if ( log.isInfoEnabled() ) - { - log.info( logCacheName + "Cache file root directory: [" + rootDirectory + "]"); - } - - try - { - if ( this.blockDiskCacheAttributes.getBlockSizeBytes() > 0 ) - { - this.dataFile = new BlockDisk( new File( rootDirectory, fileName + ".data" ), - this.blockDiskCacheAttributes.getBlockSizeBytes(), - getElementSerializer() ); - } - else - { - this.dataFile = new BlockDisk( new File( rootDirectory, fileName + ".data" ), - getElementSerializer() ); - } - - keyStore = new BlockDiskKeyStore( this.blockDiskCacheAttributes, this ); - - boolean alright = verifyDisk(); - - if ( keyStore.size() == 0 || !alright ) - { - this.reset(); - } - - // Initialization finished successfully, so set alive to true. - setAlive(true); - if ( log.isInfoEnabled() ) - { - log.info( logCacheName + "Block Disk Cache is alive." ); - } - } - catch ( IOException e ) - { - log.error( logCacheName + "Failure initializing for fileName: " + fileName + " and root directory: " - + rootDirectory, e ); - } - } - - /** - * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) - */ - @Override - public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor) - { - // add this region to the persistence thread. - // TODO we might need to stagger this a bit. - if ( this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds() > 0 ) - { - future = scheduledExecutor.scheduleAtFixedRate( - new Runnable() - { - @Override - public void run() - { - keyStore.saveKeys(); - } - }, - this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds(), - this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds(), - TimeUnit.SECONDS); - } - } - - /** - * We need to verify that the file on disk uses the same block size and that the file is the - * proper size. - *

- * @return true if it looks ok - */ - protected boolean verifyDisk() - { - boolean alright = false; - // simply try to read a few. If it works, then the file is probably ok. - // TODO add more. - - storageLock.readLock().lock(); - - try - { - int maxToTest = 100; - int count = 0; - Iterator> it = this.keyStore.entrySet().iterator(); - while ( it.hasNext() && count < maxToTest ) - { - count++; - Map.Entry entry = it.next(); - Object data = this.dataFile.read( entry.getValue() ); - if ( data == null ) - { - throw new Exception( logCacheName + "Couldn't find data for key [" + entry.getKey() + "]" ); - } - } - alright = true; - } - catch ( Exception e ) - { - log.warn( logCacheName + "Problem verifying disk. Message [" + e.getMessage() + "]" ); - alright = false; - } - finally - { - storageLock.readLock().unlock(); - } - - return alright; - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - HashSet keys = new HashSet(); - - storageLock.readLock().lock(); - - try - { - keys.addAll(this.keyStore.keySet()); - } - finally - { - storageLock.readLock().unlock(); - } - - return keys; - } - - /** - * Gets matching items from the cache. - *

- * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching keys - */ - @Override - public Map> processGetMatching( String pattern ) - { - Map> elements = new HashMap>(); - - Set keyArray = null; - storageLock.readLock().lock(); - try - { - keyArray = new HashSet(keyStore.keySet()); - } - finally - { - storageLock.readLock().unlock(); - } - - Set matchingKeys = getKeyMatcher().getMatchingKeysFromArray( pattern, keyArray ); - - for (K key : matchingKeys) - { - ICacheElement element = processGet( key ); - if ( element != null ) - { - elements.put( key, element ); - } - } - - return elements; - } - - /** - * Returns the number of keys. - *

- * (non-Javadoc) - * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getSize() - */ - @Override - public int getSize() - { - return this.keyStore.size(); - } - - /** - * Gets the ICacheElement<K, V> for the key if it is in the cache. The program flow is as follows: - *

    - *
  1. Make sure the disk cache is alive.
  2. Get a read lock.
  3. See if the key is - * in the key store.
  4. If we found a key, ask the BlockDisk for the object at the - * blocks..
  5. Release the lock.
  6. - *
- * @param key - * @return ICacheElement - * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#get(Object) - */ - @Override - protected ICacheElement processGet( K key ) - { - if ( !isAlive() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "No longer alive so returning null for key = " + key ); - } - return null; - } - - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "Trying to get from disk: " + key ); - } - - ICacheElement object = null; - - - try - { - storageLock.readLock().lock(); - try { - int[] ded = this.keyStore.get( key ); - if ( ded != null ) - { - object = this.dataFile.read( ded ); - } - } finally { - storageLock.readLock().unlock(); - } - - } - catch ( IOException ioe ) - { - log.error( logCacheName + "Failure getting from disk--IOException, key = " + key, ioe ); - reset(); - } - catch ( Exception e ) - { - log.error( logCacheName + "Failure getting from disk, key = " + key, e ); - } - return object; - } - - /** - * Writes an element to disk. The program flow is as follows: - *
    - *
  1. Acquire write lock.
  2. See id an item exists for this key.
  3. If an item - * already exists, add its blocks to the remove list.
  4. Have the Block disk write the - * item.
  5. Create a descriptor and add it to the key map.
  6. Release the write - * lock.
  7. - *
- * @param element - * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#update(ICacheElement) - */ - @Override - protected void processUpdate( ICacheElement element ) - { - if ( !isAlive() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "No longer alive; aborting put of key = " + element.getKey() ); - } - return; - } - - int[] old = null; - - // make sure this only locks for one particular cache region - storageLock.writeLock().lock(); - - try - { - old = this.keyStore.get( element.getKey() ); - - if ( old != null ) - { - this.dataFile.freeBlocks( old ); - } - - int[] blocks = this.dataFile.write( element ); - - this.keyStore.put( element.getKey(), blocks ); - - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "Put to file [" + fileName + "] key [" + element.getKey() + "]" ); - } - } - catch ( IOException e ) - { - log.error( logCacheName + "Failure updating element, key: " + element.getKey() + " old: " + Arrays.toString(old), e ); - } - finally - { - storageLock.writeLock().unlock(); - } - - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "Storing element on disk, key: " + element.getKey() ); - } - } - - /** - * Returns true if the removal was successful; or false if there is nothing to remove. Current - * implementation always result in a disk orphan. - *

- * @param key - * @return true if removed anything - * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#remove(Object) - */ - @Override - protected boolean processRemove( K key ) - { - if ( !isAlive() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "No longer alive so returning false for key = " + key ); - } - return false; - } - - boolean reset = false; - boolean removed = false; - - storageLock.writeLock().lock(); - - try - { - if (key instanceof String && key.toString().endsWith(CacheConstants.NAME_COMPONENT_DELIMITER)) - { - removed = performPartialKeyRemoval((String) key); - } - else if (key instanceof GroupAttrName && ((GroupAttrName) key).attrName == null) - { - removed = performGroupRemoval(((GroupAttrName) key).groupId); - } - else - { - removed = performSingleKeyRemoval(key); - } - } - catch ( Exception e ) - { - log.error( logCacheName + "Problem removing element.", e ); - reset = true; - } - finally - { - storageLock.writeLock().unlock(); - } - - if ( reset ) - { - reset(); - } - - return removed; - } - - /** - * Remove all elements from the group. This does not use the iterator to remove. It builds a - * list of group elements and then removes them one by one. - *

- * This operates under a lock obtained in doRemove(). - *

- * - * @param key - * @return true if an element was removed - */ - private boolean performGroupRemoval(GroupId key) - { - boolean removed = false; - - // remove all keys of the same name group. - List itemsToRemove = new LinkedList(); - - // remove all keys of the same name hierarchy. - for (K k : keyStore.keySet()) - { - if (k instanceof GroupAttrName && ((GroupAttrName) k).groupId.equals(key)) - { - itemsToRemove.add(k); - } - } - - // remove matches. - for (K fullKey : itemsToRemove) - { - // Don't add to recycle bin here - // https://issues.apache.org/jira/browse/JCS-67 - performSingleKeyRemoval(fullKey); - removed = true; - // TODO this needs to update the remove count separately - } - - return removed; - } - - /** - * Iterates over the keyset. Builds a list of matches. Removes all the keys in the list. Does - * not remove via the iterator, since the map impl may not support it. - *

- * This operates under a lock obtained in doRemove(). - *

- * - * @param key - * @return true if there was a match - */ - private boolean performPartialKeyRemoval(String key) - { - boolean removed = false; - - // remove all keys of the same name hierarchy. - List itemsToRemove = new LinkedList(); - - for (K k : keyStore.keySet()) - { - if (k instanceof String && k.toString().startsWith(key)) - { - itemsToRemove.add(k); - } - } - - // remove matches. - for (K fullKey : itemsToRemove) - { - // Don't add to recycle bin here - // https://issues.apache.org/jira/browse/JCS-67 - performSingleKeyRemoval(fullKey); - removed = true; - // TODO this needs to update the remove count separately - } - - return removed; - } - - - private boolean performSingleKeyRemoval(K key) { - boolean removed; - // remove single item. - int[] ded = this.keyStore.remove( key ); - removed = ded != null; - if ( removed ) - { - this.dataFile.freeBlocks( ded ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "Disk removal: Removed from key hash, key [" + key + "] removed = " - + removed ); - } - return removed; - } - - /** - * Resets the keyfile, the disk file, and the memory key map. - *

- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#removeAll() - */ - @Override - protected void processRemoveAll() - { - reset(); - } - - /** - * Dispose of the disk cache in a background thread. Joins against this thread to put a cap on - * the disposal time. - *

- * TODO make dispose window configurable. - */ - @Override - public void processDispose() - { - Runnable disR = new Runnable() - { - @Override - public void run() - { - try - { - disposeInternal(); - } - catch ( InterruptedException e ) - { - log.warn( "Interrupted while diposing." ); - } - } - }; - Thread t = new Thread( disR, "BlockDiskCache-DisposalThread" ); - t.start(); - // wait up to 60 seconds for dispose and then quit if not done. - try - { - t.join( 60 * 1000 ); - } - catch ( InterruptedException ex ) - { - log.error( logCacheName + "Interrupted while waiting for disposal thread to finish.", ex ); - } - } - - /** - * Internal method that handles the disposal. - * @throws InterruptedException - */ - protected void disposeInternal() - throws InterruptedException - { - if ( !isAlive() ) - { - log.error( logCacheName + "Not alive and dispose was called, filename: " + fileName ); - return; - } - storageLock.writeLock().lock(); - try - { - // Prevents any interaction with the cache while we're shutting down. - setAlive(false); - this.keyStore.saveKeys(); - - if (future != null) - { - future.cancel(true); - } - - try - { - if ( log.isDebugEnabled() ) - { - log.debug( logCacheName + "Closing files, base filename: " + fileName ); - } - dataFile.close(); - // dataFile = null; - - // TOD make a close - // keyFile.close(); - // keyFile = null; - } - catch ( IOException e ) - { - log.error( logCacheName + "Failure closing files in dispose, filename: " + fileName, e ); - } - } - finally - { - storageLock.writeLock().unlock(); - } - - if ( log.isInfoEnabled() ) - { - log.info( logCacheName + "Shutdown complete." ); - } - } - - /** - * Returns the attributes. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getAuxiliaryCacheAttributes() - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return this.blockDiskCacheAttributes; - } - - /** - * Reset effectively clears the disk cache, creating new files, recyclebins, and keymaps. - *

- * It can be used to handle errors by last resort, force content update, or removeall. - */ - private void reset() - { - if ( log.isWarnEnabled() ) - { - log.warn( logCacheName + "Resetting cache" ); - } - - try - { - storageLock.writeLock().lock(); - - this.keyStore.reset(); - - if ( dataFile != null ) - { - dataFile.reset(); - } - } - catch ( IOException e ) - { - log.error( logCacheName + "Failure resetting state", e ); - } - finally - { - storageLock.writeLock().unlock(); - } - } - - /** - * Add these blocks to the emptyBlock list. - *

- * @param blocksToFree - */ - protected void freeBlocks( int[] blocksToFree ) - { - this.dataFile.freeBlocks( blocksToFree ); - } - - /** - * Returns info about the disk cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getStatistics() - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Block Disk Cache" ); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "Is Alive", Boolean.valueOf(isAlive()) ) ); - elems.add(new StatElement( "Key Map Size", Integer.valueOf(this.keyStore.size()) ) ); - - if (this.dataFile != null) - { - try - { - elems.add(new StatElement( "Data File Length", Long.valueOf(this.dataFile.length()) ) ); - } - catch ( IOException e ) - { - log.error( e ); - } - - elems.add(new StatElement( "Block Size Bytes", - Integer.valueOf(this.dataFile.getBlockSizeBytes()) ) ); - elems.add(new StatElement( "Number Of Blocks", - Integer.valueOf(this.dataFile.getNumberOfBlocks()) ) ); - elems.add(new StatElement( "Average Put Size Bytes", - Long.valueOf(this.dataFile.getAveragePutSizeBytes()) ) ); - elems.add(new StatElement( "Empty Blocks", - Integer.valueOf(this.dataFile.getEmptyBlocks()) ) ); - } - - // get the stats from the super too - IStats sStats = super.getStatistics(); - elems.addAll(sStats.getStatElements()); - - stats.setStatElements( elems ); - - return stats; - } - - /** - * This is used by the event logging. - *

- * @return the location of the disk, either path or ip. - */ - @Override - protected String getDiskLocation() - { - return dataFile.getFilePath(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java deleted file mode 100644 index e520ddaa938..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.block; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCacheAttributes; - -/** - * This holds attributes for Block Disk Cache configuration. - *

- * @author Aaron Smuts - */ -public class BlockDiskCacheAttributes - extends AbstractDiskCacheAttributes -{ - /** Don't change */ - private static final long serialVersionUID = 6568840097657265989L; - - /** The size per block in bytes. */ - private int blockSizeBytes; - - /** Maximum number of keys to be kept in memory */ - private static final int DEFAULT_MAX_KEY_SIZE = 5000; - - /** -1 means no limit. */ - private int maxKeySize = DEFAULT_MAX_KEY_SIZE; - - /** How often should we persist the keys. */ - private static final long DEFAULT_KEY_PERSISTENCE_INTERVAL_SECONDS = 5 * 60; - - /** The keys will be persisted at this interval. -1 mean never. */ - private long keyPersistenceIntervalSeconds = DEFAULT_KEY_PERSISTENCE_INTERVAL_SECONDS; - - /** - * The size of the blocks. All blocks are the same size. - *

- * @param blockSizeBytes The blockSizeBytes to set. - */ - public void setBlockSizeBytes( int blockSizeBytes ) - { - this.blockSizeBytes = blockSizeBytes; - } - - /** - * @return Returns the blockSizeBytes. - */ - public int getBlockSizeBytes() - { - return blockSizeBytes; - } - - /** - * @param maxKeySize The maxKeySize to set. - */ - public void setMaxKeySize( int maxKeySize ) - { - this.maxKeySize = maxKeySize; - } - - /** - * @return Returns the maxKeySize. - */ - public int getMaxKeySize() - { - return maxKeySize; - } - - /** - * @param keyPersistenceIntervalSeconds The keyPersistenceIntervalSeconds to set. - */ - public void setKeyPersistenceIntervalSeconds( long keyPersistenceIntervalSeconds ) - { - this.keyPersistenceIntervalSeconds = keyPersistenceIntervalSeconds; - } - - /** - * @return Returns the keyPersistenceIntervalSeconds. - */ - public long getKeyPersistenceIntervalSeconds() - { - return keyPersistenceIntervalSeconds; - } - - /** - * Write out the values for debugging purposes. - *

- * @return String - */ - @Override - public String toString() - { - StringBuilder str = new StringBuilder(); - str.append( "\nBlockDiskAttributes " ); - str.append( "\n DiskPath [" + this.getDiskPath() + "]" ); - str.append( "\n MaxKeySize [" + this.getMaxKeySize() + "]" ); - str.append( "\n MaxPurgatorySize [" + this.getMaxPurgatorySize() + "]" ); - str.append( "\n BlockSizeBytes [" + this.getBlockSizeBytes() + "]" ); - str.append( "\n KeyPersistenceIntervalSeconds [" + this.getKeyPersistenceIntervalSeconds() + "]" ); - str.append( "\n DiskLimitType [" + this.getDiskLimitType() + "]" ); - return str.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheFactory.java deleted file mode 100644 index 0b35d2b720f..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.block; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Creates disk cache instances. - */ -public class BlockDiskCacheFactory - extends AbstractAuxiliaryCacheFactory -{ - /** The logger */ - private static final Log log = LogFactory.getLog( BlockDiskCacheFactory.class ); - - /** - * Create an instance of the BlockDiskCache. - *

- * @param iaca the cache attributes for this cache - * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is - * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier - * to test. - * @param cacheEventLogger - * @param elementSerializer - * @return BlockDiskCache - */ - @Override - public BlockDiskCache createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - { - BlockDiskCacheAttributes idca = (BlockDiskCacheAttributes) iaca; - if ( log.isDebugEnabled() ) - { - log.debug( "Creating DiskCache for attributes = " + idca ); - } - - BlockDiskCache cache = new BlockDiskCache( idca, elementSerializer ); - cache.setCacheEventLogger( cacheEventLogger ); - - return cache; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskElementDescriptor.java b/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskElementDescriptor.java deleted file mode 100644 index 73fd657378c..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskElementDescriptor.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.block; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.io.Serializable; - -/** - * This represents an element on disk. This is used when we persist the keys. We only store the - * block addresses in memory. We don't need the length here, since all the blocks are the same size - * receyle bin. - *

- * @author Aaron Smuts - */ -public class BlockDiskElementDescriptor - implements Serializable, Externalizable -{ - /** Don't change */ - private static final long serialVersionUID = -1400659301208101411L; - - /** The key */ - private K key; - - /** The array of block numbers */ - private int[] blocks; - - /** - * @param key The key to set. - */ - public void setKey( K key ) - { - this.key = key; - } - - /** - * @return Returns the key. - */ - public K getKey() - { - return key; - } - - /** - * @param blocks The blocks to set. - */ - public void setBlocks( int[] blocks ) - { - this.blocks = blocks; - } - - /** - * This holds the block numbers. An item my be dispersed between multiple blocks. - *

- * @return Returns the blocks. - */ - public int[] getBlocks() - { - return blocks; - } - - /** - * For debugging. - *

- * @return Info on the descriptor. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nBlockDiskElementDescriptor" ); - buf.append( "\n key [" + this.getKey() + "]" ); - buf.append( "\n blocks [" ); - if ( this.getBlocks() != null ) - { - for ( int i = 0; i < blocks.length; i++ ) - { - buf.append( this.getBlocks()[i] ); - } - } - buf.append( "]" ); - return buf.toString(); - } - - /** - * Saves on reflection. - *

- * (non-Javadoc) - * @see java.io.Externalizable#readExternal(java.io.ObjectInput) - */ - @Override - @SuppressWarnings("unchecked") // Need cast to K - public void readExternal( ObjectInput input ) - throws IOException, ClassNotFoundException - { - this.key = (K) input.readObject(); - this.blocks = (int[]) input.readObject(); - } - - /** - * Saves on reflection. - *

- * (non-Javadoc) - * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) - */ - @Override - public void writeExternal( ObjectOutput output ) - throws IOException - { - output.writeObject( this.key ); - output.writeObject( this.blocks ); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java b/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java deleted file mode 100644 index d41f92d7536..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java +++ /dev/null @@ -1,584 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.block; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType; -import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware; -import org.apache.commons.jcs.utils.struct.AbstractLRUMap; -import org.apache.commons.jcs.utils.struct.LRUMap; -import org.apache.commons.jcs.utils.timing.ElapsedTimer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This is responsible for storing the keys. - *

- * - * @author Aaron Smuts - */ -public class BlockDiskKeyStore -{ - /** The logger */ - private static final Log log = LogFactory.getLog(BlockDiskKeyStore.class); - - /** Attributes governing the behavior of the block disk cache. */ - private final BlockDiskCacheAttributes blockDiskCacheAttributes; - - /** The key to block map */ - private Map keyHash; - - /** The file where we persist the keys */ - private final File keyFile; - - /** The name to prefix log messages with. */ - protected final String logCacheName; - - /** Name of the file where we persist the keys */ - private final String fileName; - - /** The maximum number of keys to store in memory */ - private final int maxKeySize; - - /** - * we need this so we can communicate free blocks to the data store when - * keys fall off the LRU - */ - protected final BlockDiskCache blockDiskCache; - - private DiskLimitType diskLimitType = DiskLimitType.COUNT; - - private int blockSize; - - /** - * Set the configuration options. - *

- * - * @param cacheAttributes - * @param blockDiskCache - * used for freeing - */ - public BlockDiskKeyStore(BlockDiskCacheAttributes cacheAttributes, BlockDiskCache blockDiskCache) - { - this.blockDiskCacheAttributes = cacheAttributes; - this.logCacheName = "Region [" + this.blockDiskCacheAttributes.getCacheName() + "] "; - this.fileName = this.blockDiskCacheAttributes.getCacheName(); - this.maxKeySize = cacheAttributes.getMaxKeySize(); - this.blockDiskCache = blockDiskCache; - this.diskLimitType = cacheAttributes.getDiskLimitType(); - this.blockSize = cacheAttributes.getBlockSizeBytes(); - - File rootDirectory = cacheAttributes.getDiskPath(); - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Cache file root directory [" + rootDirectory + "]"); - } - - this.keyFile = new File(rootDirectory, fileName + ".key"); - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Key File [" + this.keyFile.getAbsolutePath() + "]"); - } - - if (keyFile.length() > 0) - { - loadKeys(); - if (!verify()) - { - log.warn(logCacheName + "Key File is invalid. Resetting file."); - initKeyMap(); - reset(); - } - } - else - { - initKeyMap(); - } - } - - /** - * Saves key file to disk. This gets the LRUMap entry set and write the - * entries out one by one after putting them in a wrapper. - */ - protected void saveKeys() - { - try - { - ElapsedTimer timer = new ElapsedTimer(); - int numKeys = keyHash.size(); - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Saving keys to [" + this.keyFile.getAbsolutePath() + "], key count [" + numKeys + "]"); - } - - synchronized (keyFile) - { - FileOutputStream fos = new FileOutputStream(keyFile); - BufferedOutputStream bos = new BufferedOutputStream(fos, 65536); - ObjectOutputStream oos = new ObjectOutputStream(bos); - try - { - if (!verify()) - { - throw new IOException("Inconsistent key file"); - } - // don't need to synchronize, since the underlying - // collection makes a copy - for (Map.Entry entry : keyHash.entrySet()) - { - BlockDiskElementDescriptor descriptor = new BlockDiskElementDescriptor(); - descriptor.setKey(entry.getKey()); - descriptor.setBlocks(entry.getValue()); - // stream these out in the loop. - oos.writeUnshared(descriptor); - } - } - finally - { - oos.flush(); - oos.close(); - } - } - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Finished saving keys. It took " + timer.getElapsedTimeString() + " to store " + numKeys - + " keys. Key file length [" + keyFile.length() + "]"); - } - } - catch (IOException e) - { - log.error(logCacheName + "Problem storing keys.", e); - } - } - - /** - * Resets the file and creates a new key map. - */ - protected void reset() - { - synchronized (keyFile) - { - clearMemoryMap(); - saveKeys(); - } - } - - /** - * This is mainly used for testing. It leave the disk in tact, and just - * clears memory. - */ - protected void clearMemoryMap() - { - this.keyHash.clear(); - } - - /** - * Create the map for keys that contain the index position on disk. - */ - private void initKeyMap() - { - keyHash = null; - if (maxKeySize >= 0) - { - if (this.diskLimitType == DiskLimitType.SIZE) - { - keyHash = new LRUMapSizeLimited(maxKeySize); - } - else - { - keyHash = new LRUMapCountLimited(maxKeySize); - } - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Set maxKeySize to: '" + maxKeySize + "'"); - } - } - else - { - // If no max size, use a plain map for memory and processing - // efficiency. - keyHash = new HashMap(); - // keyHash = Collections.synchronizedMap( new HashMap() ); - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Set maxKeySize to unlimited'"); - } - } - } - - /** - * Loads the keys from the .key file. The keys are stored individually on - * disk. They are added one by one to an LRUMap.. - */ - protected void loadKeys() - { - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Loading keys for " + keyFile.toString()); - } - - try - { - // create a key map to use. - initKeyMap(); - - HashMap keys = new HashMap(); - - synchronized (keyFile) - { - FileInputStream fis = new FileInputStream(keyFile); - BufferedInputStream bis = new BufferedInputStream(fis, 65536); - ObjectInputStream ois = new ObjectInputStreamClassLoaderAware(bis, null); - try - { - while (true) - { - @SuppressWarnings("unchecked") - // Need to cast from Object - BlockDiskElementDescriptor descriptor = (BlockDiskElementDescriptor) ois.readObject(); - if (descriptor != null) - { - keys.put(descriptor.getKey(), descriptor.getBlocks()); - } - } - } - catch (EOFException eof) - { - // nothing - } - finally - { - ois.close(); - } - } - - if (!keys.isEmpty()) - { - keyHash.putAll(keys); - - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Found " + keys.size() + " in keys file."); - } - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Loaded keys from [" + fileName + "], key count: " + keyHash.size() + "; up to " - + maxKeySize + " will be available."); - } - } - } - catch (Exception e) - { - log.error(logCacheName + "Problem loading keys for file " + fileName, e); - } - } - - /** - * Gets the entry set. - *

- * - * @return entry set. - */ - public Set> entrySet() - { - return this.keyHash.entrySet(); - } - - /** - * Gets the key set. - *

- * - * @return key set. - */ - public Set keySet() - { - return this.keyHash.keySet(); - } - - /** - * Gets the size of the key hash. - *

- * - * @return the number of keys. - */ - public int size() - { - return this.keyHash.size(); - } - - /** - * gets the object for the key. - *

- * - * @param key - * @return Object - */ - public int[] get(K key) - { - return this.keyHash.get(key); - } - - /** - * Puts a int[] in the keyStore. - *

- * - * @param key - * @param value - */ - public void put(K key, int[] value) - { - this.keyHash.put(key, value); - } - - /** - * Remove by key. - *

- * - * @param key - * @return BlockDiskElementDescriptor if it was present, else null - */ - public int[] remove(K key) - { - return this.keyHash.remove(key); - } - - /** - * Verify key store integrity - * - * @return true if key store is valid - */ - private boolean verify() - { - Map> blockAllocationMap = new TreeMap>(); - for (Entry e : keyHash.entrySet()) - { - for (int block : e.getValue()) - { - Set keys = blockAllocationMap.get(block); - if (keys == null) - { - keys = new HashSet(); - blockAllocationMap.put(block, keys); - } - else if (!log.isDebugEnabled()) - { - // keys are not null, and no debug - fail fast - return false; - } - keys.add(e.getKey()); - } - } - boolean ok = true; - if (log.isDebugEnabled()) - { - for (Entry> e : blockAllocationMap.entrySet()) - { - log.debug("Block " + e.getKey() + ":" + e.getValue()); - if (e.getValue().size() > 1) - { - ok = false; - } - } - return ok; - } - else - { - return ok; - } - } - - /** - * Class for recycling and lru. This implements the LRU size overflow - * callback, so we can mark the blocks as free. - */ - public class LRUMapSizeLimited extends AbstractLRUMap - { - /** - * tag tells us which map we are working on. - */ - public final static String TAG = "orig-lru-size"; - - // size of the content in kB - private AtomicInteger contentSize; - private int maxSize; - - /** - * Default - */ - public LRUMapSizeLimited() - { - this(-1); - } - - /** - * @param maxSize - * maximum cache size in kB - */ - public LRUMapSizeLimited(int maxSize) - { - super(); - this.maxSize = maxSize; - this.contentSize = new AtomicInteger(0); - } - - // keep the content size in kB, so 2^31 kB is reasonable value - private void subLengthFromCacheSize(int[] value) - { - contentSize.addAndGet(value.length * blockSize / -1024 - 1); - } - - // keep the content size in kB, so 2^31 kB is reasonable value - private void addLengthToCacheSize(int[] value) - { - contentSize.addAndGet(value.length * blockSize / 1024 + 1); - } - - @Override - public int[] put(K key, int[] value) - { - int[] oldValue = null; - - try - { - oldValue = super.put(key, value); - } - finally - { - if (value != null) - { - addLengthToCacheSize(value); - } - if (oldValue != null) - { - subLengthFromCacheSize(oldValue); - } - } - - return oldValue; - } - - @Override - public int[] remove(Object key) - { - int[] value = null; - - try - { - value = super.remove(key); - return value; - } - finally - { - if (value != null) - { - subLengthFromCacheSize(value); - } - } - } - - /** - * This is called when the may key size is reached. The least recently - * used item will be passed here. We will store the position and size of - * the spot on disk in the recycle bin. - *

- * - * @param key - * @param value - */ - @Override - protected void processRemovedLRU(K key, int[] value) - { - blockDiskCache.freeBlocks(value); - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Removing key: [" + key + "] from key store."); - log.debug(logCacheName + "Key store size: [" + super.size() + "]."); - } - - if (value != null) - { - subLengthFromCacheSize(value); - } - } - - @Override - protected boolean shouldRemove() - { - return maxSize > 0 && contentSize.get() > maxSize && this.size() > 1; - } - } - - /** - * Class for recycling and lru. This implements the LRU overflow callback, - * so we can mark the blocks as free. - */ - public class LRUMapCountLimited extends LRUMap - { - /** - * tag tells us which map we are working on. - */ - public final static String TAG = "orig-lru-count"; - - public LRUMapCountLimited(int maxKeySize) - { - super(maxKeySize); - } - - /** - * This is called when the may key size is reached. The least recently - * used item will be passed here. We will store the position and size of - * the spot on disk in the recycle bin. - *

- * - * @param key - * @param value - */ - @Override - protected void processRemovedLRU(K key, int[] value) - { - blockDiskCache.freeBlocks(value); - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Removing key: [" + key + "] from key store."); - log.debug(logCacheName + "Key store size: [" + super.size() + "]."); - } - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDisk.java b/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDisk.java deleted file mode 100644 index ee6a3ad87b8..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDisk.java +++ /dev/null @@ -1,282 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.indexed; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.io.Serializable; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; - -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** Provides thread safe access to the underlying random access file. */ -class IndexedDisk -{ - /** The size of the header that indicates the amount of data stored in an occupied block. */ - public static final byte HEADER_SIZE_BYTES = 4; - - /** The serializer. */ - private final IElementSerializer elementSerializer; - - /** The logger */ - private static final Log log = LogFactory.getLog( IndexedDisk.class ); - - /** The path to the log directory. */ - private final String filepath; - - /** The data file. */ - private final FileChannel fc; - - /** - * Constructor for the Disk object - *

- * @param file - * @param elementSerializer - * @throws FileNotFoundException - */ - public IndexedDisk( File file, IElementSerializer elementSerializer ) - throws FileNotFoundException - { - this.filepath = file.getAbsolutePath(); - this.elementSerializer = elementSerializer; - RandomAccessFile raf = new RandomAccessFile( filepath, "rw" ); - this.fc = raf.getChannel(); - } - - /** - * This reads an object from the given starting position on the file. - *

- * The first four bytes of the record should tell us how long it is. The data is read into a byte - * array and then an object is constructed from the byte array. - *

- * @return Serializable - * @param ded - * @throws IOException - * @throws ClassNotFoundException - */ - protected T readObject( IndexedDiskElementDescriptor ded ) - throws IOException, ClassNotFoundException - { - String message = null; - boolean corrupted = false; - long fileLength = fc.size(); - if ( ded.pos > fileLength ) - { - corrupted = true; - message = "Record " + ded + " starts past EOF."; - } - else - { - ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES); - fc.read(datalength, ded.pos); - datalength.flip(); - int datalen = datalength.getInt(); - if ( ded.len != datalen ) - { - corrupted = true; - message = "Record " + ded + " does not match data length on disk (" + datalen + ")"; - } - else if ( ded.pos + ded.len > fileLength ) - { - corrupted = true; - message = "Record " + ded + " exceeds file length."; - } - } - - if ( corrupted ) - { - log.warn( "\n The file is corrupt: " + "\n " + message ); - throw new IOException( "The File Is Corrupt, need to reset" ); - } - - ByteBuffer data = ByteBuffer.allocate(ded.len); - fc.read(data, ded.pos + HEADER_SIZE_BYTES); - data.flip(); - - return elementSerializer.deSerialize( data.array(), null ); - } - - /** - * Moves the data stored from one position to another. The descriptor's position is updated. - *

- * @param ded - * @param newPosition - * @throws IOException - */ - protected void move( final IndexedDiskElementDescriptor ded, final long newPosition ) - throws IOException - { - ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES); - fc.read(datalength, ded.pos); - datalength.flip(); - int length = datalength.getInt(); - - if ( length != ded.len ) - { - throw new IOException( "Mismatched memory and disk length (" + length + ") for " + ded ); - } - - // TODO: more checks? - - long readPos = ded.pos; - long writePos = newPosition; - - // header len + data len - int remaining = HEADER_SIZE_BYTES + length; - ByteBuffer buffer = ByteBuffer.allocate(16384); - - while ( remaining > 0 ) - { - // chunk it - int chunkSize = Math.min( remaining, buffer.capacity() ); - buffer.limit(chunkSize); - fc.read(buffer, readPos); - buffer.flip(); - fc.write(buffer, writePos); - buffer.clear(); - - writePos += chunkSize; - readPos += chunkSize; - remaining -= chunkSize; - } - - ded.pos = newPosition; - } - - /** - * Writes the given byte array to the Disk at the specified position. - *

- * @param data - * @param ded - * @return true if we wrote successfully - * @throws IOException - */ - protected boolean write( IndexedDiskElementDescriptor ded, byte[] data ) - throws IOException - { - long pos = ded.pos; - if ( log.isTraceEnabled() ) - { - log.trace( "write> pos=" + pos ); - log.trace( fc + " -- data.length = " + data.length ); - } - - if ( data.length != ded.len ) - { - throw new IOException( "Mismatched descriptor and data lengths" ); - } - - ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE_BYTES + data.length); - buffer.putInt(data.length); - buffer.put(data); - buffer.flip(); - int written = fc.write(buffer, pos); - //fc.force(true); - - return written == data.length; - } - - /** - * Serializes the object and write it out to the given position. - *

- * TODO: make this take a ded as well. - * @return true unless error - * @param obj - * @param pos - * @throws IOException - */ - protected boolean writeObject( Serializable obj, long pos ) - throws IOException - { - byte[] data = elementSerializer.serialize( obj ); - write( new IndexedDiskElementDescriptor( pos, data.length ), data ); - return true; - } - - /** - * Returns the raf length. - *

- * @return the length of the file. - * @throws IOException - */ - protected long length() - throws IOException - { - return fc.size(); - } - - /** - * Closes the raf. - *

- * @throws IOException - */ - protected void close() - throws IOException - { - fc.close(); - } - - /** - * Sets the raf to empty. - *

- * @throws IOException - */ - protected synchronized void reset() - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "Resetting Indexed File [" + filepath + "]" ); - } - fc.truncate(0); - fc.force(true); - } - - /** - * Truncates the file to a given length. - *

- * @param length the new length of the file - * @throws IOException - */ - protected void truncate( long length ) - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "Truncating file [" + filepath + "] to " + length ); - } - fc.truncate( length ); - } - - /** - * This is used for debugging. - *

- * @return the file path. - */ - protected String getFilePath() - { - return filepath; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java b/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java deleted file mode 100644 index 30a82d32910..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java +++ /dev/null @@ -1,1790 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.indexed; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache; -import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType; -import org.apache.commons.jcs.engine.CacheConstants; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.control.group.GroupAttrName; -import org.apache.commons.jcs.engine.control.group.GroupId; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.jcs.utils.struct.AbstractLRUMap; -import org.apache.commons.jcs.utils.struct.LRUMap; -import org.apache.commons.jcs.utils.timing.ElapsedTimer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Disk cache that uses a RandomAccessFile with keys stored in memory. The maximum number of keys - * stored in memory is configurable. The disk cache tries to recycle spots on disk to limit file - * expansion. - */ -public class IndexedDiskCache extends AbstractDiskCache -{ - /** The logger */ - private static final Log log = LogFactory.getLog(IndexedDiskCache.class); - - /** Cache name used in log messages */ - protected final String logCacheName; - - /** The name of the file where the data is stored */ - private final String fileName; - - /** The IndexedDisk manages reads and writes to the data file. */ - private IndexedDisk dataFile; - - /** The IndexedDisk manages reads and writes to the key file. */ - private IndexedDisk keyFile; - - /** Map containing the keys and disk offsets. */ - private Map keyHash; - - /** The maximum number of keys that we will keep in memory. */ - private final int maxKeySize; - - /** A handle on the data file. */ - private File rafDir; - - /** Should we keep adding to the recycle bin. False during optimization. */ - private boolean doRecycle = true; - - /** Should we optimize real time */ - private boolean isRealTimeOptimizationEnabled = true; - - /** Should we optimize on shutdown. */ - private boolean isShutdownOptimizationEnabled = true; - - /** are we currently optimizing the files */ - private boolean isOptimizing = false; - - /** The number of times the file has been optimized. */ - private int timesOptimized = 0; - - /** The thread optimizing the file. */ - private volatile Thread currentOptimizationThread; - - /** used for counting the number of requests */ - private int removeCount = 0; - - /** Should we queue puts. True when optimizing. We write the queue post optimization. */ - private boolean queueInput = false; - - /** list where puts made during optimization are made */ - private final ConcurrentSkipListSet queuedPutList = - new ConcurrentSkipListSet(new PositionComparator()); - - /** RECYLCE BIN -- array of empty spots */ - private ConcurrentSkipListSet recycle; - - /** User configurable parameters */ - private final IndexedDiskCacheAttributes cattr; - - /** How many slots have we recycled. */ - private int recycleCnt = 0; - - /** How many items were there on startup. */ - private int startupSize = 0; - - /** the number of bytes free on disk. */ - private AtomicLong bytesFree = new AtomicLong(0); - - /** mode we are working on (size or count limited **/ - private DiskLimitType diskLimitType = DiskLimitType.COUNT; - - /** simple stat */ - private AtomicInteger hitCount = new AtomicInteger(0); - - /** - * Use this lock to synchronize reads and writes to the underlying storage mechanism. - */ - protected ReentrantReadWriteLock storageLock = new ReentrantReadWriteLock(); - - /** - * Constructor for the DiskCache object. - *

- * - * @param cacheAttributes - */ - public IndexedDiskCache(IndexedDiskCacheAttributes cacheAttributes) - { - this(cacheAttributes, null); - } - - /** - * Constructor for the DiskCache object. - *

- * - * @param cattr - * @param elementSerializer - * used if supplied, the super's super will not set a null - */ - public IndexedDiskCache(IndexedDiskCacheAttributes cattr, IElementSerializer elementSerializer) - { - super(cattr); - - setElementSerializer(elementSerializer); - - this.cattr = cattr; - this.maxKeySize = cattr.getMaxKeySize(); - this.isRealTimeOptimizationEnabled = cattr.getOptimizeAtRemoveCount() > 0; - this.isShutdownOptimizationEnabled = cattr.isOptimizeOnShutdown(); - this.logCacheName = "Region [" + getCacheName() + "] "; - this.diskLimitType = cattr.getDiskLimitType(); - // Make a clean file name - this.fileName = getCacheName().replaceAll("[^a-zA-Z0-9-_\\.]", "_"); - - try - { - initializeFileSystem(cattr); - - initializeKeysAndData(cattr); - - initializeRecycleBin(); - - // Initialization finished successfully, so set alive to true. - setAlive(true); - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Indexed Disk Cache is alive."); - } - - // TODO: Should we improve detection of whether or not the file should be optimized. - if (isRealTimeOptimizationEnabled && keyHash.size() > 0) - { - // Kick off a real time optimization, in case we didn't do a final optimization. - doOptimizeRealTime(); - } - } - catch (IOException e) - { - log.error( - logCacheName + "Failure initializing for fileName: " + fileName + " and directory: " - + this.rafDir.getAbsolutePath(), e); - } - } - - /** - * Tries to create the root directory if it does not already exist. - *

- * - * @param cattr - */ - private void initializeFileSystem(IndexedDiskCacheAttributes cattr) - { - this.rafDir = cattr.getDiskPath(); - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Cache file root directory: " + rafDir); - } - } - - /** - * Creates the key and data disk caches. - *

- * Loads any keys if they are present and ClearDiskOnStartup is false. - *

- * - * @param cattr - * @throws IOException - */ - private void initializeKeysAndData(IndexedDiskCacheAttributes cattr) throws IOException - { - this.dataFile = new IndexedDisk(new File(rafDir, fileName + ".data"), getElementSerializer()); - this.keyFile = new IndexedDisk(new File(rafDir, fileName + ".key"), getElementSerializer()); - - if (cattr.isClearDiskOnStartup()) - { - if (log.isInfoEnabled()) - { - log.info(logCacheName + "ClearDiskOnStartup is set to true. Ingnoring any persisted data."); - } - initializeEmptyStore(); - } - else if (keyFile.length() > 0) - { - // If the key file has contents, try to initialize the keys - // from it. In no keys are loaded reset the data file. - initializeStoreFromPersistedData(); - } - else - { - // Otherwise start with a new empty map for the keys, and reset - // the data file if it has contents. - initializeEmptyStore(); - } - } - - /** - * Initializes an empty disk cache. - *

- * - * @throws IOException - */ - private void initializeEmptyStore() throws IOException - { - initializeKeyMap(); - - if (dataFile.length() > 0) - { - dataFile.reset(); - } - } - - /** - * Loads any persisted data and checks for consistency. If there is a consistency issue, the - * files are cleared. - *

- * - * @throws IOException - */ - private void initializeStoreFromPersistedData() throws IOException - { - loadKeys(); - - if (keyHash.isEmpty()) - { - dataFile.reset(); - } - else - { - boolean isOk = checkKeyDataConsistency(false); - if (!isOk) - { - keyHash.clear(); - keyFile.reset(); - dataFile.reset(); - log.warn(logCacheName + "Corruption detected. Reseting data and keys files."); - } - else - { - synchronized (this) - { - startupSize = keyHash.size(); - } - } - } - } - - /** - * Loads the keys from the .key file. The keys are stored in a HashMap on disk. This is - * converted into a LRUMap. - */ - protected void loadKeys() - { - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Loading keys for " + keyFile.toString()); - } - - storageLock.writeLock().lock(); - - try - { - // create a key map to use. - initializeKeyMap(); - - HashMap keys = keyFile.readObject( - new IndexedDiskElementDescriptor(0, (int) keyFile.length() - IndexedDisk.HEADER_SIZE_BYTES)); - - if (keys != null) - { - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Found " + keys.size() + " in keys file."); - } - - keyHash.putAll(keys); - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Loaded keys from [" + fileName + "], key count: " + keyHash.size() + "; up to " - + maxKeySize + " will be available."); - } - } - - if (log.isDebugEnabled()) - { - dump(false); - } - } - catch (Exception e) - { - log.error(logCacheName + "Problem loading keys for file " + fileName, e); - } - finally - { - storageLock.writeLock().unlock(); - } - } - - /** - * Check for minimal consistency between the keys and the datafile. Makes sure no starting - * positions in the keys exceed the file length. - *

- * The caller should take the appropriate action if the keys and data are not consistent. - * - * @param checkForDedOverlaps - * if true, do a more thorough check by checking for - * data overlap - * @return true if the test passes - */ - private boolean checkKeyDataConsistency(boolean checkForDedOverlaps) - { - ElapsedTimer timer = new ElapsedTimer(); - log.debug(logCacheName + "Performing inital consistency check"); - - boolean isOk = true; - long fileLength = 0; - try - { - fileLength = dataFile.length(); - - for (Map.Entry e : keyHash.entrySet()) - { - IndexedDiskElementDescriptor ded = e.getValue(); - - isOk = ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len <= fileLength; - - if (!isOk) - { - log.warn(logCacheName + "The dataFile is corrupted!" + "\n raf.length() = " + fileLength + "\n ded.pos = " - + ded.pos); - break; - } - } - - if (isOk && checkForDedOverlaps) - { - isOk = checkForDedOverlaps(createPositionSortedDescriptorList()); - } - } - catch (IOException e) - { - log.error(e); - isOk = false; - } - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Finished inital consistency check, isOk = " + isOk + " in " + timer.getElapsedTimeString()); - } - - return isOk; - } - - /** - * Detects any overlapping elements. This expects a sorted list. - *

- * The total length of an item is IndexedDisk.RECORD_HEADER + ded.len. - *

- * - * @param sortedDescriptors - * @return false if there are overlaps. - */ - protected boolean checkForDedOverlaps(IndexedDiskElementDescriptor[] sortedDescriptors) - { - long start = System.currentTimeMillis(); - boolean isOk = true; - long expectedNextPos = 0; - for (int i = 0; i < sortedDescriptors.length; i++) - { - IndexedDiskElementDescriptor ded = sortedDescriptors[i]; - if (expectedNextPos > ded.pos) - { - log.error(logCacheName + "Corrupt file: overlapping deds " + ded); - isOk = false; - break; - } - else - { - expectedNextPos = ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len; - } - } - long end = System.currentTimeMillis(); - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Check for DED overlaps took " + (end - start) + " ms."); - } - - return isOk; - } - - /** - * Saves key file to disk. This converts the LRUMap to a HashMap for deserialization. - */ - protected void saveKeys() - { - try - { - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Saving keys to: " + fileName + ", key count: " + keyHash.size()); - } - - keyFile.reset(); - - HashMap keys = new HashMap(); - keys.putAll(keyHash); - - if (keys.size() > 0) - { - keyFile.writeObject(keys, 0); - } - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Finished saving keys."); - } - } - catch (IOException e) - { - log.error(logCacheName + "Problem storing keys.", e); - } - } - - /** - * Update the disk cache. Called from the Queue. Makes sure the Item has not been retrieved from - * purgatory while in queue for disk. Remove items from purgatory when they go to disk. - *

- * - * @param ce - * The ICacheElement<K, V> to put to disk. - */ - @Override - protected void processUpdate(ICacheElement ce) - { - if (!isAlive()) - { - log.error(logCacheName + "No longer alive; aborting put of key = " + ce.getKey()); - return; - } - - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Storing element on disk, key: " + ce.getKey()); - } - - IndexedDiskElementDescriptor ded = null; - - // old element with same key - IndexedDiskElementDescriptor old = null; - - try - { - byte[] data = getElementSerializer().serialize(ce); - - // make sure this only locks for one particular cache region - storageLock.writeLock().lock(); - try - { - old = keyHash.get(ce.getKey()); - - // Item with the same key already exists in file. - // Try to reuse the location if possible. - if (old != null && data.length <= old.len) - { - // Reuse the old ded. The defrag relies on ded updates by reference, not - // replacement. - ded = old; - ded.len = data.length; - } - else - { - // we need this to compare in the recycle bin - ded = new IndexedDiskElementDescriptor(dataFile.length(), data.length); - - if (doRecycle) - { - IndexedDiskElementDescriptor rep = recycle.ceiling(ded); - if (rep != null) - { - // remove element from recycle bin - recycle.remove(rep); - ded = rep; - ded.len = data.length; - recycleCnt++; - this.adjustBytesFree(ded, false); - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "using recycled ded " + ded.pos + " rep.len = " + rep.len + " ded.len = " - + ded.len); - } - } - } - - // Put it in the map - keyHash.put(ce.getKey(), ded); - - if (queueInput) - { - queuedPutList.add(ded); - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "added to queued put list." + queuedPutList.size()); - } - } - - // add the old slot to the recycle bin - if (old != null) - { - addToRecycleBin(old); - } - } - - dataFile.write(ded, data); - } - finally - { - storageLock.writeLock().unlock(); - } - - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Put to file: " + fileName + ", key: " + ce.getKey() + ", position: " + ded.pos - + ", size: " + ded.len); - } - } - catch (IOException e) - { - log.error(logCacheName + "Failure updating element, key: " + ce.getKey() + " old: " + old, e); - } - } - - /** - * Gets the key, then goes to disk to get the object. - *

- * - * @param key - * @return ICacheElement<K, V> or null - * @see AbstractDiskCache#doGet - */ - @Override - protected ICacheElement processGet(K key) - { - if (!isAlive()) - { - log.error(logCacheName + "No longer alive so returning null for key = " + key); - return null; - } - - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Trying to get from disk: " + key); - } - - ICacheElement object = null; - try - { - storageLock.readLock().lock(); - try - { - object = readElement(key); - } - finally - { - storageLock.readLock().unlock(); - } - - if (object != null) - { - hitCount.incrementAndGet(); - } - } - catch (IOException ioe) - { - log.error(logCacheName + "Failure getting from disk, key = " + key, ioe); - reset(); - } - return object; - } - - /** - * Gets matching items from the cache. - *

- * - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching keys - */ - @Override - public Map> processGetMatching(String pattern) - { - Map> elements = new HashMap>(); - Set keyArray = null; - storageLock.readLock().lock(); - try - { - keyArray = new HashSet(keyHash.keySet()); - } - finally - { - storageLock.readLock().unlock(); - } - - Set matchingKeys = getKeyMatcher().getMatchingKeysFromArray(pattern, keyArray); - - for (K key : matchingKeys) - { - ICacheElement element = processGet(key); - if (element != null) - { - elements.put(key, element); - } - } - return elements; - } - - /** - * Reads the item from disk. - *

- * - * @param key - * @return ICacheElement - * @throws IOException - */ - private ICacheElement readElement(K key) throws IOException - { - ICacheElement object = null; - - IndexedDiskElementDescriptor ded = keyHash.get(key); - - if (ded != null) - { - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Found on disk, key: " + key); - } - try - { - ICacheElement readObject = dataFile.readObject(ded); - object = readObject; - // TODO consider checking key equality and throwing if there is a failure - } - catch (IOException e) - { - log.error(logCacheName + "IO Exception, Problem reading object from file", e); - throw e; - } - catch (Exception e) - { - log.error(logCacheName + "Exception, Problem reading object from file", e); - throw new IOException(logCacheName + "Problem reading object from disk. " + e.getMessage()); - } - } - - return object; - } - - /** - * Return the keys in this cache. - *

- * - * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - HashSet keys = new HashSet(); - - storageLock.readLock().lock(); - - try - { - keys.addAll(this.keyHash.keySet()); - } - finally - { - storageLock.readLock().unlock(); - } - - return keys; - } - - /** - * Returns true if the removal was successful; or false if there is nothing to remove. Current - * implementation always result in a disk orphan. - *

- * - * @return true if at least one item was removed. - * @param key - */ - @Override - protected boolean processRemove(K key) - { - if (!isAlive()) - { - log.error(logCacheName + "No longer alive so returning false for key = " + key); - return false; - } - - if (key == null) - { - return false; - } - - boolean reset = false; - boolean removed = false; - try - { - storageLock.writeLock().lock(); - - if (key instanceof String && key.toString().endsWith(CacheConstants.NAME_COMPONENT_DELIMITER)) - { - removed = performPartialKeyRemoval((String) key); - } - else if (key instanceof GroupAttrName && ((GroupAttrName) key).attrName == null) - { - removed = performGroupRemoval(((GroupAttrName) key).groupId); - } - else - { - removed = performSingleKeyRemoval(key); - } - } - finally - { - storageLock.writeLock().unlock(); - } - - if (reset) - { - reset(); - } - - // this increments the remove count. - // there is no reason to call this if an item was not removed. - if (removed) - { - doOptimizeRealTime(); - } - - return removed; - } - - /** - * Iterates over the keyset. Builds a list of matches. Removes all the keys in the list. Does - * not remove via the iterator, since the map impl may not support it. - *

- * This operates under a lock obtained in doRemove(). - *

- * - * @param key - * @return true if there was a match - */ - private boolean performPartialKeyRemoval(String key) - { - boolean removed = false; - - // remove all keys of the same name hierarchy. - List itemsToRemove = new LinkedList(); - - for (K k : keyHash.keySet()) - { - if (k instanceof String && k.toString().startsWith(key)) - { - itemsToRemove.add(k); - } - } - - // remove matches. - for (K fullKey : itemsToRemove) - { - // Don't add to recycle bin here - // https://issues.apache.org/jira/browse/JCS-67 - performSingleKeyRemoval(fullKey); - removed = true; - // TODO this needs to update the remove count separately - } - - return removed; - } - - /** - * Remove all elements from the group. This does not use the iterator to remove. It builds a - * list of group elements and then removes them one by one. - *

- * This operates under a lock obtained in doRemove(). - *

- * - * @param key - * @return true if an element was removed - */ - private boolean performGroupRemoval(GroupId key) - { - boolean removed = false; - - // remove all keys of the same name group. - List itemsToRemove = new LinkedList(); - - // remove all keys of the same name hierarchy. - for (K k : keyHash.keySet()) - { - if (k instanceof GroupAttrName && ((GroupAttrName) k).groupId.equals(key)) - { - itemsToRemove.add(k); - } - } - - // remove matches. - for (K fullKey : itemsToRemove) - { - // Don't add to recycle bin here - // https://issues.apache.org/jira/browse/JCS-67 - performSingleKeyRemoval(fullKey); - removed = true; - // TODO this needs to update the remove count separately - } - - return removed; - } - - /** - * Removes an individual key from the cache. - *

- * This operates under a lock obtained in doRemove(). - *

- * - * @param key - * @return true if an item was removed. - */ - private boolean performSingleKeyRemoval(K key) - { - boolean removed; - // remove single item. - IndexedDiskElementDescriptor ded = keyHash.remove(key); - removed = ded != null; - addToRecycleBin(ded); - - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Disk removal: Removed from key hash, key [" + key + "] removed = " + removed); - } - return removed; - } - - /** - * Remove all the items from the disk cache by reseting everything. - */ - @Override - public void processRemoveAll() - { - ICacheEvent cacheEvent = createICacheEvent(getCacheName(), "all", ICacheEventLogger.REMOVEALL_EVENT); - try - { - reset(); - } - finally - { - logICacheEvent(cacheEvent); - } - } - - /** - * Reset effectively clears the disk cache, creating new files, recycle bins, and keymaps. - *

- * It can be used to handle errors by last resort, force content update, or removeall. - */ - private void reset() - { - if (log.isWarnEnabled()) - { - log.warn(logCacheName + "Resetting cache"); - } - - try - { - storageLock.writeLock().lock(); - - if (dataFile != null) - { - dataFile.close(); - } - File dataFileTemp = new File(rafDir, fileName + ".data"); - boolean result = dataFileTemp.delete(); - if (!result && log.isDebugEnabled()) - { - log.debug("Could not delete file " + dataFileTemp); - } - - if (keyFile != null) - { - keyFile.close(); - } - File keyFileTemp = new File(rafDir, fileName + ".key"); - result = keyFileTemp.delete(); - if (!result && log.isDebugEnabled()) - { - log.debug("Could not delete file " + keyFileTemp); - } - - dataFile = new IndexedDisk(new File(rafDir, fileName + ".data"), getElementSerializer()); - keyFile = new IndexedDisk(new File(rafDir, fileName + ".key"), getElementSerializer()); - - initializeRecycleBin(); - - initializeKeyMap(); - } - catch (IOException e) - { - log.error(logCacheName + "Failure reseting state", e); - } - finally - { - storageLock.writeLock().unlock(); - } - } - - /** - * If the maxKeySize is < 0, use 5000, no way to have an unlimited recycle bin right now, or one - * less than the mazKeySize. - */ - private void initializeRecycleBin() - { - recycle = new ConcurrentSkipListSet(); - } - - /** - * Create the map for keys that contain the index position on disk. - */ - private void initializeKeyMap() - { - keyHash = null; - if (maxKeySize >= 0) - { - if (this.diskLimitType == DiskLimitType.COUNT) - { - keyHash = new LRUMapCountLimited(maxKeySize); - } - else - { - keyHash = new LRUMapSizeLimited(maxKeySize); - } - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Set maxKeySize to: '" + maxKeySize + "'"); - } - } - else - { - // If no max size, use a plain map for memory and processing efficiency. - keyHash = new HashMap(); - // keyHash = Collections.synchronizedMap( new HashMap() ); - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Set maxKeySize to unlimited'"); - } - } - } - - /** - * Dispose of the disk cache in a background thread. Joins against this thread to put a cap on - * the disposal time. - *

- * TODO make dispose window configurable. - */ - @Override - public void processDispose() - { - ICacheEvent cacheEvent = createICacheEvent(getCacheName(), "none", ICacheEventLogger.DISPOSE_EVENT); - try - { - Runnable disR = new Runnable() - { - @Override - public void run() - { - disposeInternal(); - } - }; - Thread t = new Thread(disR, "IndexedDiskCache-DisposalThread"); - t.start(); - // wait up to 60 seconds for dispose and then quit if not done. - try - { - t.join(60 * 1000); - } - catch (InterruptedException ex) - { - log.error(logCacheName + "Interrupted while waiting for disposal thread to finish.", ex); - } - } - finally - { - logICacheEvent(cacheEvent); - } - } - - /** - * Internal method that handles the disposal. - */ - protected void disposeInternal() - { - if (!isAlive()) - { - log.error(logCacheName + "Not alive and dispose was called, filename: " + fileName); - return; - } - - // Prevents any interaction with the cache while we're shutting down. - setAlive(false); - - Thread optimizationThread = currentOptimizationThread; - if (isRealTimeOptimizationEnabled && optimizationThread != null) - { - // Join with the current optimization thread. - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "In dispose, optimization already " + "in progress; waiting for completion."); - } - try - { - optimizationThread.join(); - } - catch (InterruptedException e) - { - log.error(logCacheName + "Unable to join current optimization thread.", e); - } - } - else if (isShutdownOptimizationEnabled && this.getBytesFree() > 0) - { - optimizeFile(); - } - - saveKeys(); - - try - { - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Closing files, base filename: " + fileName); - } - dataFile.close(); - dataFile = null; - keyFile.close(); - keyFile = null; - } - catch (IOException e) - { - log.error(logCacheName + "Failure closing files in dispose, filename: " + fileName, e); - } - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Shutdown complete."); - } - } - - /** - * Add descriptor to recycle bin if it is not null. Adds the length of the item to the bytes - * free. - *

- * This is called in three places: (1) When an item is removed. All item removals funnel down to the removeSingleItem method. - * (2) When an item on disk is updated with a value that will not fit in the previous slot. (3) When the max key size is - * reached, the freed slot will be added. - *

- * - * @param ded - */ - protected void addToRecycleBin(IndexedDiskElementDescriptor ded) - { - // reuse the spot - if (ded != null) - { - storageLock.readLock().lock(); - - try - { - this.adjustBytesFree(ded, true); - - if (doRecycle) - { - recycle.add(ded); - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "recycled ded" + ded); - } - - } - } - finally - { - storageLock.readLock().unlock(); - } - } - } - - /** - * Performs the check for optimization, and if it is required, do it. - */ - protected void doOptimizeRealTime() - { - if (isRealTimeOptimizationEnabled && !isOptimizing && removeCount++ >= cattr.getOptimizeAtRemoveCount()) - { - isOptimizing = true; - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Optimizing file. removeCount [" + removeCount + "] OptimizeAtRemoveCount [" - + cattr.getOptimizeAtRemoveCount() + "]"); - } - - if (currentOptimizationThread == null) - { - storageLock.writeLock().lock(); - - try - { - if (currentOptimizationThread == null) - { - currentOptimizationThread = new Thread(new Runnable() - { - @Override - public void run() - { - optimizeFile(); - - currentOptimizationThread = null; - } - }, "IndexedDiskCache-OptimizationThread"); - } - } - finally - { - storageLock.writeLock().unlock(); - } - - if (currentOptimizationThread != null) - { - currentOptimizationThread.start(); - } - } - } - } - - /** - * File optimization is handled by this method. It works as follows: - *

    - *
  1. Shutdown recycling and turn on queuing of puts.
  2. - *
  3. Take a snapshot of the current descriptors. If there are any removes, ignore them, as they will be compacted during the - * next optimization.
  4. - *
  5. Optimize the snapshot. For each descriptor: - *
      - *
    1. Obtain the write-lock.
    2. - *
    3. Shift the element on the disk, in order to compact out the free space.
    4. - *
    5. Release the write-lock. This allows elements to still be accessible during optimization.
    6. - *
    - *
  6. - *
  7. Obtain the write-lock.
  8. - *
  9. All queued puts are made at the end of the file. Optimize these under a single write-lock.
  10. - *
  11. Truncate the file.
  12. - *
  13. Release the write-lock.
  14. - *
  15. Restore system to standard operation.
  16. - *
- */ - protected void optimizeFile() - { - ElapsedTimer timer = new ElapsedTimer(); - timesOptimized++; - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Beginning Optimization #" + timesOptimized); - } - - // CREATE SNAPSHOT - IndexedDiskElementDescriptor[] defragList = null; - - storageLock.writeLock().lock(); - - try - { - queueInput = true; - // shut off recycle while we're optimizing, - doRecycle = false; - defragList = createPositionSortedDescriptorList(); - } - finally - { - // Release if I acquired. - storageLock.writeLock().unlock(); - } - - // Defrag the file outside of the write lock. This allows a move to be made, - // and yet have the element still accessible for reading or writing. - long expectedNextPos = defragFile(defragList, 0); - - // ADD THE QUEUED ITEMS to the end and then truncate - storageLock.writeLock().lock(); - - try - { - try - { - if (!queuedPutList.isEmpty()) - { - defragList = queuedPutList.toArray(new IndexedDiskElementDescriptor[queuedPutList.size()]); - - // pack them at the end - expectedNextPos = defragFile(defragList, expectedNextPos); - } - // TRUNCATE THE FILE - dataFile.truncate(expectedNextPos); - } - catch (IOException e) - { - log.error(logCacheName + "Error optimizing queued puts.", e); - } - - // RESTORE NORMAL OPERATION - removeCount = 0; - resetBytesFree(); - initializeRecycleBin(); - queuedPutList.clear(); - queueInput = false; - // turn recycle back on. - doRecycle = true; - isOptimizing = false; - } - finally - { - storageLock.writeLock().unlock(); - } - - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Finished #" + timesOptimized + " Optimization took " + timer.getElapsedTimeString()); - } - } - - /** - * Defragments the file in place by compacting out the free space (i.e., moving records - * forward). If there were no gaps the resulting file would be the same size as the previous - * file. This must be supplied an ordered defragList. - *

- * - * @param defragList - * sorted list of descriptors for optimization - * @param startingPos - * the start position in the file - * @return this is the potential new file end - */ - private long defragFile(IndexedDiskElementDescriptor[] defragList, long startingPos) - { - ElapsedTimer timer = new ElapsedTimer(); - long preFileSize = 0; - long postFileSize = 0; - long expectedNextPos = 0; - try - { - preFileSize = this.dataFile.length(); - // find the first gap in the disk and start defragging. - expectedNextPos = startingPos; - for (int i = 0; i < defragList.length; i++) - { - storageLock.writeLock().lock(); - try - { - if (expectedNextPos != defragList[i].pos) - { - dataFile.move(defragList[i], expectedNextPos); - } - expectedNextPos = defragList[i].pos + IndexedDisk.HEADER_SIZE_BYTES + defragList[i].len; - } - finally - { - storageLock.writeLock().unlock(); - } - } - - postFileSize = this.dataFile.length(); - - // this is the potential new file end - return expectedNextPos; - } - catch (IOException e) - { - log.error(logCacheName + "Error occurred during defragmentation.", e); - } - finally - { - if (log.isInfoEnabled()) - { - log.info(logCacheName + "Defragmentation took " + timer.getElapsedTimeString() + ". File Size (before=" - + preFileSize + ") (after=" + postFileSize + ") (truncating to " + expectedNextPos + ")"); - } - } - - return 0; - } - - /** - * Creates a snapshot of the IndexedDiskElementDescriptors in the keyHash and returns them - * sorted by position in the dataFile. - *

- * TODO fix values() method on the LRU map. - *

- * - * @return IndexedDiskElementDescriptor[] - */ - private IndexedDiskElementDescriptor[] createPositionSortedDescriptorList() - { - IndexedDiskElementDescriptor[] defragList = new IndexedDiskElementDescriptor[keyHash.size()]; - Iterator> iterator = keyHash.entrySet().iterator(); - for (int i = 0; iterator.hasNext(); i++) - { - Map.Entry next = iterator.next(); - defragList[i] = next.getValue(); - } - - Arrays.sort(defragList, new PositionComparator()); - - return defragList; - } - - /** - * Returns the current cache size. - *

- * - * @return The size value - */ - @Override - public int getSize() - { - return keyHash.size(); - } - - /** - * Returns the size of the recycle bin in number of elements. - *

- * - * @return The number of items in the bin. - */ - protected int getRecyleBinSize() - { - return this.recycle.size(); - } - - /** - * Returns the number of times we have used spots from the recycle bin. - *

- * - * @return The number of spots used. - */ - protected int getRecyleCount() - { - return this.recycleCnt; - } - - /** - * Returns the number of bytes that are free. When an item is removed, its length is recorded. - * When a spot is used form the recycle bin, the length of the item stored is recorded. - *

- * - * @return The number bytes free on the disk file. - */ - protected long getBytesFree() - { - return this.bytesFree.get(); - } - - /** - * Resets the number of bytes that are free. - */ - private void resetBytesFree() - { - this.bytesFree.set(0); - } - - /** - * To subtract you can pass in false for add.. - *

- * - * @param ded - * @param add - */ - private void adjustBytesFree(IndexedDiskElementDescriptor ded, boolean add) - { - if (ded != null) - { - int amount = ded.len + IndexedDisk.HEADER_SIZE_BYTES; - - if (add) - { - this.bytesFree.addAndGet(amount); - } - else - { - this.bytesFree.addAndGet(-amount); - } - } - } - - /** - * This is for debugging and testing. - *

- * - * @return the length of the data file. - * @throws IOException - */ - protected long getDataFileSize() throws IOException - { - long size = 0; - - storageLock.readLock().lock(); - - try - { - if (dataFile != null) - { - size = dataFile.length(); - } - } - finally - { - storageLock.readLock().unlock(); - } - - return size; - } - - /** - * For debugging. This dumps the values by default. - */ - public void dump() - { - dump(true); - } - - /** - * For debugging. - *

- * - * @param dumpValues - * A boolean indicating if values should be dumped. - */ - public void dump(boolean dumpValues) - { - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "[dump] Number of keys: " + keyHash.size()); - - for (Map.Entry e : keyHash.entrySet()) - { - K key = e.getKey(); - IndexedDiskElementDescriptor ded = e.getValue(); - - log.debug(logCacheName + "[dump] Disk element, key: " + key + ", pos: " + ded.pos + ", ded.len" + ded.len - + (dumpValues ? ", val: " + get(key) : "")); - } - } - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return this.cattr; - } - - /** - * Returns info about the disk cache. - *

- * - * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getStatistics() - */ - @Override - public synchronized IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName("Indexed Disk Cache"); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement("Is Alive", Boolean.valueOf(isAlive()))); - elems.add(new StatElement("Key Map Size", Integer.valueOf(this.keyHash != null ? this.keyHash.size() : -1))); - try - { - elems - .add(new StatElement("Data File Length", Long.valueOf(this.dataFile != null ? this.dataFile.length() : -1L))); - } - catch (IOException e) - { - log.error(e); - } - elems.add(new StatElement("Max Key Size", this.maxKeySize)); - elems.add(new StatElement("Hit Count", this.hitCount)); - elems.add(new StatElement("Bytes Free", this.bytesFree)); - elems.add(new StatElement("Optimize Operation Count", Integer.valueOf(this.removeCount))); - elems.add(new StatElement("Times Optimized", Integer.valueOf(this.timesOptimized))); - elems.add(new StatElement("Recycle Count", Integer.valueOf(this.recycleCnt))); - elems.add(new StatElement("Recycle Bin Size", Integer.valueOf(this.recycle.size()))); - elems.add(new StatElement("Startup Size", Integer.valueOf(this.startupSize))); - - // get the stats from the super too - IStats sStats = super.getStatistics(); - elems.addAll(sStats.getStatElements()); - - stats.setStatElements(elems); - - return stats; - } - - /** - * This is exposed for testing. - *

- * - * @return Returns the timesOptimized. - */ - protected int getTimesOptimized() - { - return timesOptimized; - } - - /** - * This is used by the event logging. - *

- * - * @return the location of the disk, either path or ip. - */ - @Override - protected String getDiskLocation() - { - return dataFile.getFilePath(); - } - - /** - * Compares IndexedDiskElementDescriptor based on their position. - *

- */ - protected static final class PositionComparator implements Comparator, Serializable - { - /** serialVersionUID */ - private static final long serialVersionUID = -8387365338590814113L; - - /** - * Compares two descriptors based on position. - *

- * - * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) - */ - @Override - public int compare(IndexedDiskElementDescriptor ded1, IndexedDiskElementDescriptor ded2) - { - if (ded1.pos < ded2.pos) - { - return -1; - } - else if (ded1.pos == ded2.pos) - { - return 0; - } - else - { - return 1; - } - } - } - - /** - * Class for recycling and lru. This implements the LRU overflow callback, so we can add items - * to the recycle bin. This class counts the size element to decide, when to throw away an element - */ - public class LRUMapSizeLimited extends AbstractLRUMap - { - /** - * tag tells us which map we are working on. - */ - public static final String TAG = "orig"; - - // size of the content in kB - private AtomicInteger contentSize; - private int maxSize; - - /** - * Default - */ - public LRUMapSizeLimited() - { - this(-1); - } - - /** - * @param maxKeySize - */ - public LRUMapSizeLimited(int maxKeySize) - { - super(); - this.maxSize = maxKeySize; - this.contentSize = new AtomicInteger(0); - } - - // keep the content size in kB, so 2^31 kB is reasonable value - private void subLengthFromCacheSize(IndexedDiskElementDescriptor value) - { - contentSize.addAndGet((value.len + IndexedDisk.HEADER_SIZE_BYTES) / -1024 - 1); - } - - // keep the content size in kB, so 2^31 kB is reasonable value - private void addLengthToCacheSize(IndexedDiskElementDescriptor value) - { - contentSize.addAndGet((value.len + IndexedDisk.HEADER_SIZE_BYTES) / 1024 + 1); - } - - @Override - public IndexedDiskElementDescriptor put(K key, IndexedDiskElementDescriptor value) - { - IndexedDiskElementDescriptor oldValue = null; - - try - { - oldValue = super.put(key, value); - } - finally - { - // keep the content size in kB, so 2^31 kB is reasonable value - if (value != null) - { - addLengthToCacheSize(value); - } - if (oldValue != null) - { - subLengthFromCacheSize(oldValue); - } - } - - return oldValue; - } - - @Override - public IndexedDiskElementDescriptor remove(Object key) - { - IndexedDiskElementDescriptor value = null; - - try - { - value = super.remove(key); - return value; - } - finally - { - if (value != null) - { - subLengthFromCacheSize(value); - } - } - } - - /** - * This is called when the may key size is reached. The least recently used item will be - * passed here. We will store the position and size of the spot on disk in the recycle bin. - *

- * - * @param key - * @param value - */ - @Override - protected void processRemovedLRU(K key, IndexedDiskElementDescriptor value) - { - if (value != null) - { - subLengthFromCacheSize(value); - } - - addToRecycleBin(value); - - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Removing key: [" + key + "] from key store."); - log.debug(logCacheName + "Key store size: [" + this.size() + "]."); - } - - doOptimizeRealTime(); - } - - @Override - protected boolean shouldRemove() - { - return maxSize > 0 && contentSize.get() > maxSize && this.size() > 0; - } - } - - /** - * Class for recycling and lru. This implements the LRU overflow callback, so we can add items - * to the recycle bin. This class counts the elements to decide, when to throw away an element - */ - - public class LRUMapCountLimited extends LRUMap - // implements Serializable - { - public LRUMapCountLimited(int maxKeySize) - { - super(maxKeySize); - } - - /** - * This is called when the may key size is reached. The least recently used item will be - * passed here. We will store the position and size of the spot on disk in the recycle bin. - *

- * - * @param key - * @param value - */ - @Override - protected void processRemovedLRU(K key, IndexedDiskElementDescriptor value) - { - addToRecycleBin(value); - if (log.isDebugEnabled()) - { - log.debug(logCacheName + "Removing key: [" + key + "] from key store."); - log.debug(logCacheName + "Key store size: [" + this.size() + "]."); - } - - doOptimizeRealTime(); - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java deleted file mode 100644 index fffaadbe1e5..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.indexed; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCacheAttributes; - -/** - * Configuration class for the Indexed Disk Cache - */ -public class IndexedDiskCacheAttributes - extends AbstractDiskCacheAttributes -{ - /** Don't change. */ - private static final long serialVersionUID = -2190863599358782950L; - - /** default value */ - private static final int DEFAULT_maxKeySize = 5000; - - /** -1 means no limit. */ - private int maxKeySize = DEFAULT_maxKeySize; - - /** default to -1, i.e., don't optimize until shutdown */ - private int optimizeAtRemoveCount = -1; - - /** Should we optimize on shutdown. */ - public static final boolean DEFAULT_OPTIMIZE_ON_SHUTDOWN = true; - - /** Should we optimize on shutdown. */ - private boolean optimizeOnShutdown = DEFAULT_OPTIMIZE_ON_SHUTDOWN; - - /** Should we clear the disk on startup. */ - public static final boolean DEFAULT_CLEAR_DISK_ON_STARTUP = false; - - /** Should we clear the disk on startup. If true the contents of disk are cleared. */ - private boolean clearDiskOnStartup = DEFAULT_CLEAR_DISK_ON_STARTUP; - - /** - * Constructor for the DiskCacheAttributes object - */ - public IndexedDiskCacheAttributes() - { - super(); - } - - /** - * Gets the maxKeySize attribute of the DiskCacheAttributes object - *

- * @return The maxKeySize value - */ - public int getMaxKeySize() - { - return this.maxKeySize; - } - - /** - * Sets the maxKeySize attribute of the DiskCacheAttributes object - *

- * @param maxKeySize The new maxKeySize value - */ - public void setMaxKeySize( int maxKeySize ) - { - this.maxKeySize = maxKeySize; - } - - /** - * Gets the optimizeAtRemoveCount attribute of the DiskCacheAttributes object - *

- * @return The optimizeAtRemoveCount value - */ - public int getOptimizeAtRemoveCount() - { - return this.optimizeAtRemoveCount; - } - - /** - * Sets the optimizeAtRemoveCount attribute of the DiskCacheAttributes object This number - * determines how often the disk cache should run real time optimizations. - *

- * @param cnt The new optimizeAtRemoveCount value - */ - public void setOptimizeAtRemoveCount( int cnt ) - { - this.optimizeAtRemoveCount = cnt; - } - - /** - * @param optimizeOnShutdown The optimizeOnShutdown to set. - */ - public void setOptimizeOnShutdown( boolean optimizeOnShutdown ) - { - this.optimizeOnShutdown = optimizeOnShutdown; - } - - /** - * @return Returns the optimizeOnShutdown. - */ - public boolean isOptimizeOnShutdown() - { - return optimizeOnShutdown; - } - - /** - * @param clearDiskOnStartup the clearDiskOnStartup to set - */ - public void setClearDiskOnStartup( boolean clearDiskOnStartup ) - { - this.clearDiskOnStartup = clearDiskOnStartup; - } - - /** - * @return the clearDiskOnStartup - */ - public boolean isClearDiskOnStartup() - { - return clearDiskOnStartup; - } - - /** - * Write out the values for debugging purposes. - *

- * @return String - */ - @Override - public String toString() - { - StringBuilder str = new StringBuilder(); - str.append( "IndexedDiskCacheAttributes " ); - str.append( "\n diskPath = " + super.getDiskPath() ); - str.append( "\n maxPurgatorySize = " + super.getMaxPurgatorySize() ); - str.append( "\n maxKeySize = " + maxKeySize ); - str.append( "\n optimizeAtRemoveCount = " + optimizeAtRemoveCount ); - str.append( "\n shutdownSpoolTimeLimit = " + super.getShutdownSpoolTimeLimit() ); - str.append( "\n optimizeOnShutdown = " + optimizeOnShutdown ); - str.append( "\n clearDiskOnStartup = " + clearDiskOnStartup ); - return str.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheFactory.java deleted file mode 100644 index 03f2f1036a7..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.indexed; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Creates disk cache instances. - */ -public class IndexedDiskCacheFactory - extends AbstractAuxiliaryCacheFactory -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( IndexedDiskCacheFactory.class ); - - /** - * Create an instance of an IndexedDiskCache. - *

- * @param iaca cache attributes of this cache instance - * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is - * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier to - * test. - * @param cacheEventLogger - * @param elementSerializer - * @return IndexedDiskCache - */ - @Override - public IndexedDiskCache createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - { - IndexedDiskCacheAttributes idca = (IndexedDiskCacheAttributes) iaca; - if ( log.isDebugEnabled() ) - { - log.debug( "Creating DiskCache for attributes = " + idca ); - } - - IndexedDiskCache cache = new IndexedDiskCache( idca, elementSerializer ); - cache.setCacheEventLogger( cacheEventLogger ); - - return cache; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskDumper.java b/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskDumper.java deleted file mode 100644 index 94d9cfe5b9d..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskDumper.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.indexed; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - - -/** - * Used to dump out a Disk cache from disk for debugging. This is meant to be - * run as a command line utility for - */ -public class IndexedDiskDumper -{ - /** - * The main program for the DiskDumper class - *

- * Creates a disk cache and then calls dump, which write out the contents to - * a debug log. - *

- * @param args - * The command line arguments - */ - public static void main( String[] args ) - { - if ( args.length != 1 ) - { - System.out.println( "Usage: java org.apache.commons.jcs.auxiliary.disk.DiskDump " ); - System.exit( 0 ); - } - - IndexedDiskCacheAttributes attr = new IndexedDiskCacheAttributes(); - - attr.setCacheName( args[0] ); - attr.setDiskPath( args[0] ); - - IndexedDiskCache dc = new IndexedDiskCache( attr ); - dc.dump( true ); - System.exit( 0 ); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java b/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java deleted file mode 100644 index 5f5af18d6f5..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.indexed; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * Disk objects are located by descriptor entries. These are saved on shutdown and loaded into - * memory on startup. - */ -public class IndexedDiskElementDescriptor - implements Serializable, Comparable -{ - /** Don't change */ - private static final long serialVersionUID = -3029163572847659450L; - - /** Position of the cache data entry on disk. */ - long pos; - - /** Number of bytes the serialized form of the cache data takes. */ - int len; - - /** - * Constructs a usable disk element descriptor. - *

- * @param pos - * @param len - */ - public IndexedDiskElementDescriptor( long pos, int len ) - { - this.pos = pos; - this.len = len; - } - - /** - * @return debug string - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "[DED: " ); - buf.append( " pos = " + pos ); - buf.append( " len = " + len ); - buf.append( "]" ); - return buf.toString(); - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() - { - return Long.valueOf(this.pos).hashCode() ^ Integer.valueOf(len).hashCode(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object o) - { - if (o == null) - { - return false; - } - else if (o instanceof IndexedDiskElementDescriptor) - { - IndexedDiskElementDescriptor ided = (IndexedDiskElementDescriptor)o; - return pos == ided.pos && len == ided.len; - } - - return false; - } - - /** - * Compares based on length, then on pos descending. - *

- * @param o Object - * @return int - */ - @Override - public int compareTo( IndexedDiskElementDescriptor o ) - { - if ( o == null ) - { - return 1; - } - - if ( o.len == len ) - { - if ( o.pos == pos ) - { - return 0; - } - else if ( o.pos < pos ) - { - return -1; - } - else - { - return 1; - } - } - else if ( o.len > len ) - { - return -1; - } - else - { - return 1; - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java deleted file mode 100644 index 6330c33b3ae..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java +++ /dev/null @@ -1,1130 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.sql.DataSource; - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache; -import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory; -import org.apache.commons.jcs.engine.CacheConstants; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.jcs.utils.serialization.StandardSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This is the jdbc disk cache plugin. - *

- * It expects a table created by the following script. The table name is configurable. - *

- * - *

- *                       drop TABLE JCS_STORE;
- *                       CREATE TABLE JCS_STORE
- *                       (
- *                       CACHE_KEY                  VARCHAR(250)          NOT NULL,
- *                       REGION                     VARCHAR(250)          NOT NULL,
- *                       ELEMENT                    BLOB,
- *                       CREATE_TIME                TIMESTAMP,
- *                       UPDATE_TIME_SECONDS        BIGINT,
- *                       MAX_LIFE_SECONDS           BIGINT,
- *                       SYSTEM_EXPIRE_TIME_SECONDS BIGINT,
- *                       IS_ETERNAL                 CHAR(1),
- *                       PRIMARY KEY (CACHE_KEY, REGION)
- *                       );
- * 
- *

- * The cleanup thread will delete non eternal items where (now - create time) > max life seconds * - * 1000 - *

- * To speed up the deletion the SYSTEM_EXPIRE_TIME_SECONDS is used instead. It is recommended that - * an index be created on this column is you will have over a million records. - *

- * @author Aaron Smuts - */ -public class JDBCDiskCache - extends AbstractDiskCache -{ - /** The local logger. */ - private static final Log log = LogFactory.getLog( JDBCDiskCache.class ); - - /** custom serialization */ - private IElementSerializer elementSerializer = new StandardSerializer(); - - /** configuration */ - private JDBCDiskCacheAttributes jdbcDiskCacheAttributes; - - /** # of times update was called */ - private AtomicInteger updateCount = new AtomicInteger(0); - - /** # of times get was called */ - private AtomicInteger getCount = new AtomicInteger(0); - - /** # of times getMatching was called */ - private AtomicInteger getMatchingCount = new AtomicInteger(0); - - /** if count % interval == 0 then log */ - private static final int LOG_INTERVAL = 100; - - /** db connection pool */ - private DataSourceFactory dsFactory = null; - - /** tracks optimization */ - private TableState tableState; - - /** - * Constructs a JDBC Disk Cache for the provided cache attributes. The table state object is - * used to mark deletions. - *

- * @param cattr the configuration object for this cache - * @param dsFactory the DataSourceFactory for this cache - * @param tableState an object to track table operations - * @param compositeCacheManager the global cache manager - */ - public JDBCDiskCache( JDBCDiskCacheAttributes cattr, DataSourceFactory dsFactory, TableState tableState, - ICompositeCacheManager compositeCacheManager ) - { - super( cattr ); - - setTableState( tableState ); - setJdbcDiskCacheAttributes( cattr ); - - if ( log.isInfoEnabled() ) - { - log.info( "jdbcDiskCacheAttributes = " + getJdbcDiskCacheAttributes() ); - } - - // This initializes the pool access. - this.dsFactory = dsFactory; - - // Initialization finished successfully, so set alive to true. - setAlive(true); - } - - /** - * Inserts or updates. By default it will try to insert. If the item exists we will get an - * error. It will then update. This behavior is configurable. The cache can be configured to - * check before inserting. - *

- * @param ce - */ - @Override - protected void processUpdate( ICacheElement ce ) - { - updateCount.incrementAndGet(); - - if ( log.isDebugEnabled() ) - { - log.debug( "updating, ce = " + ce ); - } - - Connection con; - try - { - con = getDataSource().getConnection(); - } - catch ( SQLException e ) - { - log.error( "Problem getting connection.", e ); - return; - } - - try - { - if ( log.isDebugEnabled() ) - { - log.debug( "Putting [" + ce.getKey() + "] on disk." ); - } - - byte[] element; - - try - { - element = getElementSerializer().serialize( ce ); - } - catch ( IOException e ) - { - log.error( "Could not serialize element", e ); - return; - } - - insertOrUpdate( ce, con, element ); - } - finally - { - try - { - con.close(); - } - catch ( SQLException e ) - { - log.error( "Problem closing connection.", e ); - } - } - - if ( log.isInfoEnabled() ) - { - if ( updateCount.get() % LOG_INTERVAL == 0 ) - { - // TODO make a log stats method - log.info( "Update Count [" + updateCount + "]" ); - } - } - } - - /** - * If test before insert it true, we check to see if the element exists. If the element exists - * we will update. Otherwise, we try inserting. If this fails because the item exists, we will - * update. - *

- * @param ce - * @param con - * @param element - */ - private void insertOrUpdate( ICacheElement ce, Connection con, byte[] element ) - { - boolean exists = false; - - // First do a query to determine if the element already exists - if ( this.getJdbcDiskCacheAttributes().isTestBeforeInsert() ) - { - exists = doesElementExist( ce, con ); - } - - // If it doesn't exist, insert it, otherwise update - if ( !exists ) - { - exists = insertRow( ce, con, element ); - } - - // update if it exists. - if ( exists ) - { - updateRow( ce, con, element ); - } - } - - /** - * This inserts a new row in the database. - *

- * @param ce - * @param con - * @param element - * @return true if the insertion fails because the record exists. - */ - private boolean insertRow( ICacheElement ce, Connection con, byte[] element ) - { - boolean exists = false; - PreparedStatement psInsert = null; - - try - { - String sqlI = "insert into " - + getJdbcDiskCacheAttributes().getTableName() - + " (CACHE_KEY, REGION, ELEMENT, MAX_LIFE_SECONDS, IS_ETERNAL, CREATE_TIME, UPDATE_TIME_SECONDS, SYSTEM_EXPIRE_TIME_SECONDS) " - + " values (?, ?, ?, ?, ?, ?, ?, ?)"; - - psInsert = con.prepareStatement( sqlI ); - psInsert.setString( 1, (String) ce.getKey() ); - psInsert.setString( 2, this.getCacheName() ); - psInsert.setBytes( 3, element ); - psInsert.setLong( 4, ce.getElementAttributes().getMaxLife() ); - if ( ce.getElementAttributes().getIsEternal() ) - { - psInsert.setString( 5, "T" ); - } - else - { - psInsert.setString( 5, "F" ); - } - Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() ); - psInsert.setTimestamp( 6, createTime ); - - long now = System.currentTimeMillis() / 1000; - psInsert.setLong( 7, now ); - - long expireTime = now + ce.getElementAttributes().getMaxLife(); - psInsert.setLong( 8, expireTime ); - - psInsert.execute(); - } - catch ( SQLException e ) - { - if ("23000".equals(e.getSQLState())) - { - exists = true; - } - else - { - log.error( "Could not insert element", e ); - } - - // see if it exists, if we didn't already - if ( !exists && !this.getJdbcDiskCacheAttributes().isTestBeforeInsert() ) - { - exists = doesElementExist( ce, con ); - } - } - finally - { - if (psInsert != null) - { - try - { - psInsert.close(); - } - catch (SQLException e) - { - log.error( "Problem closing statement.", e ); - } - } - } - - return exists; - } - - /** - * This updates a row in the database. - *

- * @param ce - * @param con - * @param element - */ - private void updateRow( ICacheElement ce, Connection con, byte[] element ) - { - String sqlU = null; - PreparedStatement psUpdate = null; - - try - { - sqlU = "update " + getJdbcDiskCacheAttributes().getTableName() - + " set ELEMENT = ?, CREATE_TIME = ?, UPDATE_TIME_SECONDS = ?, " + " SYSTEM_EXPIRE_TIME_SECONDS = ? " - + " where CACHE_KEY = ? and REGION = ?"; - psUpdate = con.prepareStatement( sqlU ); - psUpdate.setBytes( 1, element ); - - Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() ); - psUpdate.setTimestamp( 2, createTime ); - - long now = System.currentTimeMillis() / 1000; - psUpdate.setLong( 3, now ); - - long expireTime = now + ce.getElementAttributes().getMaxLife(); - psUpdate.setLong( 4, expireTime ); - - psUpdate.setString( 5, (String) ce.getKey() ); - psUpdate.setString( 6, this.getCacheName() ); - psUpdate.execute(); - - if ( log.isDebugEnabled() ) - { - log.debug( "ran update " + sqlU ); - } - } - catch ( SQLException e2 ) - { - log.error( "e2 sql [" + sqlU + "] Exception: ", e2 ); - } - finally - { - if (psUpdate != null) - { - try - { - psUpdate.close(); - } - catch (SQLException e) - { - log.error( "Problem closing statement.", e ); - } - } - } - } - - /** - * Does an element exist for this key? - *

- * @param ce the cache element - * @param con a database connection - * @return boolean - */ - protected boolean doesElementExist( ICacheElement ce, Connection con ) - { - boolean exists = false; - PreparedStatement psSelect = null; - ResultSet rs = null; - - try - { - // don't select the element, since we want this to be fast. - String sqlS = "select CACHE_KEY from " + getJdbcDiskCacheAttributes().getTableName() - + " where REGION = ? and CACHE_KEY = ?"; - - psSelect = con.prepareStatement( sqlS ); - psSelect.setString( 1, this.getCacheName() ); - psSelect.setString( 2, (String) ce.getKey() ); - - rs = psSelect.executeQuery(); - - if ( rs.next() ) - { - exists = true; - } - - if ( log.isDebugEnabled() ) - { - log.debug( "[" + ce.getKey() + "] existing status is " + exists ); - } - } - catch ( SQLException e ) - { - log.error( "Problem looking for item before insert.", e ); - } - finally - { - try - { - if ( rs != null ) - { - rs.close(); - } - } - catch ( SQLException e ) - { - log.error( "Problem closing result set.", e ); - } - try - { - if ( psSelect != null ) - { - psSelect.close(); - } - } - catch ( SQLException e ) - { - log.error( "Problem closing statement.", e ); - } - } - - return exists; - } - - /** - * Queries the database for the value. If it gets a result, the value is deserialized. - *

- * @param key - * @return ICacheElement - * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#get(Object) - */ - @Override - protected ICacheElement processGet( K key ) - { - getCount.incrementAndGet(); - - if ( log.isDebugEnabled() ) - { - log.debug( "Getting [" + key + "] from disk" ); - } - - if ( !isAlive() ) - { - return null; - } - - ICacheElement obj = null; - - byte[] data = null; - try - { - // region, key - String selectString = "select ELEMENT from " + getJdbcDiskCacheAttributes().getTableName() - + " where REGION = ? and CACHE_KEY = ?"; - - Connection con = getDataSource().getConnection(); - try - { - PreparedStatement psSelect = null; - - try - { - psSelect = con.prepareStatement( selectString ); - psSelect.setString( 1, this.getCacheName() ); - psSelect.setString( 2, key.toString() ); - - ResultSet rs = psSelect.executeQuery(); - - try - { - if ( rs.next() ) - { - data = rs.getBytes( 1 ); - } - if ( data != null ) - { - try - { - // USE THE SERIALIZER - obj = getElementSerializer().deSerialize( data, null ); - } - catch ( IOException ioe ) - { - log.error( "Problem getting item for key [" + key + "]", ioe ); - } - catch ( Exception e ) - { - log.error( "Problem getting item for key [" + key + "]", e ); - } - } - } - finally - { - if ( rs != null ) - { - rs.close(); - } - } - } - finally - { - if ( psSelect != null ) - { - psSelect.close(); - } - } - } - finally - { - if ( con != null ) - { - con.close(); - } - } - } - catch ( SQLException sqle ) - { - log.error( "Caught a SQL exception trying to get the item for key [" + key + "]", sqle ); - } - - if ( log.isInfoEnabled() ) - { - if ( getCount.get() % LOG_INTERVAL == 0 ) - { - // TODO make a log stats method - log.info( "Get Count [" + getCount + "]" ); - } - } - return obj; - } - - /** - * This will run a like query. It will try to construct a usable query but different - * implementations will be needed to adjust the syntax. - *

- * @param pattern - * @return key,value map - */ - @Override - protected Map> processGetMatching( String pattern ) - { - getMatchingCount.incrementAndGet(); - - if ( log.isDebugEnabled() ) - { - log.debug( "Getting [" + pattern + "] from disk" ); - } - - if ( !isAlive() ) - { - return null; - } - - Map> results = new HashMap>(); - - try - { - // region, key - String selectString = "select CACHE_KEY, ELEMENT from " + getJdbcDiskCacheAttributes().getTableName() - + " where REGION = ? and CACHE_KEY like ?"; - - Connection con = getDataSource().getConnection(); - try - { - PreparedStatement psSelect = null; - try - { - psSelect = con.prepareStatement( selectString ); - psSelect.setString( 1, this.getCacheName() ); - psSelect.setString( 2, constructLikeParameterFromPattern( pattern ) ); - - ResultSet rs = psSelect.executeQuery(); - try - { - while ( rs.next() ) - { - String key = rs.getString( 1 ); - byte[] data = rs.getBytes( 2 ); - if ( data != null ) - { - try - { - // USE THE SERIALIZER - ICacheElement value = getElementSerializer().deSerialize( data, null ); - results.put( (K) key, value ); - } - catch ( IOException ioe ) - { - log.error( "Problem getting items for pattern [" + pattern + "]", ioe ); - } - catch ( Exception e ) - { - log.error( "Problem getting items for pattern [" + pattern + "]", e ); - } - } - } - } - finally - { - if ( rs != null ) - { - rs.close(); - } - } - } - finally - { - if ( psSelect != null ) - { - psSelect.close(); - } - } - } - finally - { - if ( con != null ) - { - con.close(); - } - } - } - catch ( SQLException sqle ) - { - log.error( "Caught a SQL exception trying to get items for pattern [" + pattern + "]", sqle ); - } - - if ( log.isInfoEnabled() ) - { - if ( getMatchingCount.get() % LOG_INTERVAL == 0 ) - { - // TODO make a log stats method - log.info( "Get Matching Count [" + getMatchingCount + "]" ); - } - } - return results; - } - - /** - * @param pattern - * @return String to use in the like query. - */ - public String constructLikeParameterFromPattern( String pattern ) - { - String likePattern = pattern.replaceAll( "\\.\\+", "%" ); - likePattern = likePattern.replaceAll( "\\.", "_" ); - - if ( log.isDebugEnabled() ) - { - log.debug( "pattern = [" + likePattern + "]" ); - } - - return likePattern; - } - - /** - * Returns true if the removal was successful; or false if there is nothing to remove. Current - * implementation always results in a disk orphan. - *

- * @param key - * @return boolean - */ - @Override - protected boolean processRemove( K key ) - { - // remove single item. - String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName() - + " where REGION = ? and CACHE_KEY = ?"; - - try - { - boolean partial = false; - if ( key instanceof String && key.toString().endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) ) - { - // remove all keys of the same name group. - sql = "delete from " + getJdbcDiskCacheAttributes().getTableName() - + " where REGION = ? and CACHE_KEY like ?"; - partial = true; - } - Connection con = getDataSource().getConnection(); - PreparedStatement psSelect = null; - try - { - psSelect = con.prepareStatement( sql ); - psSelect.setString( 1, this.getCacheName() ); - if ( partial ) - { - psSelect.setString( 2, key.toString() + "%" ); - } - else - { - psSelect.setString( 2, key.toString() ); - } - - psSelect.executeUpdate(); - - setAlive(true); - } - catch ( SQLException e ) - { - log.error( "Problem creating statement. sql [" + sql + "]", e ); - setAlive(false); - } - finally - { - try - { - if ( psSelect != null ) - { - psSelect.close(); - } - con.close(); - } - catch ( SQLException e1 ) - { - log.error( "Problem closing statement.", e1 ); - } - } - } - catch ( SQLException e ) - { - log.error( "Problem updating cache.", e ); - reset(); - } - return false; - } - - /** - * This should remove all elements. The auxiliary can be configured to forbid this behavior. If - * remove all is not allowed, the method balks. - */ - @Override - protected void processRemoveAll() - { - // it should never get here from the abstract disk cache. - if ( this.jdbcDiskCacheAttributes.isAllowRemoveAll() ) - { - try - { - String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName() + " where REGION = ?"; - Connection con = getDataSource().getConnection(); - PreparedStatement psDelete = null; - try - { - psDelete = con.prepareStatement( sql ); - psDelete.setString( 1, this.getCacheName() ); - setAlive(true); - psDelete.executeUpdate(); - } - catch ( SQLException e ) - { - log.error( "Problem creating statement.", e ); - setAlive(false); - } - finally - { - try - { - if ( psDelete != null ) - { - psDelete.close(); - } - con.close(); - } - catch ( SQLException e1 ) - { - log.error( "Problem closing statement.", e1 ); - } - } - } - catch ( Exception e ) - { - log.error( "Problem removing all.", e ); - reset(); - } - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "RemoveAll was requested but the request was not fulfilled: allowRemoveAll is set to false." ); - } - } - } - - /** - * Removed the expired. (now - create time) > max life seconds * 1000 - *

- * @return the number deleted - */ - protected int deleteExpired() - { - int deleted = 0; - - try - { - getTableState().setState( TableState.DELETE_RUNNING ); - - long now = System.currentTimeMillis() / 1000; - - // This is to slow when we push over a million records - // String sql = "delete from " + - // getJdbcDiskCacheAttributes().getTableName() + " where REGION = '" - // + this.getCacheName() + "' and IS_ETERNAL = 'F' and (" + now - // + " - UPDATE_TIME_SECONDS) > MAX_LIFE_SECONDS"; - - String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName() - + " where IS_ETERNAL = ? and REGION = ? and ? > SYSTEM_EXPIRE_TIME_SECONDS"; - - Connection con = getDataSource().getConnection(); - PreparedStatement psDelete = null; - try - { - psDelete = con.prepareStatement( sql ); - psDelete.setString( 1, "F" ); - psDelete.setString( 2, this.getCacheName() ); - psDelete.setLong( 3, now ); - - setAlive(true); - - deleted = psDelete.executeUpdate(); - } - catch ( SQLException e ) - { - log.error( "Problem creating statement.", e ); - setAlive(false); - } - finally - { - try - { - if ( psDelete != null ) - { - psDelete.close(); - } - con.close(); - } - catch ( SQLException e1 ) - { - log.error( "Problem closing statement.", e1 ); - } - } - logApplicationEvent( getAuxiliaryCacheAttributes().getName(), "deleteExpired", - "Deleted expired elements. URL: " + getDiskLocation() ); - } - catch ( Exception e ) - { - logError( getAuxiliaryCacheAttributes().getName(), "deleteExpired", e.getMessage() + " URL: " - + getDiskLocation() ); - log.error( "Problem removing expired elements from the table.", e ); - reset(); - } - finally - { - getTableState().setState( TableState.FREE ); - } - - return deleted; - } - - /** - * Typically this is used to handle errors by last resort, force content update, or removeall - */ - public void reset() - { - // nothing - } - - /** Shuts down the pool */ - @Override - public void processDispose() - { - ICacheEvent cacheEvent = createICacheEvent( getCacheName(), (K)"none", ICacheEventLogger.DISPOSE_EVENT ); - try - { - try - { - dsFactory.close(); - } - catch ( SQLException e ) - { - log.error( "Problem shutting down.", e ); - } - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Returns the current cache size. Just does a count(*) for the region. - *

- * @return The size value - */ - @Override - public int getSize() - { - int size = 0; - - // region, key - String selectString = "select count(*) from " + getJdbcDiskCacheAttributes().getTableName() - + " where REGION = ?"; - - Connection con; - try - { - con = getDataSource().getConnection(); - } - catch ( SQLException e ) - { - log.error( "Problem getting connection.", e ); - return size; - } - - try - { - PreparedStatement psSelect = null; - try - { - psSelect = con.prepareStatement( selectString ); - psSelect.setString( 1, this.getCacheName() ); - ResultSet rs = null; - - rs = psSelect.executeQuery(); - try - { - if ( rs.next() ) - { - size = rs.getInt( 1 ); - } - } - finally - { - if ( rs != null ) - { - rs.close(); - } - } - } - finally - { - if ( psSelect != null ) - { - psSelect.close(); - } - } - } - catch ( SQLException e ) - { - log.error( "Problem getting size.", e ); - } - finally - { - try - { - con.close(); - } - catch ( SQLException e ) - { - log.error( "Problem closing connection.", e ); - } - } - return size; - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - throw new UnsupportedOperationException( "Groups not implemented." ); - // return null; - } - - /** - * @param elementSerializer The elementSerializer to set. - */ - @Override - public void setElementSerializer( IElementSerializer elementSerializer ) - { - this.elementSerializer = elementSerializer; - } - - /** - * @return Returns the elementSerializer. - */ - @Override - public IElementSerializer getElementSerializer() - { - return elementSerializer; - } - - /** - * @param jdbcDiskCacheAttributes The jdbcDiskCacheAttributes to set. - */ - protected void setJdbcDiskCacheAttributes( JDBCDiskCacheAttributes jdbcDiskCacheAttributes ) - { - this.jdbcDiskCacheAttributes = jdbcDiskCacheAttributes; - } - - /** - * @return Returns the jdbcDiskCacheAttributes. - */ - protected JDBCDiskCacheAttributes getJdbcDiskCacheAttributes() - { - return jdbcDiskCacheAttributes; - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return this.getJdbcDiskCacheAttributes(); - } - - /** - * Extends the parent stats. - *

- * @return IStats - */ - @Override - public IStats getStatistics() - { - IStats stats = super.getStatistics(); - stats.setTypeName( "JDBC/Abstract Disk Cache" ); - - List> elems = stats.getStatElements(); - - elems.add(new StatElement( "Update Count", updateCount ) ); - elems.add(new StatElement( "Get Count", getCount ) ); - elems.add(new StatElement( "Get Matching Count", getMatchingCount ) ); - elems.add(new StatElement( "DB URL", getJdbcDiskCacheAttributes().getUrl()) ); - - stats.setStatElements( elems ); - - return stats; - } - - /** - * Returns the name of the table. - *

- * @return the table name or UNDEFINED - */ - protected String getTableName() - { - String name = "UNDEFINED"; - if ( this.getJdbcDiskCacheAttributes() != null ) - { - name = this.getJdbcDiskCacheAttributes().getTableName(); - } - return name; - } - - /** - * @param tableState The tableState to set. - */ - public void setTableState( TableState tableState ) - { - this.tableState = tableState; - } - - /** - * @return Returns the tableState. - */ - public TableState getTableState() - { - return tableState; - } - - /** - * This is used by the event logging. - *

- * @return the location of the disk, either path or ip. - */ - @Override - protected String getDiskLocation() - { - return this.jdbcDiskCacheAttributes.getUrl(); - } - - /** - * Public so managers can access it. - * @return the dsFactory - * @throws SQLException if getting a data source fails - */ - public DataSource getDataSource() throws SQLException - { - return dsFactory.getDataSource(); - } - - /** - * For debugging. - *

- * @return this.getStats(); - */ - @Override - public String toString() - { - return this.getStats(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java deleted file mode 100644 index d14202adee0..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java +++ /dev/null @@ -1,331 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCacheAttributes; - -/** - * The configurator will set these values based on what is in the cache.ccf file. - *

- * @author Aaron Smuts - */ -public class JDBCDiskCacheAttributes - extends AbstractDiskCacheAttributes -{ - /** Don't change */ - private static final long serialVersionUID = -6535808344813320062L; - - /** default */ - private static final String DEFAULT_TABLE_NAME = "JCS_STORE"; - - /** DB username */ - private String userName; - - /** DB password */ - private String password; - - /** URL for the db */ - private String url; - - /** The name of the database. */ - private String database = ""; - - /** The driver */ - private String driverClassName; - - /** The JNDI path. */ - private String jndiPath; - - /** The time between two JNDI lookups */ - private long jndiTTL = 0L; - - /** The table name */ - private String tableName = DEFAULT_TABLE_NAME; - - /** If false we will insert and if it fails we will update. */ - private boolean testBeforeInsert = true; - - /** This is the default limit on the maximum number of active connections. */ - public static final int DEFAULT_MAX_TOTAL = 10; - - /** Max connections allowed */ - private int maxTotal = DEFAULT_MAX_TOTAL; - - /** This is the default setting for the cleanup routine. */ - public static final int DEFAULT_SHRINKER_INTERVAL_SECONDS = 300; - - /** How often should we remove expired. */ - private int shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS; - - /** Should we remove expired in the background. */ - private boolean useDiskShrinker = true; - - /** The default Pool Name to which the connection pool will be keyed. */ - public static final String DEFAULT_POOL_NAME = "jcs"; - - /** - * If a pool name is supplied, the manager will attempt to load it. It should be configured in a - * separate section as follows. Assuming the name is "MyPool": - * - *

-     * jcs.jdbcconnectionpool.MyPool.attributes.userName=MyUserName
-     * jcs.jdbcconnectionpool.MyPool.attributes.password=MyPassword
-     * jcs.jdbcconnectionpool.MyPool.attributes.url=MyUrl
-     * jcs.jdbcconnectionpool.MyPool.attributes.maxActive=MyMaxActive
-     * jcs.jdbcconnectionpool.MyPool.attributes.driverClassName=MyDriverClassName
-     * 
- */ - private String connectionPoolName; - - /** - * @param userName The userName to set. - */ - public void setUserName( String userName ) - { - this.userName = userName; - } - - /** - * @return Returns the userName. - */ - public String getUserName() - { - return userName; - } - - /** - * @param password The password to set. - */ - public void setPassword( String password ) - { - this.password = password; - } - - /** - * @return Returns the password. - */ - public String getPassword() - { - return password; - } - - /** - * @param url The url to set. - */ - public void setUrl( String url ) - { - this.url = url; - } - - /** - * @return Returns the url. - */ - public String getUrl() - { - return url; - } - - /** - * This is appended to the url. - * @param database The database to set. - */ - public void setDatabase( String database ) - { - this.database = database; - } - - /** - * @return Returns the database. - */ - public String getDatabase() - { - return database; - } - - /** - * @param driverClassName The driverClassName to set. - */ - public void setDriverClassName( String driverClassName ) - { - this.driverClassName = driverClassName; - } - - /** - * @return Returns the driverClassName. - */ - public String getDriverClassName() - { - return driverClassName; - } - - /** - * @return the jndiPath - */ - public String getJndiPath() - { - return jndiPath; - } - - /** - * @param jndiPath the jndiPath to set - */ - public void setJndiPath(String jndiPath) - { - this.jndiPath = jndiPath; - } - - /** - * @return the jndiTTL - */ - public long getJndiTTL() - { - return jndiTTL; - } - - /** - * @param jndiTTL the jndiTTL to set - */ - public void setJndiTTL(long jndiTTL) - { - this.jndiTTL = jndiTTL; - } - - /** - * @param tableName The tableName to set. - */ - public void setTableName( String tableName ) - { - this.tableName = tableName; - } - - /** - * @return Returns the tableName. - */ - public String getTableName() - { - return tableName; - } - - /** - * If this is true then the disk cache will check to see if the item already exists in the - * database. If it is false, it will try to insert. If the insert fails it will try to update. - *

- * @param testBeforeInsert The testBeforeInsert to set. - */ - public void setTestBeforeInsert( boolean testBeforeInsert ) - { - this.testBeforeInsert = testBeforeInsert; - } - - /** - * @return Returns the testBeforeInsert. - */ - public boolean isTestBeforeInsert() - { - return testBeforeInsert; - } - - /** - * @param maxTotal The maxTotal to set. - */ - public void setMaxTotal( int maxActive ) - { - this.maxTotal = maxActive; - } - - /** - * @return Returns the maxTotal. - */ - public int getMaxTotal() - { - return maxTotal; - } - - /** - * @param shrinkerIntervalSecondsArg The shrinkerIntervalSeconds to set. - */ - public void setShrinkerIntervalSeconds( int shrinkerIntervalSecondsArg ) - { - this.shrinkerIntervalSeconds = shrinkerIntervalSecondsArg; - } - - /** - * @return Returns the shrinkerIntervalSeconds. - */ - public int getShrinkerIntervalSeconds() - { - return shrinkerIntervalSeconds; - } - - /** - * @param useDiskShrinker The useDiskShrinker to set. - */ - public void setUseDiskShrinker( boolean useDiskShrinker ) - { - this.useDiskShrinker = useDiskShrinker; - } - - /** - * @return Returns the useDiskShrinker. - */ - public boolean isUseDiskShrinker() - { - return useDiskShrinker; - } - - /** - * @param connectionPoolName the connectionPoolName to set - */ - public void setConnectionPoolName( String connectionPoolName ) - { - this.connectionPoolName = connectionPoolName; - } - - /** - * @return the connectionPoolName - */ - public String getConnectionPoolName() - { - return connectionPoolName; - } - - /** - * For debugging. - *

- * @return debug string with most of the properties. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nJDBCCacheAttributes" ); - buf.append( "\n UserName [" + getUserName() + "]" ); - buf.append( "\n Url [" + getUrl() + "]" ); - buf.append( "\n Database [" + getDatabase() + "]" ); - buf.append( "\n DriverClassName [" + getDriverClassName() + "]" ); - buf.append( "\n TableName [" + getTableName() + "]" ); - buf.append( "\n TestBeforeInsert [" + isTestBeforeInsert() + "]" ); - buf.append( "\n MaxActive [" + getMaxTotal() + "]" ); - buf.append( "\n AllowRemoveAll [" + isAllowRemoveAll() + "]" ); - buf.append( "\n ShrinkerIntervalSeconds [" + getShrinkerIntervalSeconds() + "]" ); - buf.append( "\n useDiskShrinker [" + isUseDiskShrinker() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java deleted file mode 100644 index ca8f0712755..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java +++ /dev/null @@ -1,294 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.SQLException; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory; -import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.JndiDataSourceFactory; -import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.behavior.IRequireScheduler; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.utils.config.PropertySetter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This factory should create JDBC auxiliary caches. - *

- * @author Aaron Smuts - */ -public class JDBCDiskCacheFactory - extends AbstractAuxiliaryCacheFactory - implements IRequireScheduler -{ - /** The logger */ - private static final Log log = LogFactory.getLog( JDBCDiskCacheFactory.class ); - - /** - * A map of TableState objects to table names. Each cache has a table state object, which is - * used to determine if any long processes such as deletes or optimizations are running. - */ - private ConcurrentMap tableStates; - - /** The background scheduler, one for all regions. Injected by the configurator */ - protected ScheduledExecutorService scheduler; - - /** - * A map of table name to shrinker threads. This allows each table to have a different setting. - * It assumes that there is only one jdbc disk cache auxiliary defined per table. - */ - private ConcurrentMap shrinkerThreadMap; - - /** Pool name to DataSourceFactories */ - private ConcurrentMap dsFactories; - - /** Lock to allow lengthy initialization of DataSourceFactories */ - private ReentrantLock dsFactoryLock; - - /** props prefix */ - protected static final String POOL_CONFIGURATION_PREFIX = "jcs.jdbcconnectionpool."; - - /** .attributes */ - protected static final String ATTRIBUTE_PREFIX = ".attributes"; - - /** - * This factory method should create an instance of the jdbc cache. - *

- * @param rawAttr specific cache configuration attributes - * @param compositeCacheManager the global cache manager - * @param cacheEventLogger a specific logger for cache events - * @param elementSerializer a serializer for cache elements - * @return JDBCDiskCache the cache instance - * @throws SQLException if the cache instance could not be created - */ - @Override - public JDBCDiskCache createCache( AuxiliaryCacheAttributes rawAttr, - ICompositeCacheManager compositeCacheManager, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - throws SQLException - { - JDBCDiskCacheAttributes cattr = (JDBCDiskCacheAttributes) rawAttr; - TableState tableState = getTableState( cattr.getTableName() ); - DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties()); - - JDBCDiskCache cache = new JDBCDiskCache( cattr, dsFactory, tableState, compositeCacheManager ); - cache.setCacheEventLogger( cacheEventLogger ); - cache.setElementSerializer( elementSerializer ); - - // create a shrinker if we need it. - createShrinkerWhenNeeded( cattr, cache ); - - return cache; - } - - /** - * Initialize this factory - */ - @Override - public void initialize() - { - super.initialize(); - this.tableStates = new ConcurrentHashMap(); - this.shrinkerThreadMap = new ConcurrentHashMap(); - this.dsFactories = new ConcurrentHashMap(); - this.dsFactoryLock = new ReentrantLock(); - } - - /** - * Dispose of this factory, clean up shared resources - */ - @Override - public void dispose() - { - this.tableStates.clear(); - - for (DataSourceFactory dsFactory : this.dsFactories.values()) - { - try - { - dsFactory.close(); - } - catch (SQLException e) - { - log.error("Could not close data source factory " + dsFactory.getName(), e); - } - } - - this.dsFactories.clear(); - this.shrinkerThreadMap.clear(); - super.dispose(); - } - - /** - * Get a table state for a given table name - * - * @param tableName - * @return a cached instance of the table state - */ - protected TableState getTableState(String tableName) - { - TableState newTableState = new TableState( tableName ); - TableState tableState = tableStates.putIfAbsent( tableName, newTableState ); - - if ( tableState == null ) - { - tableState = newTableState; - } - - return tableState; - } - - /** - * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) - */ - @Override - public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor) - { - this.scheduler = scheduledExecutor; - } - - /** - * Get the scheduler service - * - * @return the scheduler - */ - protected ScheduledExecutorService getScheduledExecutorService() - { - return scheduler; - } - - /** - * If UseDiskShrinker is true then we will create a shrinker daemon if necessary. - *

- * @param cattr - * @param raf - */ - protected void createShrinkerWhenNeeded( JDBCDiskCacheAttributes cattr, JDBCDiskCache raf ) - { - // add cache to shrinker. - if ( cattr.isUseDiskShrinker() ) - { - ScheduledExecutorService shrinkerService = getScheduledExecutorService(); - ShrinkerThread newShrinkerThread = new ShrinkerThread(); - ShrinkerThread shrinkerThread = shrinkerThreadMap.putIfAbsent( cattr.getTableName(), newShrinkerThread ); - - if ( shrinkerThread == null ) - { - shrinkerThread = newShrinkerThread; - - long intervalMillis = Math.max( 999, cattr.getShrinkerIntervalSeconds() * 1000 ); - if ( log.isInfoEnabled() ) - { - log.info( "Setting the shrinker to run every [" + intervalMillis + "] ms. for table [" - + cattr.getTableName() + "]" ); - } - shrinkerService.scheduleAtFixedRate(shrinkerThread, 0, intervalMillis, TimeUnit.MILLISECONDS); - } - - shrinkerThread.addDiskCacheToShrinkList( raf ); - } - } - - /** - * manages the DataSourceFactories. - *

- * @param cattr the cache configuration - * @param configProps the configuration properties object - * @return a DataSourceFactory - * @throws SQLException if a database access error occurs - */ - protected DataSourceFactory getDataSourceFactory( JDBCDiskCacheAttributes cattr, - Properties configProps ) throws SQLException - { - String poolName = null; - - if (cattr.getConnectionPoolName() == null) - { - poolName = cattr.getCacheName() + "." + JDBCDiskCacheAttributes.DEFAULT_POOL_NAME; - } - else - { - poolName = cattr.getConnectionPoolName(); - } - - - DataSourceFactory dsFactory = this.dsFactories.get(poolName); - - if (dsFactory == null) - { - dsFactoryLock.lock(); - - try - { - // double check - dsFactory = this.dsFactories.get(poolName); - - if (dsFactory == null) - { - JDBCDiskCacheAttributes dsConfig = null; - - if (cattr.getConnectionPoolName() == null) - { - dsConfig = cattr; - } - else - { - dsConfig = new JDBCDiskCacheAttributes(); - String dsConfigAttributePrefix = POOL_CONFIGURATION_PREFIX + poolName + ATTRIBUTE_PREFIX; - PropertySetter.setProperties( dsConfig, - configProps, - dsConfigAttributePrefix + "." ); - - dsConfig.setConnectionPoolName(poolName); - } - - if ( dsConfig.getJndiPath() != null ) - { - dsFactory = new JndiDataSourceFactory(); - } - else - { - dsFactory = new SharedPoolDataSourceFactory(); - } - - dsFactory.initialize(dsConfig); - this.dsFactories.put(poolName, dsFactory); - } - } - finally - { - dsFactoryLock.unlock(); - } - } - - return dsFactory; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/ShrinkerThread.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/ShrinkerThread.java deleted file mode 100644 index adcdb0eb312..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/ShrinkerThread.java +++ /dev/null @@ -1,169 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - * Calls delete expired on the disk caches. The shrinker is run by a clock daemon. The shrinker - * calls delete on each region. It pauses between calls. - *

- * @author Aaron Smuts - */ -public class ShrinkerThread - implements Runnable -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( ShrinkerThread.class ); - - /** A set of JDBCDiskCache objects to call deleteExpired on. */ - private final Set> shrinkSet = - Collections.synchronizedSet( new HashSet>() ); - - /** Default time period to use. */ - private static final long DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS = 5000; - - /** - * How long should we wait between calls to deleteExpired when we are iterating through the list - * of regions. Delete can lock the table. We want to give clients a chance to get some work - * done. - */ - private long pauseBetweenRegionCallsMillis = DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS; - - /** - * Does nothing special. - */ - protected ShrinkerThread() - { - super(); - } - - /** - * Adds a JDBC disk cache to the set of disk cache to shrink. - *

- * @param diskCache - */ - public void addDiskCacheToShrinkList( JDBCDiskCache diskCache ) - { - // the set will prevent dupes. - // we could also just add these to a hashmap by region name - // but that might cause a problem if you wanted to use two different - // jbdc disk caches for the same region. - shrinkSet.add( diskCache ); - } - - /** - * Calls deleteExpired on each item in the set. It pauses between each call. - */ - @Override - public void run() - { - try - { - deleteExpiredFromAllRegisteredRegions(); - } - catch ( Throwable e ) - { - log.error( "Caught an expcetion while trying to delete expired items.", e ); - } - } - - /** - * Deletes the expired items from all the registered regions. - */ - private void deleteExpiredFromAllRegisteredRegions() - { - if ( log.isInfoEnabled() ) - { - log.info( "Running JDBC disk cache shrinker. Number of regions [" + shrinkSet.size() + "]" ); - } - - Object[] caches = null; - - synchronized ( shrinkSet ) - { - caches = this.shrinkSet.toArray(); - } - - if ( caches != null ) - { - for ( int i = 0; i < caches.length; i++ ) - { - JDBCDiskCache cache = (JDBCDiskCache) caches[i]; - - long start = System.currentTimeMillis(); - int deleted = cache.deleteExpired(); - long end = System.currentTimeMillis(); - - if ( log.isInfoEnabled() ) - { - log.info( "Deleted [" + deleted + "] expired for region [" + cache.getCacheName() + "] for table [" - + cache.getTableName() + "] in " + ( end - start ) + " ms." ); - } - - // don't pause after the last call to delete expired. - if ( i < caches.length - 1 ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Pausing for [" + this.getPauseBetweenRegionCallsMillis() - + "] ms. before shrinking the next region." ); - } - - try - { - Thread.sleep( this.getPauseBetweenRegionCallsMillis() ); - } - catch ( InterruptedException e ) - { - log.warn( "Interrupted while waiting to delete expired for the next region." ); - } - } - } - } - } - - /** - * How long should we wait between calls to deleteExpired when we are iterating through the list - * of regions. - *

- * @param pauseBetweenRegionCallsMillis The pauseBetweenRegionCallsMillis to set. - */ - public void setPauseBetweenRegionCallsMillis( long pauseBetweenRegionCallsMillis ) - { - this.pauseBetweenRegionCallsMillis = pauseBetweenRegionCallsMillis; - } - - /** - * How long should we wait between calls to deleteExpired when we are iterating through the list - * of regions. - *

- * @return Returns the pauseBetweenRegionCallsMillis. - */ - public long getPauseBetweenRegionCallsMillis() - { - return pauseBetweenRegionCallsMillis; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/TableState.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/TableState.java deleted file mode 100644 index a8626609f97..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/TableState.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * This is used by various elements of the JDBC disk cache to indicate the - * status of a table. The MySQL disk cache, for instance, marks the status as - * optimizing when a scheduled optimization is taking place. This allows the - * cache to balk rather than block during long running optimizations. - *

- * @author Aaron Smuts - */ -public class TableState - implements Serializable -{ - /** Don't change. */ - private static final long serialVersionUID = -6625081552084964885L; - - /** Name of the table whose state this reflects. */ - private String tableName; - - /** - * The table is free. It can be accessed and no potentially table locking - * jobs are running. - */ - public static final int FREE = 0; - - /** A potentially table locking deletion is running */ - public static final int DELETE_RUNNING = 1; - - /** A table locking optimization is running. */ - public static final int OPTIMIZATION_RUNNING = 2; - - /** we might want to add error */ - private int state = FREE; - - /** - * Construct a usable table state. - *

- * @param tableName - */ - public TableState( String tableName ) - { - this.setTableName( tableName ); - } - - /** - * @param tableName - * The tableName to set. - */ - public void setTableName( String tableName ) - { - this.tableName = tableName; - } - - /** - * @return Returns the tableName. - */ - public String getTableName() - { - return tableName; - } - - /** - * @param state - * The state to set. - */ - public void setState( int state ) - { - this.state = state; - } - - /** - * @return Returns the state. - */ - public int getState() - { - return state; - } - - /** - * Write out the values for debugging purposes. - *

- * @return String - */ - @Override - public String toString() - { - StringBuilder str = new StringBuilder(); - str.append( "TableState " ); - str.append( "\n TableName = " + getTableName() ); - str.append( "\n State = " + getState() ); - return str.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java deleted file mode 100644 index 73b57e1c631..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.SQLException; - -import javax.sql.DataSource; - -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; - - -/** - * A factory that returns a DataSource. - * Borrowed from Apache DB Torque - * - * @author John McNally - * @author Thomas Fischer - * @version $Id: DataSourceFactory.java 1336091 2012-05-09 11:09:40Z tfischer $ - */ -public interface DataSourceFactory -{ - /** - * Key for the configuration which contains DataSourceFactories - */ - String DSFACTORY_KEY = "dsfactory"; - - /** - * Key for the configuration which contains the fully qualified name - * of the factory implementation class - */ - String FACTORY_KEY = "factory"; - - /** - * @return the name of the factory. - */ - String getName(); - - /** - * @return the DataSource configured by the factory. - * @throws SQLException if the source can't be returned - */ - DataSource getDataSource() throws SQLException; - - /** - * Initialize the factory. - * - * @param config the factory settings - * @throws SQLException Any exceptions caught during processing will be - * rethrown wrapped into a SQLException. - */ - void initialize(JDBCDiskCacheAttributes config) - throws SQLException; - - /** - * A hook which is called when the resources of the associated DataSource - * can be released. - * After close() is called, the other methods may not work any more - * (e.g. getDataSource() might return null). - * It is not guaranteed that this method does anything. For example, - * we do not want to close connections retrieved via JNDI, so the - * JndiDataSouurceFactory does not close these connections - * - * @throws SQLException Any exceptions caught during processing will be - * rethrown wrapped into a SQLException. - */ - void close() - throws SQLException; -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java deleted file mode 100644 index 517db18e97e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java +++ /dev/null @@ -1,185 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.SQLException; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; - -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.sql.DataSource; - -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A factory that looks up the DataSource from JNDI. It is also able - * to deploy the DataSource based on properties found in the - * configuration. - * - * This factory tries to avoid excessive context lookups to improve speed. - * The time between two lookups can be configured. The default is 0 (no cache). - * - * Borrowed and adapted from Apache DB Torque - * - * @author John McNally - * @author Thomas Vandahl - */ -public class JndiDataSourceFactory implements DataSourceFactory -{ - /** The log. */ - private static Log log = LogFactory.getLog(JndiDataSourceFactory.class); - - /** The name of the factory. */ - private String name; - - /** The path to get the resource from. */ - private String path; - - /** The context to get the resource from. */ - private Context ctx; - - /** A locally cached copy of the DataSource */ - private DataSource ds = null; - - /** Time of last actual lookup action */ - private long lastLookup = 0; - - /** Time between two lookups */ - private long ttl = 0; // ms - - /** - * @return the name of the factory. - */ - @Override - public String getName() - { - return name; - } - - /** - * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource() - */ - @Override - public DataSource getDataSource() throws SQLException - { - long time = System.currentTimeMillis(); - - if (ds == null || time - lastLookup > ttl) - { - try - { - synchronized (ctx) - { - ds = ((DataSource) ctx.lookup(path)); - } - lastLookup = time; - } - catch (NamingException e) - { - throw new SQLException(e); - } - } - - return ds; - } - - /** - * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes) - */ - @Override - public void initialize(JDBCDiskCacheAttributes config) throws SQLException - { - this.name = config.getConnectionPoolName(); - initJNDI(config); - } - - /** - * Initializes JNDI. - * - * @param config where to read the settings from - * @throws SQLException if a property set fails - */ - private void initJNDI(JDBCDiskCacheAttributes config) throws SQLException - { - log.debug("Starting initJNDI"); - - try - { - this.path = config.getJndiPath(); - if (log.isDebugEnabled()) - { - log.debug("JNDI path: " + path); - } - - this.ttl = config.getJndiTTL(); - if (log.isDebugEnabled()) - { - log.debug("Time between context lookups: " + ttl); - } - - Hashtable env = new Hashtable(); - ctx = new InitialContext(env); - - if (log.isDebugEnabled()) - { - log.debug("Created new InitialContext"); - debugCtx(ctx); - } - } - catch (NamingException e) - { - throw new SQLException(e); - } - } - - /** - * Does nothing. We do not want to close a dataSource retrieved from Jndi, - * because other applications might use it as well. - */ - @Override - public void close() - { - // do nothing - } - - /** - * - * @param ctx the context - * @throws NamingException - */ - private void debugCtx(Context ctx) throws NamingException - { - log.debug("InitialContext -------------------------------"); - Map env = ctx.getEnvironment(); - Iterator qw = env.entrySet().iterator(); - log.debug("Environment properties:" + env.size()); - while (qw.hasNext()) - { - Map.Entry entry = (Map.Entry) qw.next(); - log.debug(" " + entry.getKey() + ": " + entry.getValue()); - } - log.debug("----------------------------------------------"); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java deleted file mode 100644 index d5417a878ad..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.SQLException; - -import javax.sql.ConnectionPoolDataSource; -import javax.sql.DataSource; - -import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS; -import org.apache.commons.dbcp2.datasources.InstanceKeyDataSource; -import org.apache.commons.dbcp2.datasources.SharedPoolDataSource; -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A factory that looks up the DataSource using the JDBC2 pool methods. - * - * Borrowed and adapted from Apache DB Torque - * - * @author John McNally - * @author Henning P. Schmiedehausen - */ -public class SharedPoolDataSourceFactory implements DataSourceFactory -{ - /** The log. */ - private static Log log = LogFactory.getLog(SharedPoolDataSourceFactory.class); - - /** The name of the factory. */ - private String name; - - /** The wrapped DataSource. */ - private SharedPoolDataSource ds = null; - - /** - * @return the name of the factory. - */ - @Override - public String getName() - { - return name; - } - - /** - * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource() - */ - @Override - public DataSource getDataSource() - { - return ds; - } - - /** - * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes) - */ - @Override - public void initialize(JDBCDiskCacheAttributes config) throws SQLException - { - this.name = config.getConnectionPoolName(); - ConnectionPoolDataSource cpds = initCPDS(config); - SharedPoolDataSource dataSource = new SharedPoolDataSource(); - initJdbc2Pool(dataSource, config); - dataSource.setConnectionPoolDataSource(cpds); - dataSource.setMaxTotal(config.getMaxTotal()); - this.ds = dataSource; - } - - /** - * Closes the pool associated with this factory and releases it. - * @throws SQLException if the pool cannot be closed properly - */ - @Override - public void close() throws SQLException - { - try - { - ds.close(); - } - catch (Exception e) - { - throw new SQLException("Exception caught closing data source", e); - } - ds = null; - } - - /** - * Initializes the ConnectionPoolDataSource. - * - * @param config where to read the settings from - * @throws SQLException if a property set fails - * @return a configured ConnectionPoolDataSource - */ - private ConnectionPoolDataSource initCPDS(final JDBCDiskCacheAttributes config) - throws SQLException - { - log.debug("Starting initCPDS"); - - DriverAdapterCPDS cpds = new DriverAdapterCPDS(); - - try - { - cpds.setDriver(config.getDriverClassName()); - } - catch (ClassNotFoundException e) - { - throw new SQLException("Driver class not found " + config.getDriverClassName(), e); - } - - cpds.setUrl(config.getUrl()); - cpds.setUser(config.getUserName()); - cpds.setPassword(config.getPassword()); - - return cpds; - } - - /** - * Initializes the Jdbc2PoolDataSource. - * - * @param dataSource the dataSource to initialize, not null. - * @param config where to read the settings from, not null. - * - * @throws SQLException if a property set fails. - */ - private void initJdbc2Pool(final InstanceKeyDataSource dataSource, final JDBCDiskCacheAttributes config) - throws SQLException - { - log.debug("Starting initJdbc2Pool"); - - dataSource.setDescription(config.getConnectionPoolName()); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java deleted file mode 100644 index 01607928eab..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java +++ /dev/null @@ -1,182 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.hsql; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCache; -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This factory should create hsql disk caches. - *

- * @author Aaron Smuts - */ -public class HSQLDiskCacheFactory - extends JDBCDiskCacheFactory -{ - /** The logger */ - private static final Log log = LogFactory.getLog( HSQLDiskCacheFactory.class ); - - /** The databases. */ - private Set databases; - - /** - * This factory method should create an instance of the hsqlcache. - *

- * @param rawAttr - * @param compositeCacheManager - * @param cacheEventLogger - * @param elementSerializer - * @return JDBCDiskCache - * @throws SQLException if the creation of the cache instance fails - */ - @Override - public JDBCDiskCache createCache( AuxiliaryCacheAttributes rawAttr, - ICompositeCacheManager compositeCacheManager, - ICacheEventLogger cacheEventLogger, - IElementSerializer elementSerializer ) - throws SQLException - { - setupDatabase( (JDBCDiskCacheAttributes) rawAttr ); - return super.createCache(rawAttr, compositeCacheManager, cacheEventLogger, elementSerializer); - } - - /** - * Initialize this factory - */ - @Override - public void initialize() - { - super.initialize(); - this.databases = Collections.synchronizedSet( new HashSet() ); - } - - /** - * Creates the database if it doesn't exist, registers the driver class, etc. - *

- * @param attributes - * @throws SQLException - */ - protected void setupDatabase( JDBCDiskCacheAttributes attributes ) - throws SQLException - { - if ( attributes == null ) - { - throw new SQLException( "The attributes are null." ); - } - - // url should start with "jdbc:hsqldb:" - String database = attributes.getUrl() + attributes.getDatabase(); - - if ( databases.contains( database ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "We already setup database [" + database + "]" ); - } - return; - } - - // TODO get this from the attributes. - System.setProperty( "hsqldb.cache_scale", "8" ); - - // "org.hsqldb.jdbcDriver" - String driver = attributes.getDriverClassName(); - // "sa" - String user = attributes.getUserName(); - // "" - String password = attributes.getPassword(); - - try - { - Class.forName( driver ).newInstance(); - } - catch (Exception e) - { - throw new SQLException( "Could not initialize driver " + driver, e ); - } - - Connection cConn = DriverManager.getConnection( database, user, password ); - setupTable( cConn, attributes.getTableName() ); - - if ( log.isInfoEnabled() ) - { - log.info( "Finished setting up database [" + database + "]" ); - } - - databases.add( database ); - } - - /** - * SETUP TABLE FOR CACHE - *

- * @param cConn - * @param tableName - */ - protected void setupTable( Connection cConn, String tableName ) throws SQLException - { - // TODO make the cached nature of the table configurable - StringBuilder createSql = new StringBuilder(); - createSql.append( "CREATE CACHED TABLE ").append( tableName ); - createSql.append( "( " ); - createSql.append( "CACHE_KEY VARCHAR(250) NOT NULL, " ); - createSql.append( "REGION VARCHAR(250) NOT NULL, " ); - createSql.append( "ELEMENT BINARY, " ); - createSql.append( "CREATE_TIME TIMESTAMP, " ); - createSql.append( "UPDATE_TIME_SECONDS BIGINT, " ); - createSql.append( "MAX_LIFE_SECONDS BIGINT, " ); - createSql.append( "SYSTEM_EXPIRE_TIME_SECONDS BIGINT, " ); - createSql.append( "IS_ETERNAL CHAR(1), " ); - createSql.append( "PRIMARY KEY (CACHE_KEY, REGION) " ); - createSql.append( ");" ); - - Statement sStatement = cConn.createStatement(); - - try - { - sStatement.execute( createSql.toString() ); - } - catch ( SQLException e ) - { - if (!"23000".equals(e.getSQLState())) - { - throw e; - } - } - finally - { - sStatement.close(); - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java deleted file mode 100644 index 688827589be..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java +++ /dev/null @@ -1,171 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.SQLException; -import java.util.Map; - -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCache; -import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState; -import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * The MySQLDiskCache extends the core JDBCDiskCache. - *

- * Although the generic JDBC Disk Cache can be used for MySQL, the MySQL JDBC Disk Cache has - * additional features, such as table optimization that are particular to MySQL. - *

- * @author Aaron Smuts - */ -public class MySQLDiskCache - extends JDBCDiskCache -{ - /** local logger */ - private static final Log log = LogFactory.getLog( MySQLDiskCache.class ); - - /** config attributes */ - private final MySQLDiskCacheAttributes mySQLDiskCacheAttributes; - - /** - * Delegates to the super and makes use of the MySQL specific parameters used for scheduled - * optimization. - *

- * @param attributes the configuration object for this cache - * @param dsFactory the DataSourceFactory for this cache - * @param tableState an object to track table operations - * @param compositeCacheManager the global cache manager - * @throws SQLException if the pool access could not be set up - */ - public MySQLDiskCache( MySQLDiskCacheAttributes attributes, DataSourceFactory dsFactory, - TableState tableState, ICompositeCacheManager compositeCacheManager ) throws SQLException - { - super( attributes, dsFactory, tableState, compositeCacheManager ); - - mySQLDiskCacheAttributes = attributes; - - if ( log.isDebugEnabled() ) - { - log.debug( "MySQLDiskCacheAttributes = " + attributes ); - } - } - - /** - * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this - * method will balk and return null. - *

- * @param key Key to locate value for. - * @return An object matching key, or null. - */ - @Override - protected ICacheElement processGet( K key ) - { - if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING ) - { - if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() ) - { - return null; - } - } - return super.processGet( key ); - } - - /** - * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this - * method will balk and return null. - *

- * @param pattern used for like query. - * @return An object matching key, or null. - */ - @Override - protected Map> processGetMatching( String pattern ) - { - if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING ) - { - if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() ) - { - return null; - } - } - return super.processGetMatching( pattern ); - } - - /** - * @param pattern - * @return String to use in the like query. - */ - @Override - public String constructLikeParameterFromPattern( String pattern ) - { - String likePattern = pattern.replaceAll( "\\.\\+", "%" ); - likePattern = likePattern.replaceAll( "\\.", "_" ); - - if ( log.isDebugEnabled() ) - { - log.debug( "pattern = [" + likePattern + "]" ); - } - - return likePattern; - } - - /** - * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this - * method will balk and do nothing. - *

- * @param element - */ - @Override - protected void processUpdate( ICacheElement element ) - { - if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING ) - { - if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() ) - { - return; - } - } - super.processUpdate( element ); - } - - /** - * Removed the expired. (now - create time) > max life seconds * 1000 - *

- * If we are currently optimizing, then this method will balk and do nothing. - *

- * TODO consider blocking and trying again. - *

- * @return the number deleted - */ - @Override - protected int deleteExpired() - { - if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING ) - { - if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() ) - { - return -1; - } - } - return super.deleteExpired(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java deleted file mode 100644 index fca970237c5..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; - -/** - * This has additional attributes that are particular to the MySQL disk cache. - *

- * @author Aaron Smuts - */ -public class MySQLDiskCacheAttributes - extends JDBCDiskCacheAttributes -{ - /** Don't change. */ - private static final long serialVersionUID = -6535808344813320061L; - - /** - * For now this is a simple comma delimited list of HH:MM:SS times to optimize - * the table. If none is supplied, then no optimizations will be performed. - *

- * In the future we can add a chron like scheduling system. This is to meet - * a pressing current need. - *

- * 03:01,15:00 will cause the optimizer to run at 3 am and at 3 pm. - */ - private String optimizationSchedule = null; - - /** - * If true, we will balk, that is return null during optimization rather than block. - */ - public static final boolean DEFAULT_BALK_DURING_OPTIMIZATION = true; - - /** - * If true, we will balk, that is return null during optimization rather than block. - *

- * Balking - */ - private boolean balkDuringOptimization = DEFAULT_BALK_DURING_OPTIMIZATION; - - /** - * @param optimizationSchedule The optimizationSchedule to set. - */ - public void setOptimizationSchedule( String optimizationSchedule ) - { - this.optimizationSchedule = optimizationSchedule; - } - - /** - * @return Returns the optimizationSchedule. - */ - public String getOptimizationSchedule() - { - return optimizationSchedule; - } - - /** - * @param balkDuringOptimization The balkDuringOptimization to set. - */ - public void setBalkDuringOptimization( boolean balkDuringOptimization ) - { - this.balkDuringOptimization = balkDuringOptimization; - } - - /** - * Should we return null while optimizing the table. - *

- * @return Returns the balkDuringOptimization. - */ - public boolean isBalkDuringOptimization() - { - return balkDuringOptimization; - } - - /** - * For debugging. - *

- * @return debug string - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nMySQLDiskCacheAttributes" ); - buf.append( "\n OptimizationSchedule [" + getOptimizationSchedule() + "]" ); - buf.append( "\n BalkDuringOptimization [" + isBalkDuringOptimization() + "]" ); - buf.append( super.toString() ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java deleted file mode 100644 index 147948aedc6..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java +++ /dev/null @@ -1,196 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.SQLException; -import java.text.ParseException; -import java.util.Date; -import java.util.concurrent.TimeUnit; - -import javax.sql.DataSource; - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory; -import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState; -import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory; -import org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.util.ScheduleParser; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This factory should create mysql disk caches. - *

- * @author Aaron Smuts - */ -public class MySQLDiskCacheFactory - extends JDBCDiskCacheFactory -{ - /** The logger */ - private static final Log log = LogFactory.getLog( MySQLDiskCacheFactory.class ); - - /** - * This factory method should create an instance of the mysqlcache. - *

- * @param rawAttr specific cache configuration attributes - * @param compositeCacheManager the global cache manager - * @param cacheEventLogger a specific logger for cache events - * @param elementSerializer a serializer for cache elements - * @return MySQLDiskCache the cache instance - * @throws SQLException if the cache instance could not be created - */ - @Override - public MySQLDiskCache createCache( AuxiliaryCacheAttributes rawAttr, - ICompositeCacheManager compositeCacheManager, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - throws SQLException - { - MySQLDiskCacheAttributes cattr = (MySQLDiskCacheAttributes) rawAttr; - TableState tableState = getTableState( cattr.getTableName() ); - DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties()); - - MySQLDiskCache cache = new MySQLDiskCache( cattr, dsFactory, tableState, compositeCacheManager ); - cache.setCacheEventLogger( cacheEventLogger ); - cache.setElementSerializer( elementSerializer ); - - // create a shrinker if we need it. - createShrinkerWhenNeeded( cattr, cache ); - scheduleOptimizations( cattr, tableState, cache.getDataSource() ); - - return cache; - - } - - /** - * For each time in the optimization schedule, this calls schedule Optimization. - *

- * @param attributes configuration properties. - * @param tableState for noting optimization in progress, etc. - * @param ds the DataSource - */ - protected void scheduleOptimizations( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource ds ) - { - if ( attributes != null ) - { - if ( attributes.getOptimizationSchedule() != null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Will try to configure optimization for table [" + attributes.getTableName() - + "] on schedule [" + attributes.getOptimizationSchedule() + "]" ); - } - - MySQLTableOptimizer optimizer = new MySQLTableOptimizer( attributes, tableState, ds ); - - // loop through the dates. - try - { - Date[] dates = ScheduleParser.createDatesForSchedule( attributes.getOptimizationSchedule() ); - if ( dates != null ) - { - for ( int i = 0; i < dates.length; i++ ) - { - this.scheduleOptimization( dates[i], optimizer ); - } - } - } - catch ( ParseException e ) - { - log.warn( "Problem creating optimization schedule for table [" + attributes.getTableName() + "]", e ); - } - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "Optimization is not configured for table [" + attributes.getTableName() + "]" ); - } - } - } - } - - /** - * This takes in a single time and schedules the optimizer to be called at that time every day. - *

- * @param startTime -- HH:MM:SS format - * @param optimizer - */ - protected void scheduleOptimization( Date startTime, MySQLTableOptimizer optimizer ) - { - if ( log.isInfoEnabled() ) - { - log.info( "startTime [" + startTime + "] for optimizer " + optimizer ); - } - - // get the runnable from the factory - OptimizerTask runnable = new OptimizerTask( optimizer ); - Date now = new Date(); - long initialDelay = startTime.getTime() - now.getTime(); - - // have the daemon execute our runnable - getScheduledExecutorService().scheduleAtFixedRate(runnable, initialDelay, 86400000L, TimeUnit.MILLISECONDS ); - } - - /** - * This calls the optimizers' optimize table method. This is used by the timer. - *

- * @author Aaron Smuts - */ - private static class OptimizerTask - implements Runnable - { - /** Handles optimization */ - private MySQLTableOptimizer optimizer = null; - - /** - * Get a handle on the optimizer. - *

- * @param optimizer - */ - public OptimizerTask( MySQLTableOptimizer optimizer ) - { - this.optimizer = optimizer; - } - - /** - * This calls optimize on the optimizer. - *

- * @see java.lang.Runnable#run() - */ - @Override - public void run() - { - if ( optimizer != null ) - { - boolean success = optimizer.optimizeTable(); - if ( log.isInfoEnabled() ) - { - log.info( "Optimization success status [" + success + "]" ); - } - } - else - { - log.warn( "OptimizerRunner: The optimizer is null. Could not optimize table." ); - } - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java deleted file mode 100644 index 23f91012621..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java +++ /dev/null @@ -1,324 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import javax.sql.DataSource; - -import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * The MySQL Table Optimizer can optimize MySQL tables. It knows how to optimize for MySQL databases - * in particular and how to repair the table if it is corrupted in the process. - *

- * We will probably be able to abstract out a generic optimizer interface from this class in the - * future. - *

- * @author Aaron Smuts - */ -public class MySQLTableOptimizer -{ - /** The logger */ - private static final Log log = LogFactory.getLog( MySQLTableOptimizer.class ); - - /** The data source */ - private DataSource dataSource = null; - - /** The name of the table. */ - private String tableName = null; - - /** optimizing, etc. */ - private TableState tableState; - - /** - * This constructs an optimizer with the disk cacn properties. - *

- * @param attributes - * @param tableState We mark the table status as optimizing when this is happening. - * @param dataSource access to the database - */ - public MySQLTableOptimizer( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource dataSource ) - { - setTableName( attributes.getTableName() ); - - this.tableState = tableState; - this.dataSource = dataSource; - } - - /** - * A scheduler will call this method. When it is called the table state is marked as optimizing. - * TODO we need to verify that no deletions are running before we call optimize. We should wait - * if a deletion is in progress. - *

- * This restores when there is an optimization error. The error output looks like this: - * - *

-     *           mysql> optimize table JCS_STORE_FLIGHT_OPTION_ITINERARY;
-     *               +---------------------------------------------+----------+----------+---------------------+
-     *               | Table                                       | Op       | Msg_type | Msg_text            |
-     *               +---------------------------------------------+----------+----------+---------------------+
-     *               | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | optimize | error    | 2 when fixing table |
-     *               | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | optimize | status   | Operation failed    |
-     *               +---------------------------------------------+----------+----------+---------------------+
-     *               2 rows in set (51.78 sec)
-     * 
- * - * A successful repair response looks like this: - * - *
-     *        mysql> REPAIR TABLE JCS_STORE_FLIGHT_OPTION_ITINERARY;
-     *            +---------------------------------------------+--------+----------+----------------------------------------------+
-     *            | Table                                       | Op     | Msg_type | Msg_text                                     |
-     *            +---------------------------------------------+--------+----------+----------------------------------------------+
-     *            | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | error    | 2 when fixing table                          |
-     *            | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | warning  | Number of rows changed from 131276 to 260461 |
-     *            | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | status   | OK                                           |
-     *            +---------------------------------------------+--------+----------+----------------------------------------------+
-     *            3 rows in set (3 min 5.94 sec)
-     * 
- * - * A successful optimization looks like this: - * - *
-     *       mysql> optimize table JCS_STORE_DEFAULT;
-     *           +-----------------------------+----------+----------+----------+
-     *           | Table                       | Op       | Msg_type | Msg_text |
-     *           +-----------------------------+----------+----------+----------+
-     *           | jcs_cache.JCS_STORE_DEFAULT | optimize | status   | OK       |
-     *           +-----------------------------+----------+----------+----------+
-     *           1 row in set (1.10 sec)
-     * 
- * @return true if it worked - */ - public boolean optimizeTable() - { - long start = System.currentTimeMillis(); - boolean success = false; - - if ( tableState.getState() == TableState.OPTIMIZATION_RUNNING ) - { - log - .warn( "Skipping optimization. Optimize was called, but the table state indicates that an optimization is currently running." ); - return false; - } - - try - { - tableState.setState( TableState.OPTIMIZATION_RUNNING ); - if ( log.isInfoEnabled() ) - { - log.info( "Optimizing table [" + this.getTableName() + "]" ); - } - - Connection con; - try - { - con = dataSource.getConnection(); - } - catch ( SQLException e ) - { - log.error( "Problem getting connection.", e ); - return false; - } - - try - { - // TEST - Statement sStatement = null; - try - { - sStatement = con.createStatement(); - - ResultSet rs = sStatement.executeQuery( "optimize table " + this.getTableName() ); - - // first row is error, then status - // if there is only one row in the result set, everything - // should be fine. - // This may be mysql version specific. - if ( rs.next() ) - { - String status = rs.getString( "Msg_type" ); - String message = rs.getString( "Msg_text" ); - - if ( log.isInfoEnabled() ) - { - log.info( "Message Type: " + status ); - log.info( "Message: " + message ); - } - - if ( "error".equals( status ) ) - { - log.warn( "Optimization was in error. Will attempt to repair the table. Message: " - + message ); - - // try to repair the table. - success = repairTable( sStatement ); - } - else - { - success = true; - } - } - - // log the table status - String statusString = getTableStatus( sStatement ); - if ( log.isInfoEnabled() ) - { - log.info( "Table status after optimizing table [" + this.getTableName() + "]\n" + statusString ); - } - } - catch ( SQLException e ) - { - log.error( "Problem optimizing table [" + this.getTableName() + "]", e ); - return false; - } - finally - { - if (sStatement != null) - { - try - { - sStatement.close(); - } - catch ( SQLException e ) - { - log.error( "Problem closing statement.", e ); - } - } - } - } - finally - { - try - { - con.close(); - } - catch ( SQLException e ) - { - log.error( "Problem closing connection.", e ); - } - } - } - finally - { - tableState.setState( TableState.FREE ); - - long end = System.currentTimeMillis(); - if ( log.isInfoEnabled() ) - { - log.info( "Optimization of table [" + this.getTableName() + "] took " + ( end - start ) + " ms." ); - } - } - - return success; - } - - /** - * This calls show table status and returns the result as a String. - *

- * @param sStatement - * @return String - * @throws SQLException - */ - protected String getTableStatus( Statement sStatement ) - throws SQLException - { - ResultSet statusResultSet = sStatement.executeQuery( "show table status" ); - StringBuilder statusString = new StringBuilder(); - int numColumns = statusResultSet.getMetaData().getColumnCount(); - while ( statusResultSet.next() ) - { - statusString.append( "\n" ); - for ( int i = 1; i <= numColumns; i++ ) - { - statusString.append( statusResultSet.getMetaData().getColumnLabel( i ) + " [" - + statusResultSet.getString( i ) + "] | " ); - } - } - return statusString.toString(); - } - - /** - * This is called if the optimization is in error. - *

- * It looks for "OK" in response. If it find "OK" as a message in any result set row, it returns - * true. Otherwise we assume that the repair failed. - *

- * @param sStatement - * @return true if successful - * @throws SQLException - */ - protected boolean repairTable( Statement sStatement ) - throws SQLException - { - boolean success = false; - - // if( message != null && message.indexOf( ) ) - ResultSet repairResult = sStatement.executeQuery( "repair table " + this.getTableName() ); - StringBuilder repairString = new StringBuilder(); - int numColumns = repairResult.getMetaData().getColumnCount(); - while ( repairResult.next() ) - { - for ( int i = 1; i <= numColumns; i++ ) - { - repairString.append( repairResult.getMetaData().getColumnLabel( i ) + " [" + repairResult.getString( i ) - + "] | " ); - } - - String message = repairResult.getString( "Msg_text" ); - if ( "OK".equals( message ) ) - { - success = true; - } - } - if ( log.isInfoEnabled() ) - { - log.info( repairString ); - } - - if ( !success ) - { - log.warn( "Failed to repair the table. " + repairString ); - } - return success; - } - - /** - * @param tableName The tableName to set. - */ - public void setTableName( String tableName ) - { - this.tableName = tableName; - } - - /** - * @return Returns the tableName. - */ - public String getTableName() - { - return tableName; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java b/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java deleted file mode 100644 index 4e973e2283e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.util; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.StringTokenizer; - -/** - * Parses the very simple schedule format. - *

- * @author Aaron Smuts - */ -public class ScheduleParser -{ - /** - * For each date time that is separated by a comma in the - * OptimizationSchedule, create a date and add it to an array of dates. - *

- * @param schedule - * @return Date[] - * @throws ParseException - */ - public static Date[] createDatesForSchedule( String schedule ) - throws ParseException - { - if ( schedule == null ) - { - throw new ParseException( "Cannot create schedules for a null String.", 0 ); - } - - StringTokenizer toker = new StringTokenizer( schedule, "," ); - Date[] dates = new Date[toker.countTokens()]; - int cnt = 0; - while ( toker.hasMoreTokens() ) - { - String time = toker.nextToken(); - dates[cnt] = getDateForSchedule( time ); - cnt++; - } - return dates; - } - - /** - * For a single string it creates a date that is the next time this hh:mm:ss - * combo will be seen. - *

- * @param startTime - * @return Date - * @throws ParseException - */ - public static Date getDateForSchedule( String startTime ) - throws ParseException - { - if ( startTime == null ) - { - throw new ParseException( "Cannot create date for a null String.", 0 ); - } - - SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); - Date date = sdf.parse(startTime); - Calendar cal = Calendar.getInstance(); - // This will result in a date of 1/1/1970 - cal.setTime(date); - - Calendar now = Calendar.getInstance(); - cal.set(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH)); - - // if the date is less than now, add a day. - if ( cal.before( now ) ) - { - cal.add( Calendar.DAY_OF_MONTH, 1 ); - } - - return cal.getTime(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/disk/package.html b/src/org/apache/commons/jcs/auxiliary/disk/package.html deleted file mode 100644 index 668a1418ca1..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/disk/package.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - The primary disk auxiliary. Objects are serialized to a file on disk. - This implementation uses memory keys and performs quite well. - Recomended for most cases. - - diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCache.java b/src/org/apache/commons/jcs/auxiliary/lateral/LateralCache.java deleted file mode 100644 index 7ead6e5b7b2..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCache.java +++ /dev/null @@ -1,454 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheEventLogging; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes; -import org.apache.commons.jcs.engine.CacheInfo; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.IZombie; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Lateral distributor. Returns null on get by default. Net search not implemented. - */ -public class LateralCache - extends AbstractAuxiliaryCacheEventLogging -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( LateralCache.class ); - - /** generalize this, use another interface */ - private final ILateralCacheAttributes lateralCacheAttributes; - - /** The region name */ - final String cacheName; - - /** either http, socket.udp, or socket.tcp can set in config */ - private ICacheServiceNonLocal lateralCacheService; - - /** Monitors the connection. */ - private LateralCacheMonitor monitor; - - /** - * Constructor for the LateralCache object - *

- * @param cattr - * @param lateral - * @param monitor - */ - public LateralCache( ILateralCacheAttributes cattr, ICacheServiceNonLocal lateral, LateralCacheMonitor monitor ) - { - this.cacheName = cattr.getCacheName(); - this.lateralCacheAttributes = cattr; - this.lateralCacheService = lateral; - this.monitor = monitor; - } - - /** - * Constructor for the LateralCache object - *

- * @param cattr - */ - public LateralCache( ILateralCacheAttributes cattr ) - { - this.cacheName = cattr.getCacheName(); - this.lateralCacheAttributes = cattr; - } - - /** - * Update lateral. - *

- * @param ce - * @throws IOException - */ - @Override - protected void processUpdate( ICacheElement ce ) - throws IOException - { - try - { - if (ce != null) - { - if ( log.isDebugEnabled() ) - { - log.debug( "update: lateral = [" + lateralCacheService + "], " + "CacheInfo.listenerId = " - + CacheInfo.listenerId ); - } - lateralCacheService.update( ce, CacheInfo.listenerId ); - } - } - catch ( IOException ex ) - { - handleException( ex, "Failed to put [" + ce.getKey() + "] to " + ce.getCacheName() + "@" + lateralCacheAttributes ); - } - } - - /** - * The performance costs are too great. It is not recommended that you enable lateral gets. - *

- * @param key - * @return ICacheElement<K, V> or null - * @throws IOException - */ - @Override - protected ICacheElement processGet( K key ) - throws IOException - { - ICacheElement obj = null; - - if ( this.lateralCacheAttributes.getPutOnlyMode() ) - { - return null; - } - try - { - obj = lateralCacheService.get( cacheName, key ); - } - catch ( Exception e ) - { - log.error( e ); - handleException( e, "Failed to get [" + key + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes ); - } - return obj; - } - - /** - * @param pattern - * @return A map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - protected Map> processGetMatching( String pattern ) - throws IOException - { - if ( this.lateralCacheAttributes.getPutOnlyMode() ) - { - return Collections.emptyMap(); - } - try - { - return lateralCacheService.getMatching( cacheName, pattern ); - } - catch ( IOException e ) - { - log.error( e ); - handleException( e, "Failed to getMatching [" + pattern + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes ); - return Collections.emptyMap(); - } - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - protected Map> processGetMultiple( Set keys ) - throws IOException - { - Map> elements = new HashMap>(); - - if ( keys != null && !keys.isEmpty() ) - { - for (K key : keys) - { - ICacheElement element = get( key ); - - if ( element != null ) - { - elements.put( key, element ); - } - } - } - - return elements; - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - try - { - return lateralCacheService.getKeySet( cacheName ); - } - catch ( IOException ex ) - { - handleException( ex, "Failed to get key set from " + lateralCacheAttributes.getCacheName() + "@" - + lateralCacheAttributes ); - } - return Collections.emptySet(); - } - - /** - * Synchronously remove from the remote cache; if failed, replace the remote handle with a - * zombie. - *

- * @param key - * @return false always - * @throws IOException - */ - @Override - protected boolean processRemove( K key ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "removing key:" + key ); - } - - try - { - lateralCacheService.remove( cacheName, key, CacheInfo.listenerId ); - } - catch ( IOException ex ) - { - handleException( ex, "Failed to remove " + key + " from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes ); - } - return false; - } - - /** - * Synchronously removeAll from the remote cache; if failed, replace the remote handle with a - * zombie. - *

- * @throws IOException - */ - @Override - protected void processRemoveAll() - throws IOException - { - try - { - lateralCacheService.removeAll( cacheName, CacheInfo.listenerId ); - } - catch ( IOException ex ) - { - handleException( ex, "Failed to remove all from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes ); - } - } - - /** - * Synchronously dispose the cache. Not sure we want this. - *

- * @throws IOException - */ - @Override - protected void processDispose() - throws IOException - { - log.debug( "Disposing of lateral cache" ); - - ///* HELP: This section did nothing but generate compilation warnings. - // TODO: may limit this functionality. It is dangerous. - // asmuts -- Added functionality to help with warnings. I'm not getting - // any. - try - { - lateralCacheService.dispose( this.lateralCacheAttributes.getCacheName() ); - // Should remove connection - } - catch ( IOException ex ) - { - log.error( "Couldn't dispose", ex ); - handleException( ex, "Failed to dispose " + lateralCacheAttributes.getCacheName() ); - } - } - - /** - * Returns the cache status. - *

- * @return The status value - */ - @Override - public CacheStatus getStatus() - { - return this.lateralCacheService instanceof IZombie ? CacheStatus.ERROR : CacheStatus.ALIVE; - } - - /** - * Returns the current cache size. - *

- * @return The size value - */ - @Override - public int getSize() - { - return 0; - } - - /** - * Gets the cacheType attribute of the LateralCache object - *

- * @return The cacheType value - */ - @Override - public CacheType getCacheType() - { - return CacheType.LATERAL_CACHE; - } - - /** - * Gets the cacheName attribute of the LateralCache object - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return cacheName; - } - - /** - * Not yet sure what to do here. - *

- * @param ex - * @param msg - * @throws IOException - */ - private void handleException( Exception ex, String msg ) - throws IOException - { - log.error( "Disabling lateral cache due to error " + msg, ex ); - - lateralCacheService = new ZombieCacheServiceNonLocal( lateralCacheAttributes.getZombieQueueMaxSize() ); - // may want to flush if region specifies - // Notify the cache monitor about the error, and kick off the recovery - // process. - monitor.notifyError(); - - // could stop the net search if it is built and try to reconnect? - if ( ex instanceof IOException ) - { - throw (IOException) ex; - } - throw new IOException( ex.getMessage() ); - } - - /** - * Replaces the current remote cache service handle with the given handle. - *

- * @param restoredLateral - */ - public void fixCache( ICacheServiceNonLocal restoredLateral ) - { - if ( this.lateralCacheService != null && this.lateralCacheService instanceof ZombieCacheServiceNonLocal ) - { - ZombieCacheServiceNonLocal zombie = (ZombieCacheServiceNonLocal) this.lateralCacheService; - this.lateralCacheService = restoredLateral; - try - { - zombie.propagateEvents( restoredLateral ); - } - catch ( Exception e ) - { - try - { - handleException( e, "Problem propagating events from Zombie Queue to new Lateral Service." ); - } - catch ( IOException e1 ) - { - // swallow, since this is just expected kick back. Handle always throws - } - } - } - else - { - this.lateralCacheService = restoredLateral; - } - } - - /** - * getStats - *

- * @return String - */ - @Override - public String getStats() - { - return ""; - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return lateralCacheAttributes; - } - - /** - * @return debugging data. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n LateralCache " ); - buf.append( "\n Cache Name [" + lateralCacheAttributes.getCacheName() + "]" ); - buf.append( "\n cattr = [" + lateralCacheAttributes + "]" ); - return buf.toString(); - } - - /** - * @return extra data. - */ - @Override - public String getEventLoggingExtraInfo() - { - return null; - } - - /** - * The NoWait on top does not call out to here yet. - *

- * @return almost nothing - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "LateralCache" ); - return stats; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheAttributes.java deleted file mode 100644 index fba67f3c05a..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheAttributes.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes; - -/** - * This class stores attributes for all of the available lateral cache auxiliaries. - */ -public class LateralCacheAttributes - extends AbstractAuxiliaryCacheAttributes - implements ILateralCacheAttributes -{ - /** Don't change */ - private static final long serialVersionUID = -3408449508837393660L; - - /** Default receive setting */ - private static final boolean DEFAULT_RECEIVE = true; - - /** THe type of lateral */ - private String transmissionTypeName = "UDP"; - - /** indicates the lateral type, this needs to change */ - private Type transmissionType = Type.UDP; - - /** The http servers */ - private String httpServers; - - /** used to identify the service that this manager will be operating on */ - private String httpServer = ""; - - /** this needs to change */ - private String udpMulticastAddr = "228.5.6.7"; - - /** this needs to change */ - private int udpMulticastPort = 6789; - - /** this needs to change */ - private int httpListenerPort = 8080; - - /** disables gets from laterals */ - private boolean putOnlyMode = true; - - /** - * do we receive and broadcast or only broadcast this is useful when you don't want to get any - * notifications - */ - private boolean receive = DEFAULT_RECEIVE; - - /** If the primary fails, we will queue items before reconnect. This limits the number of items that can be queued. */ - private int zombieQueueMaxSize = DEFAULT_ZOMBIE_QUEUE_MAX_SIZE; - - /** - * Sets the httpServer attribute of the LateralCacheAttributes object - *

- * @param val The new httpServer value - */ - @Override - public void setHttpServer( String val ) - { - httpServer = val; - } - - /** - * Gets the httpServer attribute of the LateralCacheAttributes object - * @return The httpServer value - */ - @Override - public String getHttpServer() - { - return httpServer; - } - - /** - * Sets the httpServers attribute of the LateralCacheAttributes object - * @param val The new httpServers value - */ - @Override - public void setHttpServers( String val ) - { - httpServers = val; - } - - /** - * Gets the httpSrvers attribute of the LateralCacheAttributes object - * @return The httpServers value - */ - @Override - public String getHttpServers() - { - return httpServers; - } - - /** - * Sets the httpListenerPort attribute of the ILateralCacheAttributes object - * @param val The new tcpListenerPort value - */ - @Override - public void setHttpListenerPort( int val ) - { - this.httpListenerPort = val; - } - - /** - * Gets the httpListenerPort attribute of the ILateralCacheAttributes object - * @return The httpListenerPort value - */ - @Override - public int getHttpListenerPort() - { - return this.httpListenerPort; - } - - /** - * Sets the udpMulticastAddr attribute of the LateralCacheAttributes object - * @param val The new udpMulticastAddr value - */ - @Override - public void setUdpMulticastAddr( String val ) - { - udpMulticastAddr = val; - } - - /** - * Gets the udpMulticastAddr attribute of the LateralCacheAttributes object - * @return The udpMulticastAddr value - */ - @Override - public String getUdpMulticastAddr() - { - return udpMulticastAddr; - } - - /** - * Sets the udpMulticastPort attribute of the LateralCacheAttributes object - * @param val The new udpMulticastPort value - */ - @Override - public void setUdpMulticastPort( int val ) - { - udpMulticastPort = val; - } - - /** - * Gets the udpMulticastPort attribute of the LateralCacheAttributes object - * @return The udpMulticastPort value - */ - @Override - public int getUdpMulticastPort() - { - return udpMulticastPort; - } - - /** - * Sets the transmissionType attribute of the LateralCacheAttributes object - * @param val The new transmissionType value - */ - @Override - public void setTransmissionType( Type val ) - { - this.transmissionType = val; - this.transmissionTypeName = val.toString(); - } - - /** - * Gets the transmissionType attribute of the LateralCacheAttributes object - * @return The transmissionType value - */ - @Override - public Type getTransmissionType() - { - return this.transmissionType; - } - - /** - * Sets the transmissionTypeName attribute of the LateralCacheAttributes object - * @param val The new transmissionTypeName value - */ - @Override - public void setTransmissionTypeName( String val ) - { - this.transmissionTypeName = val; - this.transmissionType = Type.valueOf(val); - } - - /** - * Gets the transmissionTypeName attribute of the LateralCacheAttributes object - * @return The transmissionTypeName value - */ - @Override - public String getTransmissionTypeName() - { - return this.transmissionTypeName; - } - - /** - * Sets the outgoingOnlyMode attribute of the ILateralCacheAttributes. When this is true the - * lateral cache will only issue put and remove order and will not try to retrieve elements from - * other lateral caches. - * @param val The new transmissionTypeName value - */ - @Override - public void setPutOnlyMode( boolean val ) - { - this.putOnlyMode = val; - } - - /** - * @return The outgoingOnlyMode value. Stops gets from going remote. - */ - @Override - public boolean getPutOnlyMode() - { - return putOnlyMode; - } - - /** - * @param receive The receive to set. - */ - @Override - public void setReceive( boolean receive ) - { - this.receive = receive; - } - - /** - * @return Returns the receive. - */ - @Override - public boolean isReceive() - { - return receive; - } - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @param zombieQueueMaxSize The zombieQueueMaxSize to set. - */ - @Override - public void setZombieQueueMaxSize( int zombieQueueMaxSize ) - { - this.zombieQueueMaxSize = zombieQueueMaxSize; - } - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @return Returns the zombieQueueMaxSize. - */ - @Override - public int getZombieQueueMaxSize() - { - return zombieQueueMaxSize; - } - - /** - * @return debug string. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - //buf.append( "cacheName=" + cacheName + "\n" ); - //buf.append( "putOnlyMode=" + putOnlyMode + "\n" ); - //buf.append( "transmissionTypeName=" + transmissionTypeName + "\n" ); - //buf.append( "transmissionType=" + transmissionType + "\n" ); - //buf.append( "tcpServer=" + tcpServer + "\n" ); - buf.append( transmissionTypeName + httpServer + udpMulticastAddr + String.valueOf( udpMulticastPort ) ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java b/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java deleted file mode 100644 index bbe88ad486e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; - -/** - * Used to monitor and repair any failed connection for the lateral cache service. By default the - * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an - * error. Upon the notification of a connection error, the monitor changes to operate in a time - * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed - * connections are restored, it changes back to the failure driven mode. - */ -public class LateralCacheMonitor extends AbstractAuxiliaryCacheMonitor -{ - /** - * Map of caches to monitor - */ - private ConcurrentHashMap> caches; - - /** - * Reference to the factory - */ - private LateralTCPCacheFactory factory; - - /** - * Allows close classes, ie testers to set the idle period to something testable. - *

- * @param idlePeriod - */ - protected static void forceShortIdlePeriod( long idlePeriod ) - { - LateralCacheMonitor.idlePeriod = idlePeriod; - } - - /** - * Constructor for the LateralCacheMonitor object - *

- * It's the clients responsibility to decide how many of these there will be. - * - * @param factory a reference to the factory that manages the service instances - */ - public LateralCacheMonitor(LateralTCPCacheFactory factory) - { - super("JCS-LateralCacheMonitor"); - this.factory = factory; - this.caches = new ConcurrentHashMap>(); - setIdlePeriod(20000L); - } - - /** - * Add a cache to be monitored - * - * @param cache the cache - */ - public void addCache(LateralCacheNoWait cache) - { - this.caches.put(cache.getCacheName(), cache); - - // if not yet started, go ahead - if (this.getState() == Thread.State.NEW) - { - this.start(); - } - } - - /** - * Clean up all resources before shutdown - */ - @Override - public void dispose() - { - this.caches.clear(); - } - - /** - * Main processing method for the LateralCacheMonitor object - */ - @Override - public void doWork() - { - // Monitor each cache instance one after the other. - log.info( "Number of caches to monitor = " + caches.size() ); - //for - for (Map.Entry> entry : caches.entrySet()) - { - String cacheName = entry.getKey(); - - @SuppressWarnings("unchecked") // Downcast to match service - LateralCacheNoWait c = (LateralCacheNoWait) entry.getValue(); - if ( c.getStatus() == CacheStatus.ERROR ) - { - log.info( "Found LateralCacheNoWait in error, " + cacheName ); - - ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)c.getAuxiliaryCacheAttributes(); - - // Get service instance - ICacheServiceNonLocal cacheService = factory.getCSNLInstance(lca); - - // If we can't fix them, just skip and re-try in the - // next round. - if (cacheService instanceof ZombieCacheServiceNonLocal) - { - continue; - } - - c.fixCache(cacheService); - } - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWait.java b/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWait.java deleted file mode 100644 index f87850cc510..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWait.java +++ /dev/null @@ -1,436 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.engine.CacheAdaptor; -import org.apache.commons.jcs.engine.CacheEventQueueFactory; -import org.apache.commons.jcs.engine.CacheInfo; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.IOException; -import java.rmi.UnmarshalException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * Used to queue up update requests to the underlying cache. These requests will be processed in - * their order of arrival via the cache event queue processor. - */ -public class LateralCacheNoWait - extends AbstractAuxiliaryCache -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( LateralCacheNoWait.class ); - - /** The cache */ - private final LateralCache cache; - - /** The event queue */ - private ICacheEventQueue eventQueue; - - /** times get called */ - private int getCount = 0; - - /** times remove called */ - private int removeCount = 0; - - /** times put called */ - private int putCount = 0; - - /** - * Constructs with the given lateral cache, and fires up an event queue for asynchronous - * processing. - *

- * @param cache - */ - public LateralCacheNoWait( LateralCache cache ) - { - this.cache = cache; - - if ( log.isDebugEnabled() ) - { - log.debug( "Constructing LateralCacheNoWait, LateralCache = [" + cache + "]" ); - } - - CacheEventQueueFactory fact = new CacheEventQueueFactory(); - this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor( cache ), CacheInfo.listenerId, cache - .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache - .getAuxiliaryCacheAttributes().getEventQueueType() ); - - // need each no wait to handle each of its real updates and removes, - // since there may - // be more than one per cache? alternative is to have the cache - // perform updates using a different method that specifies the listener - // this.q = new CacheEventQueue(new CacheAdaptor(this), - // LateralCacheInfo.listenerId, cache.getCacheName()); - if ( cache.getStatus() == CacheStatus.ERROR ) - { - eventQueue.destroy(); - } - } - - /** - * @param ce - * @throws IOException - */ - @Override - public void update( ICacheElement ce ) - throws IOException - { - putCount++; - try - { - eventQueue.addPutEvent( ce ); - } - catch ( IOException ex ) - { - log.error( ex ); - eventQueue.destroy(); - } - } - - /** - * Synchronously reads from the lateral cache. - *

- * @param key - * @return ICacheElement<K, V> if found, else null - */ - @Override - public ICacheElement get( K key ) - { - getCount++; - if ( this.getStatus() != CacheStatus.ERROR ) - { - try - { - return cache.get( key ); - } - catch ( UnmarshalException ue ) - { - log.debug( "Retrying the get owing to UnmarshalException..." ); - try - { - return cache.get( key ); - } - catch ( IOException ex ) - { - log.error( "Failed in retrying the get for the second time." ); - eventQueue.destroy(); - } - } - catch ( IOException ex ) - { - eventQueue.destroy(); - } - } - return null; - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - */ - @Override - public Map> getMultiple(Set keys) - { - Map> elements = new HashMap>(); - - if ( keys != null && !keys.isEmpty() ) - { - for (K key : keys) - { - ICacheElement element = get( key ); - - if ( element != null ) - { - elements.put( key, element ); - } - } - } - - return elements; - } - - /** - * Synchronously reads from the lateral cache. - *

- * @param pattern - * @return ICacheElement<K, V> if found, else empty - */ - @Override - public Map> getMatching(String pattern) - { - getCount++; - if ( this.getStatus() != CacheStatus.ERROR ) - { - try - { - return cache.getMatching( pattern ); - } - catch ( UnmarshalException ue ) - { - log.debug( "Retrying the get owing to UnmarshalException." ); - try - { - return cache.getMatching( pattern ); - } - catch ( IOException ex ) - { - log.error( "Failed in retrying the get for the second time." ); - eventQueue.destroy(); - } - } - catch ( IOException ex ) - { - eventQueue.destroy(); - } - } - return Collections.emptyMap(); - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - try - { - return cache.getKeySet(); - } - catch ( IOException ex ) - { - log.error( ex ); - eventQueue.destroy(); - } - return Collections.emptySet(); - } - - /** - * Adds a remove request to the lateral cache. - *

- * @param key - * @return always false - */ - @Override - public boolean remove( K key ) - { - removeCount++; - try - { - eventQueue.addRemoveEvent( key ); - } - catch ( IOException ex ) - { - log.error( ex ); - eventQueue.destroy(); - } - return false; - } - - /** Adds a removeAll request to the lateral cache. */ - @Override - public void removeAll() - { - try - { - eventQueue.addRemoveAllEvent(); - } - catch ( IOException ex ) - { - log.error( ex ); - eventQueue.destroy(); - } - } - - /** Adds a dispose request to the lateral cache. */ - @Override - public void dispose() - { - try - { - eventQueue.addDisposeEvent(); - } - catch ( IOException ex ) - { - log.error( ex ); - eventQueue.destroy(); - } - } - - /** - * No lateral invocation. - *

- * @return The size value - */ - @Override - public int getSize() - { - return cache.getSize(); - } - - /** - * No lateral invocation. - *

- * @return The cacheType value - */ - @Override - public CacheType getCacheType() - { - return cache.getCacheType(); - } - - /** - * Returns the asyn cache status. An error status indicates either the lateral connection is not - * available, or the asyn queue has been unexpectedly destroyed. No lateral invocation. - *

- * @return The status value - */ - @Override - public CacheStatus getStatus() - { - return eventQueue.isWorking() ? cache.getStatus() : CacheStatus.ERROR; - } - - /** - * Gets the cacheName attribute of the LateralCacheNoWait object - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return cache.getCacheName(); - } - - /** - * Replaces the lateral cache service handle with the given handle and reset the queue by - * starting up a new instance. - *

- * @param lateral - */ - public void fixCache( ICacheServiceNonLocal lateral ) - { - cache.fixCache( lateral ); - resetEventQ(); - } - - /** - * Resets the event q by first destroying the existing one and starting up new one. - */ - public void resetEventQ() - { - if ( eventQueue.isWorking() ) - { - eventQueue.destroy(); - } - CacheEventQueueFactory fact = new CacheEventQueueFactory(); - this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor( cache ), CacheInfo.listenerId, cache - .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache - .getAuxiliaryCacheAttributes().getEventQueueType() ); - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return cache.getAuxiliaryCacheAttributes(); - } - - /** - * getStats - * @return String - */ - @Override - public String getStats() - { - return getStatistics().toString(); - } - - /** - * this won't be called since we don't do ICache logging here. - *

- * @return String - */ - @Override - public String getEventLoggingExtraInfo() - { - return "Lateral Cache No Wait"; - } - - /** - * @return statistics about this communication - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Lateral Cache No Wait" ); - - ArrayList> elems = new ArrayList>(); - - // get the stats from the event queue too - IStats eqStats = this.eventQueue.getStatistics(); - elems.addAll(eqStats.getStatElements()); - - elems.add(new StatElement( "Get Count", Integer.valueOf(this.getCount) ) ); - elems.add(new StatElement( "Remove Count", Integer.valueOf(this.removeCount) ) ); - elems.add(new StatElement( "Put Count", Integer.valueOf(this.putCount) ) ); - elems.add(new StatElement( "Attributes", cache.getAuxiliaryCacheAttributes() ) ); - - stats.setStatElements( elems ); - - return stats; - } - - /** - * @return debugging info. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( " LateralCacheNoWait " ); - buf.append( " Status = " + this.getStatus() ); - buf.append( " cache = [" + cache.toString() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacade.java b/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacade.java deleted file mode 100644 index 3adc5022a02..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacade.java +++ /dev/null @@ -1,533 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * Used to provide access to multiple services under nowait protection. Composite factory should - * construct LateralCacheNoWaitFacade to give to the composite cache out of caches it constructs - * from the varies manager to lateral services. Perhaps the lateralcache factory should be able to - * do this. - */ -public class LateralCacheNoWaitFacade - extends AbstractAuxiliaryCache -{ - /** The logger */ - private static final Log log = LogFactory.getLog( LateralCacheNoWaitFacade.class ); - - /** The queuing facade to the client. */ - public LateralCacheNoWait[] noWaits; - - /** The region name */ - private final String cacheName; - - /** A cache listener */ - private ILateralCacheListener listener; - - /** User configurable attributes. */ - private final ILateralCacheAttributes lateralCacheAttributes; - - /** Disposed state of this facade */ - private boolean disposed = false; - - /** - * Constructs with the given lateral cache, and fires events to any listeners. - *

- * @param noWaits - * @param cattr - */ - public LateralCacheNoWaitFacade(ILateralCacheListener listener, LateralCacheNoWait[] noWaits, ILateralCacheAttributes cattr ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "CONSTRUCTING NO WAIT FACADE" ); - } - this.listener = listener; - this.noWaits = noWaits; - this.cacheName = cattr.getCacheName(); - this.lateralCacheAttributes = cattr; - } - - /** - * Tells you if the no wait is in the list or not. - *

- * @param noWait - * @return true if the noWait is in the list. - */ - public boolean containsNoWait( LateralCacheNoWait noWait ) - { - for ( int i = 0; i < noWaits.length; i++ ) - { - // we know noWait isn't null - if ( noWait.equals( noWaits[i] ) ) - { - return true; - } - } - return false; - } - - /** - * Adds a no wait to the list if it isn't already in the list. - *

- * @param noWait - * @return true if it wasn't already contained - */ - public synchronized boolean addNoWait( LateralCacheNoWait noWait ) - { - if ( noWait == null ) - { - return false; - } - - if ( containsNoWait( noWait ) ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "No Wait already contained, [" + noWait + "]" ); - } - return false; - } - - @SuppressWarnings("unchecked") // No generic arrays in java - LateralCacheNoWait[] newArray = new LateralCacheNoWait[noWaits.length + 1]; - - System.arraycopy( noWaits, 0, newArray, 0, noWaits.length ); - - // set the last position to the new noWait - newArray[noWaits.length] = noWait; - - noWaits = newArray; - - return true; - } - - /** - * Removes a no wait from the list if it is already there. - *

- * @param noWait - * @return true if it was already in the array - */ - public synchronized boolean removeNoWait( LateralCacheNoWait noWait ) - { - if ( noWait == null ) - { - return false; - } - - int position = -1; - for ( int i = 0; i < noWaits.length; i++ ) - { - // we know noWait isn't null - if ( noWait.equals( noWaits[i] ) ) - { - position = i; - break; - } - } - - if ( position == -1 ) - { - return false; - } - - @SuppressWarnings("unchecked") // No generic arrays in java - LateralCacheNoWait[] newArray = new LateralCacheNoWait[noWaits.length - 1]; - - System.arraycopy( noWaits, 0, newArray, 0, position ); - if ( noWaits.length != position ) - { - System.arraycopy( noWaits, position + 1, newArray, position, noWaits.length - position - 1 ); - } - noWaits = newArray; - - return true; - } - - /** - * @param ce - * @throws IOException - */ - @Override - public void update( ICacheElement ce ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "updating through lateral cache facade, noWaits.length = " + noWaits.length ); - } - try - { - for ( int i = 0; i < noWaits.length; i++ ) - { - noWaits[i].update( ce ); - } - } - catch ( Exception ex ) - { - log.error( ex ); - } - } - - /** - * Synchronously reads from the lateral cache. - *

- * @param key - * @return ICacheElement - */ - @Override - public ICacheElement get( K key ) - { - for ( int i = 0; i < noWaits.length; i++ ) - { - try - { - ICacheElement obj = noWaits[i].get( key ); - - if ( obj != null ) - { - // TODO: return after first success - // could do this simultaneously - // serious blocking risk here - return obj; - } - } - catch ( Exception ex ) - { - log.error( "Failed to get", ex ); - } - } - return null; - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - */ - @Override - public Map> getMultiple(Set keys) - { - Map> elements = new HashMap>(); - - if ( keys != null && !keys.isEmpty() ) - { - for (K key : keys) - { - ICacheElement element = get( key ); - - if ( element != null ) - { - elements.put( key, element ); - } - } - } - - return elements; - } - - /** - * Synchronously reads from the lateral cache. Get a response from each! This will be slow. - * Merge them. - *

- * @param pattern - * @return ICacheElement - */ - @Override - public Map> getMatching(String pattern) - { - Map> elements = new HashMap>(); - for ( int i = 0; i < noWaits.length; i++ ) - { - try - { - elements.putAll( noWaits[i].getMatching( pattern ) ); - } - catch ( Exception ex ) - { - log.error( "Failed to get", ex ); - } - } - return elements; - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - HashSet allKeys = new HashSet(); - for ( int i = 0; i < noWaits.length; i++ ) - { - AuxiliaryCache aux = noWaits[i]; - if ( aux != null ) - { - Set keys = aux.getKeySet(); - if(keys != null) - { - allKeys.addAll( keys ); - } - } - } - return allKeys; - } - - /** - * Adds a remove request to the lateral cache. - *

- * @param key - * @return always false. - */ - @Override - public boolean remove( K key ) - { - try - { - for ( int i = 0; i < noWaits.length; i++ ) - { - noWaits[i].remove( key ); - } - } - catch ( Exception ex ) - { - log.error( ex ); - } - return false; - } - - /** - * Adds a removeAll request to the lateral cache. - */ - @Override - public void removeAll() - { - try - { - for ( int i = 0; i < noWaits.length; i++ ) - { - noWaits[i].removeAll(); - } - } - catch ( Exception ex ) - { - log.error( ex ); - } - } - - /** Adds a dispose request to the lateral cache. */ - @Override - public void dispose() - { - try - { - if ( listener != null ) - { - listener.dispose(); - listener = null; - } - - for ( int i = 0; i < noWaits.length; i++ ) - { - noWaits[i].dispose(); - } - } - catch ( Exception ex ) - { - log.error( ex ); - } - finally - { - disposed = true; - } - } - - /** - * No lateral invocation. - * @return The size value - */ - @Override - public int getSize() - { - return 0; - //cache.getSize(); - } - - /** - * Gets the cacheType attribute of the LateralCacheNoWaitFacade object. - *

- * @return The cacheType value - */ - @Override - public CacheType getCacheType() - { - return CacheType.LATERAL_CACHE; - } - - /** - * Gets the cacheName attribute of the LateralCacheNoWaitFacade object. - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return ""; - //cache.getCacheName(); - } - - /** - * Gets the status attribute of the LateralCacheNoWaitFacade object - * @return The status value - */ - @Override - public CacheStatus getStatus() - { - if (disposed) - { - return CacheStatus.DISPOSED; - } - - if (noWaits.length == 0 || listener != null) - { - return CacheStatus.ALIVE; - } - - CacheStatus[] statii = new CacheStatus[noWaits.length]; - for (int i = 0; i < noWaits.length; i++) - { - statii[i] = noWaits[i].getStatus(); - } - // It's alive if ANY of its nowaits is alive - for (int i = 0; i < noWaits.length; i++) - { - if (statii[i] == CacheStatus.ALIVE) - { - return CacheStatus.ALIVE; - } - } - // It's alive if ANY of its nowaits is in error, but - // none are alive, then it's in error - for (int i = 0; i < noWaits.length; i++) - { - if (statii[i] == CacheStatus.ERROR) - { - return CacheStatus.ERROR; - } - } - - // Otherwise, it's been disposed, since it's the only status left - return CacheStatus.DISPOSED; - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return this.lateralCacheAttributes; - } - - /** - * @return "LateralCacheNoWaitFacade: " + cacheName; - */ - @Override - public String toString() - { - return "LateralCacheNoWaitFacade: " + cacheName; - } - - /** - * this won't be called since we don't do ICache logging here. - *

- * @return String - */ - @Override - public String getEventLoggingExtraInfo() - { - return "Lateral Cache No Wait"; - } - - /** - * getStats - * @return String - */ - @Override - public String getStats() - { - return getStatistics().toString(); - } - - /** - * @return IStats - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Lateral Cache No Wait Facade" ); - - ArrayList> elems = new ArrayList>(); - - if ( noWaits != null ) - { - elems.add(new StatElement( "Number of No Waits", Integer.valueOf(noWaits.length) ) ); - - for ( LateralCacheNoWait lcnw : noWaits ) - { - if ( lcnw != null ) - { - // get the stats from the super too - IStats sStats = lcnw.getStatistics(); - elems.addAll(sStats.getStatElements()); - } - } - } - - stats.setStatElements( elems ); - - return stats; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCommand.java b/src/org/apache/commons/jcs/auxiliary/lateral/LateralCommand.java deleted file mode 100644 index 5c4ff57ee02..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/LateralCommand.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Enumeration of the available lateral commands - */ -public enum LateralCommand -{ - /** The command for updates */ - UPDATE, - - /** The command for removes */ - REMOVE, - - /** The command instructing us to remove all */ - REMOVEALL, - - /** The command for disposing the cache. */ - DISPOSE, - - /** Command to return an object. */ - GET, - - /** Command to return an object. */ - GET_MATCHING, - - /** Command to get all keys */ - GET_KEYSET -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/LateralElementDescriptor.java b/src/org/apache/commons/jcs/auxiliary/lateral/LateralElementDescriptor.java deleted file mode 100644 index 55ef04bd8ff..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/LateralElementDescriptor.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; - -import java.io.Serializable; - -/** - * This class wraps command to other laterals. It is essentially a - * JCS-TCP-Lateral packet. The headers specify the action the receiver should - * take. - */ -public class LateralElementDescriptor - implements Serializable -{ - /** Don't change */ - private static final long serialVersionUID = 5268222498076063575L; - - /** The Cache Element that we are distributing. */ - public ICacheElement ce; - - /** - * The id of the the source of the request. This is used to prevent infinite - * loops. - */ - public long requesterId; - - /** The operation has been requested by the client. */ - public LateralCommand command = LateralCommand.UPDATE; - - /** - * The hashcode value for this element. - */ - public int valHashCode = -1; - - /** Constructor for the LateralElementDescriptor object */ - public LateralElementDescriptor() - { - super(); - } - - /** - * Constructor for the LateralElementDescriptor object - *

- * @param ce ICacheElement<K, V> payload - */ - public LateralElementDescriptor( ICacheElement ce ) - { - this.ce = ce; - } - - /** - * @return String, all the important values that can be configured - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n LateralElementDescriptor " ); - buf.append( "\n command = [" + this.command + "]" ); - buf.append( "\n valHashCode = [" + this.valHashCode + "]" ); - buf.append( "\n ICacheElement = [" + this.ce + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheAttributes.java deleted file mode 100644 index 07b018302bf..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheAttributes.java +++ /dev/null @@ -1,200 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; - -/** - * This interface defines configuration options common to lateral cache plugins. - *

- * TODO it needs to be trimmed down. The old version had features for every lateral. Now, the - * individual laterals have their own specific attributes interfaces. - */ -public interface ILateralCacheAttributes - extends AuxiliaryCacheAttributes -{ - enum Type - { - /** HTTP type */ - HTTP, // 1 - - /** UDP type */ - UDP, // 2 - - /** TCP type */ - TCP, // 3 - - /** XMLRPC type */ - XMLRPC // 4 - } - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - */ - int DEFAULT_ZOMBIE_QUEUE_MAX_SIZE = 1000; - - /** - * Sets the httpServer attribute of the ILateralCacheAttributes object - *

- * @param val The new httpServer value - */ - void setHttpServer( String val ); - - /** - * Gets the httpServer attribute of the ILateralCacheAttributes object - *

- * @return The httpServer value - */ - String getHttpServer(); - - /** - * Sets the httpListenerPort attribute of the ILateralCacheAttributes object - *

- * @param val The new tcpListenerPort value - */ - void setHttpListenerPort( int val ); - - /** - * Gets the httpListenerPort attribute of the ILateralCacheAttributes object - *

- * @return The httpListenerPort value - */ - int getHttpListenerPort(); - - /** - * Sets the httpServers attribute of the LateralCacheAttributes object - *

- * @param val The new httpServers value - */ - void setHttpServers( String val ); - - /** - * Gets the httpSrvers attribute of the LateralCacheAttributes object - *

- * @return The httpServers value - */ - String getHttpServers(); - - /** - * Sets the udpMulticastAddr attribute of the ILateralCacheAttributes object - *

- * @param val The new udpMulticastAddr value - */ - void setUdpMulticastAddr( String val ); - - /** - * Gets the udpMulticastAddr attribute of the ILateralCacheAttributes object - *

- * @return The udpMulticastAddr value - */ - String getUdpMulticastAddr(); - - /** - * Sets the udpMulticastPort attribute of the ILateralCacheAttributes object - *

- * @param val The new udpMulticastPort value - */ - void setUdpMulticastPort( int val ); - - /** - * Gets the udpMulticastPort attribute of the ILateralCacheAttributes object - *

- * @return The udpMulticastPort value - */ - int getUdpMulticastPort(); - - /** - * Sets the transmissionType attribute of the ILateralCacheAttributes object - *

- * @param val The new transmissionType value - */ - void setTransmissionType( Type val ); - - /** - * Gets the transmissionType attribute of the ILateralCacheAttributes object - *

- * @return The transmissionType value - */ - Type getTransmissionType(); - - /** - * Sets the transmissionTypeName attribute of the ILateralCacheAttributes object - *

- * @param val The new transmissionTypeName value - */ - void setTransmissionTypeName( String val ); - - /** - * Gets the transmissionTypeName attribute of the ILateralCacheAttributes object - *

- * @return The transmissionTypeName value - */ - String getTransmissionTypeName(); - - /** - * Sets the putOnlyMode attribute of the ILateralCacheAttributes. When this is true the lateral - * cache will only issue put and remove order and will not try to retrieve elements from other - * lateral caches. - *

- * @param val The new transmissionTypeName value - */ - void setPutOnlyMode( boolean val ); - - /** - * @return The outgoingOnlyMode value. Stops gets from going remote. - */ - boolean getPutOnlyMode(); - - /** - * @param receive The receive to set. - */ - void setReceive( boolean receive ); - - /** - * Should a listener be created. By default this is true. - *

- * If this is false the lateral will connect to others but it will not create a listener to - * receive. - *

- * It is possible if two laterals are misconfigured that lateral A may have a region R1 that is - * not configured for the lateral but another is. And if cache B has region R1 configured for - * lateral distribution, A will get messages for R1 but not send them. - *

- * @return true if we should have a listener connection - */ - boolean isReceive(); - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @param zombieQueueMaxSize The zombieQueueMaxSize to set. - */ - void setZombieQueueMaxSize( int zombieQueueMaxSize ); - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @return Returns the zombieQueueMaxSize. - */ - int getZombieQueueMaxSize(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheListener.java b/src/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheListener.java deleted file mode 100644 index 581f593d122..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheListener.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; - -/** - * Listens for lateral cache event notification. - */ -public interface ILateralCacheListener - extends ICacheListener -{ - /** - * Initialize this listener - */ - void init(); - - /** - * @param cacheMgr - * The cacheMgr to set. - */ - void setCacheManager( ICompositeCacheManager cacheMgr ); - - /** - * @return Returns the cacheMgr. - */ - ICompositeCacheManager getCacheManager(); - - /** - * Dispose this listener - */ - void dispose(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/package.html b/src/org/apache/commons/jcs/auxiliary/lateral/package.html deleted file mode 100644 index d38b4cccae5..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/package.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - Root package for the lateral cache family. Lateral caches broadcast puts - and removals to other local caches. - - diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java deleted file mode 100644 index c080fc41a68..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java +++ /dev/null @@ -1,452 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.socket.tcp; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.ArrayList; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.LateralCache; -import org.apache.commons.jcs.auxiliary.lateral.LateralCacheMonitor; -import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWait; -import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWaitFacade; -import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; -import org.apache.commons.jcs.engine.CacheWatchRepairable; -import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; -import org.apache.commons.jcs.engine.ZombieCacheWatch; -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.behavior.IShutdownObserver; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.utils.discovery.UDPDiscoveryManager; -import org.apache.commons.jcs.utils.discovery.UDPDiscoveryService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Constructs a LateralCacheNoWaitFacade for the given configuration. Each lateral service / local - * relationship is managed by one manager. This manager can have multiple caches. The remote - * relationships are consolidated and restored via these managers. - *

- * The facade provides a front to the composite cache so the implementation is transparent. - */ -public class LateralTCPCacheFactory - extends AbstractAuxiliaryCacheFactory -{ - /** The logger */ - private static final Log log = LogFactory.getLog( LateralTCPCacheFactory.class ); - - /** Address to service map. */ - private ConcurrentHashMap> csnlInstances; - - /** Lock for initialization of address to service map */ - private ReentrantLock csnlLock; - - /** Map of available discovery listener instances, keyed by port. */ - private ConcurrentHashMap lTCPDLInstances; - - /** Monitor thread */ - private LateralCacheMonitor monitor; - - /** - * Wrapper of the lateral cache watch service; or wrapper of a zombie - * service if failed to connect. - */ - private CacheWatchRepairable lateralWatch; - - /** - * Creates a TCP lateral. - *

- * @param iaca - * @param cacheMgr - * @param cacheEventLogger - * @param elementSerializer - * @return LateralCacheNoWaitFacade - */ - @Override - public LateralCacheNoWaitFacade createCache( - AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - { - ITCPLateralCacheAttributes lac = (ITCPLateralCacheAttributes) iaca; - ArrayList> noWaits = new ArrayList>(); - - // pairs up the tcp servers and set the tcpServer value and - // get the manager and then get the cache - // no servers are required. - if ( lac.getTcpServers() != null ) - { - StringTokenizer it = new StringTokenizer( lac.getTcpServers(), "," ); - if ( log.isDebugEnabled() ) - { - log.debug( "Configured for [" + it.countTokens() + "] servers." ); - } - while ( it.hasMoreElements() ) - { - String server = (String) it.nextElement(); - if ( log.isDebugEnabled() ) - { - log.debug( "tcp server = " + server ); - } - ITCPLateralCacheAttributes lacC = (ITCPLateralCacheAttributes) lac.clone(); - lacC.setTcpServer( server ); - - LateralCacheNoWait lateralNoWait = createCacheNoWait(lacC, cacheEventLogger, elementSerializer); - - addListenerIfNeeded( lacC, cacheMgr ); - monitor.addCache(lateralNoWait); - noWaits.add( lateralNoWait ); - } - } - - ILateralCacheListener listener = createListener( lac, cacheMgr ); - - // create the no wait facade. - @SuppressWarnings("unchecked") // No generic arrays in java - LateralCacheNoWait[] lcnwArray = noWaits.toArray( new LateralCacheNoWait[0] ); - LateralCacheNoWaitFacade lcnwf = - new LateralCacheNoWaitFacade(listener, lcnwArray, lac ); - - // create udp discovery if available. - createDiscoveryService( lac, lcnwf, cacheMgr, cacheEventLogger, elementSerializer ); - - return lcnwf; - } - - protected LateralCacheNoWait createCacheNoWait( ITCPLateralCacheAttributes lca, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - { - ICacheServiceNonLocal lateralService = getCSNLInstance(lca); - - LateralCache cache = new LateralCache( lca, lateralService, this.monitor ); - cache.setCacheEventLogger( cacheEventLogger ); - cache.setElementSerializer( elementSerializer ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Created cache for noWait, cache [" + cache + "]" ); - } - - LateralCacheNoWait lateralNoWait = new LateralCacheNoWait( cache ); - lateralNoWait.setCacheEventLogger( cacheEventLogger ); - lateralNoWait.setElementSerializer( elementSerializer ); - - if ( log.isInfoEnabled() ) - { - log.info( "Created LateralCacheNoWait for [" + lca + "] LateralCacheNoWait = [" + lateralNoWait - + "]" ); - } - - return lateralNoWait; - } - - /** - * Initialize this factory - */ - @Override - public void initialize() - { - this.csnlInstances = new ConcurrentHashMap>(); - this.csnlLock = new ReentrantLock(); - this.lTCPDLInstances = new ConcurrentHashMap(); - - // Create the monitoring daemon thread - this.monitor = new LateralCacheMonitor(this); - this.monitor.setDaemon( true ); - this.monitor.start(); - - this.lateralWatch = new CacheWatchRepairable(); - this.lateralWatch.setCacheWatch( new ZombieCacheWatch() ); - } - - /** - * Dispose of this factory, clean up shared resources - */ - @Override - public void dispose() - { - for (ICacheServiceNonLocal service : this.csnlInstances.values()) - { - try - { - service.dispose(""); - } - catch (IOException e) - { - log.error("Could not dispose service " + service, e); - } - } - - this.csnlInstances.clear(); - - // TODO: shut down discovery listeners - this.lTCPDLInstances.clear(); - - if (this.monitor != null) - { - this.monitor.notifyShutdown(); - try - { - this.monitor.join(5000); - } - catch (InterruptedException e) - { - // swallow - } - this.monitor = null; - } - } - - /** - * Returns an instance of the cache service. - *

- * @param lca configuration for the creation of a new service instance - * - * @return ICacheServiceNonLocal<K, V> - */ - // Need to cast because of common map for all cache services - @SuppressWarnings("unchecked") - public ICacheServiceNonLocal getCSNLInstance( ITCPLateralCacheAttributes lca ) - { - String key = lca.getTcpServer(); - - ICacheServiceNonLocal service = (ICacheServiceNonLocal)csnlInstances.get( key ); - - if ( service == null || service instanceof ZombieCacheServiceNonLocal ) - { - csnlLock.lock(); - - try - { - // double check - service = (ICacheServiceNonLocal)csnlInstances.get( key ); - - // If service creation did not succeed last time, force retry - if ( service instanceof ZombieCacheServiceNonLocal) - { - service = null; - log.info("Disposing of zombie service instance for [" + key + "]"); - } - - if ( service == null ) - { - log.info( "Instance for [" + key + "] is null, creating" ); - - // Create the service - try - { - if ( log.isInfoEnabled() ) - { - log.info( "Creating TCP service, lca = " + lca ); - } - - service = new LateralTCPService( lca ); - } - catch ( IOException ex ) - { - // Failed to connect to the lateral server. - // Configure this LateralCacheManager instance to use the - // "zombie" services. - log.error( "Failure, lateral instance will use zombie service", ex ); - - service = new ZombieCacheServiceNonLocal( lca.getZombieQueueMaxSize() ); - - // Notify the cache monitor about the error, and kick off - // the recovery process. - monitor.notifyError(); - } - - csnlInstances.put( key, service ); - } - } - finally - { - csnlLock.unlock(); - } - } - - return service; - } - - /** - * Gets the instance attribute of the LateralCacheTCPListener class. - *

- * @param ilca ITCPLateralCacheAttributes - * @param cacheManager a reference to the global cache manager - * - * @return The instance value - */ - private LateralTCPDiscoveryListener getDiscoveryListener( ITCPLateralCacheAttributes ilca, ICompositeCacheManager cacheManager ) - { - String key = ilca.getUdpDiscoveryAddr() + ":" + ilca.getUdpDiscoveryPort(); - LateralTCPDiscoveryListener ins = null; - - LateralTCPDiscoveryListener newListener = new LateralTCPDiscoveryListener( this.getName(), cacheManager); - ins = lTCPDLInstances.putIfAbsent(key, newListener ); - - if ( ins == null ) - { - ins = newListener; - - if ( log.isInfoEnabled() ) - { - log.info( "Created new discovery listener for " + key + " cacheName for request " + ilca.getCacheName() ); - } - } - - return ins; - } - - /** - * Add listener for receivers - *

- * @param iaca cache configuration attributes - * @param cacheMgr the composite cache manager - */ - private void addListenerIfNeeded( ITCPLateralCacheAttributes iaca, ICompositeCacheManager cacheMgr ) - { - // don't create a listener if we are not receiving. - if ( iaca.isReceive() ) - { - try - { - addLateralCacheListener( iaca.getCacheName(), LateralTCPListener.getInstance( iaca, cacheMgr ) ); - } - catch ( IOException ioe ) - { - log.error( "Problem creating lateral listener", ioe ); - } - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Not creating a listener since we are not receiving." ); - } - } - } - - /** - * Adds the lateral cache listener to the underlying cache-watch service. - *

- * @param cacheName The feature to be added to the LateralCacheListener attribute - * @param listener The feature to be added to the LateralCacheListener attribute - * @throws IOException - */ - private void addLateralCacheListener( String cacheName, ILateralCacheListener listener ) - throws IOException - { - synchronized ( this.lateralWatch ) - { - lateralWatch.addCacheListener( cacheName, listener ); - } - } - - /** - * Makes sure a listener gets created. It will get monitored as soon as it - * is used. - *

- * This should be called by create cache. - *

- * @param attr ITCPLateralCacheAttributes - * @param cacheMgr - * - * @return the listener if created, else null - */ - private ILateralCacheListener createListener( ITCPLateralCacheAttributes attr, - ICompositeCacheManager cacheMgr ) - { - ILateralCacheListener listener = null; - - // don't create a listener if we are not receiving. - if ( attr.isReceive() ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Getting listener for " + attr ); - } - - // make a listener. if one doesn't exist - listener = LateralTCPListener.getInstance( attr, cacheMgr ); - - // register for shutdown notification - cacheMgr.registerShutdownObserver( (IShutdownObserver) listener ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Not creating a listener since we are not receiving." ); - } - } - - return listener; - } - - /** - * Creates the discovery service. Only creates this for tcp laterals right now. - *

- * @param lac ITCPLateralCacheAttributes - * @param lcnwf - * @param cacheMgr - * @param cacheEventLogger - * @param elementSerializer - * @return null if none is created. - */ - private synchronized UDPDiscoveryService createDiscoveryService( - ITCPLateralCacheAttributes lac, - LateralCacheNoWaitFacade lcnwf, - ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, - IElementSerializer elementSerializer ) - { - UDPDiscoveryService discovery = null; - - // create the UDP discovery for the TCP lateral - if ( lac.isUdpDiscoveryEnabled() ) - { - // One can be used for all regions - LateralTCPDiscoveryListener discoveryListener = getDiscoveryListener( lac, cacheMgr ); - discoveryListener.addNoWaitFacade( lac.getCacheName(), lcnwf ); - - // need a factory for this so it doesn't - // get dereferenced, also we don't want one for every region. - discovery = UDPDiscoveryManager.getInstance().getService( lac.getUdpDiscoveryAddr(), - lac.getUdpDiscoveryPort(), - lac.getTcpListenerPort(), cacheMgr); - - discovery.addParticipatingCacheName( lac.getCacheName() ); - discovery.addDiscoveryListener( discoveryListener ); - - if ( log.isInfoEnabled() ) - { - log.info( "Registered TCP lateral cache [" + lac.getCacheName() + "] with UDPDiscoveryService." ); - } - } - return discovery; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java b/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java deleted file mode 100644 index 4d6fd73b946..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java +++ /dev/null @@ -1,343 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.socket.tcp; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWait; -import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWaitFacade; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.utils.discovery.DiscoveredService; -import org.apache.commons.jcs.utils.discovery.behavior.IDiscoveryListener; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * This knows how to add and remove discovered services. It observes UDP discovery events. - *

- * We can have one listener per region, or one shared by all regions. - */ -public class LateralTCPDiscoveryListener - implements IDiscoveryListener -{ - /** The log factory */ - private static final Log log = LogFactory.getLog( LateralTCPDiscoveryListener.class ); - - /** - * Map of no wait facades. these are used to determine which regions are locally configured to - * use laterals. - */ - private final Map> facades = - Collections.synchronizedMap( new HashMap>() ); - - /** - * List of regions that are configured differently here than on another server. We keep track of - * this to limit the amount of info logging. - */ - private final Set knownDifferentlyConfiguredRegions = - Collections.synchronizedSet( new HashSet() ); - - /** The name of the cache factory */ - private String factoryName; - - /** Reference to the cache manager for auxiliary cache access */ - private ICompositeCacheManager cacheManager; - - /** - * This plugs into the udp discovery system. It will receive add and remove events. - *

- * @param factoryName the name of the related cache factory - * @param cacheManager the global cache manager - */ - protected LateralTCPDiscoveryListener( String factoryName, ICompositeCacheManager cacheManager ) - { - this.factoryName = factoryName; - this.cacheManager = cacheManager; - } - - /** - * Adds a nowait facade under this cachename. If one already existed, it will be overridden. - *

- * This adds nowaits to a facade for the region name. If the region has no facade, then it is - * not configured to use the lateral cache, and no facade will be created. - *

- * @param cacheName - the region name - * @param facade - facade (for region) => multiple lateral clients. - * @return true if the facade was not already registered. - */ - public synchronized boolean addNoWaitFacade( String cacheName, LateralCacheNoWaitFacade facade ) - { - boolean isNew = !containsNoWaitFacade( cacheName ); - - // override or put anew, it doesn't matter - facades.put( cacheName, facade ); - knownDifferentlyConfiguredRegions.remove( cacheName ); - - return isNew; - } - - /** - * Allows us to see if the facade is present. - *

- * @param cacheName - facades are for a region - * @return do we contain the no wait. true if so - */ - public boolean containsNoWaitFacade( String cacheName ) - { - return facades.containsKey( cacheName ); - } - - /** - * Allows us to see if the facade is present and if it has the no wait. - *

- * @param cacheName - facades are for a region - * @param noWait - is this no wait in the facade - * @return do we contain the no wait. true if so - */ - public boolean containsNoWait( String cacheName, LateralCacheNoWait noWait ) - { - @SuppressWarnings("unchecked") // Need to cast because of common map for all facades - LateralCacheNoWaitFacade facade = (LateralCacheNoWaitFacade)facades.get( noWait.getCacheName() ); - if ( facade == null ) - { - return false; - } - - return facade.containsNoWait( noWait ); - } - - /** - * When a broadcast is received from the UDP Discovery receiver, for each cacheName in the - * message, the add no wait will be called here. To add a no wait, the facade is looked up for - * this cache name. - *

- * Each region has a facade. The facade contains a list of end points--the other tcp lateral - * services. - *

- * @param noWait - * @return true if we found the no wait and added it. False if the no wait was not present or it - * we already had it. - */ - protected boolean addNoWait( LateralCacheNoWait noWait ) - { - @SuppressWarnings("unchecked") // Need to cast because of common map for all facades - LateralCacheNoWaitFacade facade = (LateralCacheNoWaitFacade)facades.get( noWait.getCacheName() ); - if ( log.isDebugEnabled() ) - { - log.debug( "addNoWait > Got facade for " + noWait.getCacheName() + " = " + facade ); - } - - if ( facade != null ) - { - boolean isNew = facade.addNoWait( noWait ); - if ( log.isDebugEnabled() ) - { - log.debug( "Called addNoWait, isNew = " + isNew ); - } - return isNew; - } - else - { - if ( !knownDifferentlyConfiguredRegions.contains( noWait.getCacheName() ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "addNoWait > Different nodes are configured differently or region [" - + noWait.getCacheName() + "] is not yet used on this side. " ); - } - knownDifferentlyConfiguredRegions.add( noWait.getCacheName() ); - } - return false; - } - } - - /** - * Look up the facade for the name. If it doesn't exist, then the region is not configured for - * use with the lateral cache. If it is present, remove the item from the no wait list. - *

- * @param noWait - * @return true if we found the no wait and removed it. False if the no wait was not present. - */ - protected boolean removeNoWait( LateralCacheNoWait noWait ) - { - @SuppressWarnings("unchecked") // Need to cast because of common map for all facades - LateralCacheNoWaitFacade facade = (LateralCacheNoWaitFacade)facades.get( noWait.getCacheName() ); - if ( log.isDebugEnabled() ) - { - log.debug( "removeNoWait > Got facade for " + noWait.getCacheName() + " = " + facade ); - } - - if ( facade != null ) - { - boolean removed = facade.removeNoWait( noWait ); - if ( log.isDebugEnabled() ) - { - log.debug( "Called removeNoWait, removed " + removed ); - } - return removed; - } - else - { - if ( !knownDifferentlyConfiguredRegions.contains( noWait.getCacheName() ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "removeNoWait > Different nodes are configured differently or region [" - + noWait.getCacheName() + "] is not yet used on this side. " ); - } - knownDifferentlyConfiguredRegions.add( noWait.getCacheName() ); - } - return false; - } - } - - /** - * Creates the lateral cache if needed. - *

- * We could go to the composite cache manager and get the the cache for the region. This would - * force a full configuration of the region. One advantage of this would be that the creation of - * the later would go through the factory, which would add the item to the no wait list. But we - * don't want to do this. This would force this client to have all the regions as the other. - * This might not be desired. We don't want to send or receive for a region here that is either - * not used or not configured to use the lateral. - *

- * Right now, I'm afraid that the region will get puts if another instance has the region - * configured to use the lateral and our address is configured. This might be a bug, but it - * shouldn't happen with discovery. - *

- * @param service - */ - @Override - public void addDiscoveredService( DiscoveredService service ) - { - // get a cache and add it to the no waits - // the add method should not add the same. - // we need the listener port from the original config. - ArrayList regions = service.getCacheNames(); - String serverAndPort = service.getServiceAddress() + ":" + service.getServicePort(); - - if ( regions != null ) - { - // for each region get the cache - for (String cacheName : regions) - { - AuxiliaryCache ic = cacheManager.getAuxiliaryCache(factoryName, cacheName); - - if ( log.isDebugEnabled() ) - { - log.debug( "Got cache, ic = " + ic ); - } - - // add this to the nowaits for this cachename - if ( ic != null ) - { - AuxiliaryCacheAttributes aca = ic.getAuxiliaryCacheAttributes(); - if (aca instanceof ITCPLateralCacheAttributes) - { - ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)aca; - if (lca.getTransmissionType() != LateralCacheAttributes.Type.TCP - || !serverAndPort.equals(lca.getTcpServer()) ) - { - // skip caches not belonging to this service - continue; - } - } - - addNoWait( (LateralCacheNoWait) ic ); - if ( log.isDebugEnabled() ) - { - log.debug( "Called addNoWait for cacheName [" + cacheName + "]" ); - } - } - } - } - else - { - log.warn( "No cache names found in message " + service ); - } - } - - /** - * Removes the lateral cache. - *

- * We need to tell the manager that this instance is bad, so it will reconnect the sender if it - * comes back. - *

- * @param service - */ - @Override - public void removeDiscoveredService( DiscoveredService service ) - { - // get a cache and add it to the no waits - // the add method should not add the same. - // we need the listener port from the original config. - ArrayList regions = service.getCacheNames(); - String serverAndPort = service.getServiceAddress() + ":" + service.getServicePort(); - - if ( regions != null ) - { - // for each region get the cache - for (String cacheName : regions) - { - AuxiliaryCache ic = cacheManager.getAuxiliaryCache(factoryName, cacheName); - - if ( log.isDebugEnabled() ) - { - log.debug( "Got cache, ic = " + ic ); - } - - // remove this to the nowaits for this cachename - if ( ic != null ) - { - AuxiliaryCacheAttributes aca = ic.getAuxiliaryCacheAttributes(); - if (aca instanceof ITCPLateralCacheAttributes) - { - ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)aca; - if (lca.getTransmissionType() != LateralCacheAttributes.Type.TCP - || !serverAndPort.equals(lca.getTcpServer()) ) - { - // skip caches not belonging to this service - continue; - } - } - - removeNoWait( (LateralCacheNoWait) ic ); - if ( log.isDebugEnabled() ) - { - log.debug( "Called removeNoWait for cacheName [" + cacheName + "]" ); - } - } - } - } - else - { - log.warn( "No cache names found in message " + service ); - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPListener.java b/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPListener.java deleted file mode 100644 index 5a41c2d4c3e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPListener.java +++ /dev/null @@ -1,770 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.socket.tcp; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.EOFException; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.auxiliary.lateral.LateralElementDescriptor; -import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; -import org.apache.commons.jcs.engine.CacheInfo; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IShutdownObserver; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.CompositeCacheManager; -import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware; -import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Listens for connections from other TCP lateral caches and handles them. The initialization method - * starts a listening thread, which creates a socket server. When messages are received they are - * passed to a pooled executor which then calls the appropriate handle method. - */ -public class LateralTCPListener - implements ILateralCacheListener, IShutdownObserver -{ - /** The logger */ - private static final Log log = LogFactory.getLog( LateralTCPListener.class ); - - /** How long the server will block on an accept(). 0 is infinite. */ - private static final int acceptTimeOut = 1000; - - /** The CacheHub this listener is associated with */ - private transient ICompositeCacheManager cacheManager; - - /** Map of available instances, keyed by port */ - private static final HashMap> instances = - new HashMap>(); - - /** The socket listener */ - private ListenerThread receiver; - - /** Configuration attributes */ - private ITCPLateralCacheAttributes tcpLateralCacheAttributes; - - /** Listening port */ - private int port; - - /** The processor. We should probably use an event queue here. */ - private ExecutorService pooledExecutor; - - /** put count */ - private int putCnt = 0; - - /** remove count */ - private int removeCnt = 0; - - /** get count */ - private int getCnt = 0; - - /** - * Use the vmid by default. This can be set for testing. If we ever need to run more than one - * per vm, then we need a new technique. - */ - private long listenerId = CacheInfo.listenerId; - - /** is this shut down? */ - private AtomicBoolean shutdown; - - /** is this terminated? */ - private AtomicBoolean terminated; - - /** - * Gets the instance attribute of the LateralCacheTCPListener class. - *

- * @param ilca ITCPLateralCacheAttributes - * @param cacheMgr - * @return The instance value - */ - public synchronized static LateralTCPListener - getInstance( ITCPLateralCacheAttributes ilca, ICompositeCacheManager cacheMgr ) - { - @SuppressWarnings("unchecked") // Need to cast because of common map for all instances - LateralTCPListener ins = (LateralTCPListener) instances.get( String.valueOf( ilca.getTcpListenerPort() ) ); - - if ( ins == null ) - { - ins = new LateralTCPListener( ilca ); - - ins.init(); - ins.setCacheManager( cacheMgr ); - - instances.put( String.valueOf( ilca.getTcpListenerPort() ), ins ); - - if ( log.isInfoEnabled() ) - { - log.info( "Created new listener " + ilca.getTcpListenerPort() ); - } - } - - return ins; - } - - /** - * Only need one since it does work for all regions, just reference by multiple region names. - *

- * @param ilca - */ - protected LateralTCPListener( ITCPLateralCacheAttributes ilca ) - { - this.setTcpLateralCacheAttributes( ilca ); - } - - /** - * This starts the ListenerThread on the specified port. - */ - @Override - public synchronized void init() - { - try - { - this.port = getTcpLateralCacheAttributes().getTcpListenerPort(); - - pooledExecutor = Executors.newCachedThreadPool( - new DaemonThreadFactory("JCS-LateralTCPListener-")); - terminated = new AtomicBoolean(false); - shutdown = new AtomicBoolean(false); - - log.info( "Listening on port " + port ); - - ServerSocket serverSocket = new ServerSocket( port ); - serverSocket.setSoTimeout( acceptTimeOut ); - - receiver = new ListenerThread(serverSocket); - receiver.setDaemon( true ); - receiver.start(); - } - catch ( IOException ex ) - { - throw new IllegalStateException( ex ); - } - } - - /** - * Let the lateral cache set a listener_id. Since there is only one listener for all the - * regions and every region gets registered? the id shouldn't be set if it isn't zero. If it is - * we assume that it is a reconnect. - *

- * By default, the listener id is the vmid. - *

- * The service should set this value. This value will never be changed by a server we connect - * to. It needs to be non static, for unit tests. - *

- * The service will use the value it sets in all send requests to the sender. - *

- * @param id The new listenerId value - * @throws IOException - */ - @Override - public void setListenerId( long id ) - throws IOException - { - this.listenerId = id; - if ( log.isDebugEnabled() ) - { - log.debug( "set listenerId = " + id ); - } - } - - /** - * Gets the listenerId attribute of the LateralCacheTCPListener object - *

- * @return The listenerId value - * @throws IOException - */ - @Override - public long getListenerId() - throws IOException - { - return this.listenerId; - } - - /** - * Increments the put count. Gets the cache that was injected by the lateral factory. Calls put - * on the cache. - *

- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handlePut(org.apache.commons.jcs.engine.behavior.ICacheElement) - */ - @Override - public void handlePut( ICacheElement element ) - throws IOException - { - putCnt++; - if ( log.isInfoEnabled() ) - { - if ( getPutCnt() % 100 == 0 ) - { - log.info( "Put Count (port " + getTcpLateralCacheAttributes().getTcpListenerPort() + ") = " - + getPutCnt() ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "handlePut> cacheName=" + element.getCacheName() + ", key=" + element.getKey() ); - } - - getCache( element.getCacheName() ).localUpdate( element ); - } - - /** - * Increments the remove count. Gets the cache that was injected by the lateral factory. Calls - * remove on the cache. - *

- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handleRemove(java.lang.String, - * Object) - */ - @Override - public void handleRemove( String cacheName, K key ) - throws IOException - { - removeCnt++; - if ( log.isInfoEnabled() ) - { - if ( getRemoveCnt() % 100 == 0 ) - { - log.info( "Remove Count = " + getRemoveCnt() ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "handleRemove> cacheName=" + cacheName + ", key=" + key ); - } - - getCache( cacheName ).localRemove( key ); - } - - /** - * Gets the cache that was injected by the lateral factory. Calls removeAll on the cache. - *

- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handleRemoveAll(java.lang.String) - */ - @Override - public void handleRemoveAll( String cacheName ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "handleRemoveAll> cacheName=" + cacheName ); - } - - getCache( cacheName ).localRemoveAll(); - } - - /** - * Gets the cache that was injected by the lateral factory. Calls get on the cache. - *

- * @param cacheName - * @param key - * @return a ICacheElement - * @throws IOException - */ - public ICacheElement handleGet( String cacheName, K key ) - throws IOException - { - getCnt++; - if ( log.isInfoEnabled() ) - { - if ( getGetCnt() % 100 == 0 ) - { - log.info( "Get Count (port " + getTcpLateralCacheAttributes().getTcpListenerPort() + ") = " - + getGetCnt() ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "handleGet> cacheName=" + cacheName + ", key = " + key ); - } - - return getCache( cacheName ).localGet( key ); - } - - /** - * Gets the cache that was injected by the lateral factory. Calls get on the cache. - *

- * @param cacheName the name of the cache - * @param pattern the matching pattern - * @return Map - * @throws IOException - */ - public Map> handleGetMatching( String cacheName, String pattern ) - throws IOException - { - getCnt++; - if ( log.isInfoEnabled() ) - { - if ( getGetCnt() % 100 == 0 ) - { - log.info( "GetMatching Count (port " + getTcpLateralCacheAttributes().getTcpListenerPort() + ") = " - + getGetCnt() ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "handleGetMatching> cacheName=" + cacheName + ", pattern = " + pattern ); - } - - return getCache( cacheName ).localGetMatching( pattern ); - } - - /** - * Gets the cache that was injected by the lateral factory. Calls getKeySet on the cache. - *

- * @param cacheName the name of the cache - * @return a set of keys - * @throws IOException - */ - public Set handleGetKeySet( String cacheName ) throws IOException - { - return getCache( cacheName ).getKeySet(true); - } - - /** - * This marks this instance as terminated. - *

- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handleDispose(java.lang.String) - */ - @Override - public void handleDispose( String cacheName ) - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "handleDispose > cacheName=" + cacheName + " | Ignoring message. Do not dispose from remote." ); - } - - // TODO handle active deregistration, rather than passive detection - terminated.set(true); - } - - @Override - public synchronized void dispose() - { - terminated.set(true); - notify(); - - pooledExecutor.shutdownNow(); - } - - /** - * Gets the cacheManager attribute of the LateralCacheTCPListener object. - *

- * Normally this is set by the factory. If it wasn't set the listener defaults to the expected - * singleton behavior of the cache manager. - *

- * @param name - * @return CompositeCache - */ - protected CompositeCache getCache( String name ) - { - if ( getCacheManager() == null ) - { - // revert to singleton on failure - try - { - setCacheManager( CompositeCacheManager.getInstance() ); - } - catch (CacheException e) - { - throw new RuntimeException("Could not retrieve cache manager instance", e); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "cacheMgr = " + getCacheManager() ); - } - } - - return getCacheManager().getCache( name ); - } - - /** - * This is roughly the number of updates the lateral has received. - *

- * @return Returns the putCnt. - */ - public int getPutCnt() - { - return putCnt; - } - - /** - * @return Returns the getCnt. - */ - public int getGetCnt() - { - return getCnt; - } - - /** - * @return Returns the removeCnt. - */ - public int getRemoveCnt() - { - return removeCnt; - } - - /** - * @param cacheMgr The cacheMgr to set. - */ - @Override - public void setCacheManager( ICompositeCacheManager cacheMgr ) - { - this.cacheManager = cacheMgr; - } - - /** - * @return Returns the cacheMgr. - */ - @Override - public ICompositeCacheManager getCacheManager() - { - return cacheManager; - } - - /** - * @param tcpLateralCacheAttributes The tcpLateralCacheAttributes to set. - */ - public void setTcpLateralCacheAttributes( ITCPLateralCacheAttributes tcpLateralCacheAttributes ) - { - this.tcpLateralCacheAttributes = tcpLateralCacheAttributes; - } - - /** - * @return Returns the tcpLateralCacheAttributes. - */ - public ITCPLateralCacheAttributes getTcpLateralCacheAttributes() - { - return tcpLateralCacheAttributes; - } - - /** - * Processes commands from the server socket. There should be one listener for each configured - * TCP lateral. - */ - public class ListenerThread - extends Thread - { - /** The socket listener */ - private final ServerSocket serverSocket; - - /** - * Constructor - * - * @param serverSocket - */ - public ListenerThread(ServerSocket serverSocket) - { - super(); - this.serverSocket = serverSocket; - } - - /** Main processing method for the ListenerThread object */ - @SuppressWarnings("synthetic-access") - @Override - public void run() - { - try - { - ConnectionHandler handler; - - outer: while ( true ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Waiting for clients to connect " ); - } - - Socket socket = null; - inner: while (true) - { - // Check to see if we've been asked to exit, and exit - if (terminated.get()) - { - if (log.isDebugEnabled()) - { - log.debug("Thread terminated, exiting gracefully"); - } - break outer; - } - - try - { - socket = serverSocket.accept(); - break inner; - } - catch (SocketTimeoutException e) - { - // No problem! We loop back up! - continue inner; - } - } - - if ( socket != null && log.isDebugEnabled() ) - { - InetAddress inetAddress = socket.getInetAddress(); - log.debug( "Connected to client at " + inetAddress ); - } - - handler = new ConnectionHandler( socket ); - pooledExecutor.execute( handler ); - } - } - catch ( IOException e ) - { - log.error( "Exception caught in TCP listener", e ); - } - finally - { - if (serverSocket != null) - { - try - { - serverSocket.close(); - } - catch (IOException e) - { - log.error( "Exception caught closing socket", e ); - } - } - } - } - } - - /** - * A Separate thread that runs when a command comes into the LateralTCPReceiver. - */ - public class ConnectionHandler - implements Runnable - { - /** The socket connection, passed in via constructor */ - private final Socket socket; - - /** - * Construct for a given socket - * @param socket - */ - public ConnectionHandler( Socket socket ) - { - this.socket = socket; - } - - /** - * Main processing method for the LateralTCPReceiverConnection object - */ - @Override - @SuppressWarnings({"unchecked", // Need to cast from Object - "synthetic-access" }) - public void run() - { - ObjectInputStream ois; - - try - { - ois = new ObjectInputStreamClassLoaderAware( socket.getInputStream(), null ); - } - catch ( Exception e ) - { - log.error( "Could not open ObjectInputStream on " + socket, e ); - - return; - } - - LateralElementDescriptor led; - - try - { - while ( true ) - { - led = (LateralElementDescriptor) ois.readObject(); - - if ( led == null ) - { - log.debug( "LateralElementDescriptor is null" ); - continue; - } - if ( led.requesterId == getListenerId() ) - { - log.debug( "from self" ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "receiving LateralElementDescriptor from another" + "led = " + led - + ", led.command = " + led.command + ", led.ce = " + led.ce ); - } - - handle( led ); - } - } - } - catch ( EOFException e ) - { - log.info( "Caught java.io.EOFException closing connection." + e.getMessage() ); - } - catch ( SocketException e ) - { - log.info( "Caught java.net.SocketException closing connection." + e.getMessage() ); - } - catch ( Exception e ) - { - log.error( "Unexpected exception.", e ); - } - - try - { - ois.close(); - } - catch ( IOException e ) - { - log.error( "Could not close object input stream.", e ); - } - } - - /** - * This calls the appropriate method, based on the command sent in the Lateral element - * descriptor. - *

- * @param led - * @throws IOException - */ - @SuppressWarnings("synthetic-access") - private void handle( LateralElementDescriptor led ) - throws IOException - { - String cacheName = led.ce.getCacheName(); - K key = led.ce.getKey(); - Serializable obj = null; - - switch (led.command) - { - case UPDATE: - handlePut( led.ce ); - break; - - case REMOVE: - // if a hashcode was given and filtering is on - // check to see if they are the same - // if so, then don't remove, otherwise issue a remove - if ( led.valHashCode != -1 ) - { - if ( getTcpLateralCacheAttributes().isFilterRemoveByHashCode() ) - { - ICacheElement test = getCache( cacheName ).localGet( key ); - if ( test != null ) - { - if ( test.getVal().hashCode() == led.valHashCode ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Filtering detected identical hashCode [" + led.valHashCode - + "], not issuing a remove for led " + led ); - } - return; - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Different hashcodes, in cache [" + test.getVal().hashCode() - + "] sent [" + led.valHashCode + "]" ); - } - } - } - } - } - handleRemove( cacheName, key ); - break; - - case REMOVEALL: - handleRemoveAll( cacheName ); - break; - - case GET: - obj = handleGet( cacheName, key ); - break; - - case GET_MATCHING: - obj = (Serializable) handleGetMatching( cacheName, (String) key ); - break; - - case GET_KEYSET: - obj = (Serializable) handleGetKeySet(cacheName); - break; - - default: break; - } - - if (obj != null) - { - ObjectOutputStream oos = new ObjectOutputStream( socket.getOutputStream() ); - oos.writeObject( obj ); - oos.flush(); - } - } - } - - /** - * Shuts down the receiver. - */ - @Override - public void shutdown() - { - if ( shutdown.compareAndSet(false, true) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Shutting down TCP Lateral receiver." ); - } - - receiver.interrupt(); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Shutdown already called." ); - } - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPSender.java b/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPSender.java deleted file mode 100644 index e1e2307c186..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPSender.java +++ /dev/null @@ -1,281 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.socket.tcp; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.net.InetSocketAddress; -import java.net.Socket; - -import org.apache.commons.jcs.auxiliary.lateral.LateralElementDescriptor; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; -import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class is based on the log4j SocketAppender class. I'm using a different repair structure, so - * it is significantly different. - */ -public class LateralTCPSender -{ - /** The logger */ - private static final Log log = LogFactory.getLog( LateralTCPSender.class ); - - /** Config */ - private int socketOpenTimeOut; - private int socketSoTimeOut; - - /** The stream from the server connection. */ - private ObjectOutputStream oos; - - /** The socket connection with the server. */ - private Socket socket; - - /** how many messages sent */ - private int sendCnt = 0; - - /** Use to synchronize multiple threads that may be trying to get. */ - private final Object getLock = new int[0]; - - /** - * Constructor for the LateralTCPSender object. - *

- * @param lca - * @throws IOException - */ - public LateralTCPSender( ITCPLateralCacheAttributes lca ) - throws IOException - { - this.socketOpenTimeOut = lca.getOpenTimeOut(); - this.socketSoTimeOut = lca.getSocketTimeOut(); - - String p1 = lca.getTcpServer(); - if ( p1 == null ) - { - throw new IOException( "Invalid server (null)" ); - } - - String h2 = p1.substring( 0, p1.indexOf( ":" ) ); - int po = Integer.parseInt( p1.substring( p1.indexOf( ":" ) + 1 ) ); - if ( log.isDebugEnabled() ) - { - log.debug( "h2 = " + h2 ); - log.debug( "po = " + po ); - } - - if ( h2.length() == 0 ) - { - throw new IOException( "Cannot connect to invalid address [" + h2 + ":" + po + "]" ); - } - - init( h2, po ); - } - - /** - * Creates a connection to a TCP server. - *

- * @param host - * @param port - * @throws IOException - */ - protected void init( String host, int port ) - throws IOException - { - try - { - if ( log.isInfoEnabled() ) - { - log.info( "Attempting connection to [" + host + "]" ); - } - - // have time out socket open do this for us - try - { - socket = new Socket(); - socket.connect( new InetSocketAddress( host, port ), this.socketOpenTimeOut ); - } - catch ( IOException ioe ) - { - if (socket != null) - { - socket.close(); - } - - throw new IOException( "Cannot connect to " + host + ":" + port, ioe ); - } - - socket.setSoTimeout( socketSoTimeOut ); - synchronized ( this ) - { - oos = new ObjectOutputStream( socket.getOutputStream() ); - } - } - catch ( java.net.ConnectException e ) - { - log.debug( "Remote host [" + host + "] refused connection." ); - throw e; - } - catch ( IOException e ) - { - log.debug( "Could not connect to [" + host + "]. Exception is " + e ); - throw e; - } - } - - /** - * Sends commands to the lateral cache listener. - *

- * @param led - * @throws IOException - */ - public void send( LateralElementDescriptor led ) - throws IOException - { - sendCnt++; - if ( log.isInfoEnabled() && sendCnt % 100 == 0 ) - { - log.info( "Send Count (port " + socket.getPort() + ") = " + sendCnt ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "sending LateralElementDescriptor" ); - } - - if ( led == null ) - { - return; - } - - if ( oos == null ) - { - throw new IOException( "No remote connection is available for LateralTCPSender." ); - } - - synchronized ( this.getLock ) - { - oos.writeUnshared( led ); - oos.flush(); - } - } - - /** - * Sends commands to the lateral cache listener and gets a response. I'm afraid that we could - * get into a pretty bad blocking situation here. This needs work. I just wanted to get some - * form of get working. However, get is not recommended for performance reasons. If you have 10 - * laterals, then you have to make 10 failed gets to find out none of the caches have the item. - *

- * @param led - * @return ICacheElement - * @throws IOException - */ - public Object sendAndReceive( LateralElementDescriptor led ) - throws IOException - { - if ( led == null ) - { - return null; - } - - if ( oos == null ) - { - throw new IOException( "No remote connection is available for LateralTCPSender." ); - } - - Object response = null; - - // Synchronized to insure that the get requests to server from this - // sender and the responses are processed in order, else you could - // return the wrong item from the cache. - // This is a big block of code. May need to re-think this strategy. - // This may not be necessary. - // Normal puts, etc to laterals do not have to be synchronized. - synchronized ( this.getLock ) - { - try - { - // clean up input stream, nothing should be there yet. - if ( socket.getInputStream().available() > 0 ) - { - socket.getInputStream().read( new byte[socket.getInputStream().available()] ); - } - } - catch ( IOException ioe ) - { - log.error( "Problem cleaning socket before send " + socket, ioe ); - throw ioe; - } - - // write object to listener - oos.writeUnshared( led ); - oos.flush(); - ObjectInputStream ois = null; - - try - { - socket.setSoTimeout( socketSoTimeOut ); - ois = new ObjectInputStreamClassLoaderAware( socket.getInputStream(), null ); - response = ois.readObject(); - } - catch ( IOException ioe ) - { - String message = "Could not open ObjectInputStream to " + socket + - " SoTimeout [" + socket.getSoTimeout() + - "] Connected [" + socket.isConnected() + "]"; - log.error( message, ioe ); - throw ioe; - } - catch ( Exception e ) - { - log.error( e ); - } - finally - { - if (ois != null) - { - ois.close(); - } - } - } - - return response; - } - - /** - * Closes connection used by all LateralTCPSenders for this lateral connection. Dispose request - * should come into the facade and be sent to all lateral cache services. The lateral cache - * service will then call this method. - *

- * @throws IOException - */ - public void dispose() - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "Dispose called" ); - } - // WILL CLOSE CONNECTION USED BY ALL - oos.close(); - socket.close(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPService.java b/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPService.java deleted file mode 100644 index 5f346c9ef50..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPService.java +++ /dev/null @@ -1,456 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.socket.tcp; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.auxiliary.lateral.LateralCommand; -import org.apache.commons.jcs.auxiliary.lateral.LateralElementDescriptor; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; -import org.apache.commons.jcs.engine.CacheElement; -import org.apache.commons.jcs.engine.CacheInfo; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A lateral cache service implementation. Does not implement getGroupKey - * TODO: Remove generics - */ -public class LateralTCPService - implements ICacheServiceNonLocal -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( LateralTCPService.class ); - - /** special configuration */ - private boolean allowPut; - private boolean allowGet; - private boolean issueRemoveOnPut; - - /** Sends to another lateral. */ - private LateralTCPSender sender; - - /** use the vmid by default */ - private long listenerId = CacheInfo.listenerId; - - /** - * Constructor for the LateralTCPService object - *

- * @param lca ITCPLateralCacheAttributes - * @throws IOException - */ - public LateralTCPService( ITCPLateralCacheAttributes lca ) - throws IOException - { - this.allowGet = lca.isAllowGet(); - this.allowPut = lca.isAllowPut(); - this.issueRemoveOnPut = lca.isIssueRemoveOnPut(); - - try - { - sender = new LateralTCPSender( lca ); - - if ( log.isInfoEnabled() ) - { - log.debug( "Created sender to [" + lca.getTcpServer() + "]" ); - } - } - catch ( IOException e ) - { - // log.error( "Could not create sender", e ); - // This gets thrown over and over in recovery mode. - // The stack trace isn't useful here. - log.error( "Could not create sender to [" + lca.getTcpServer() + "] -- " + e.getMessage() ); - - throw e; - } - } - - /** - * @param item - * @throws IOException - */ - @Override - public void update( ICacheElement item ) - throws IOException - { - update( item, getListenerId() ); - } - - /** - * If put is allowed, we will issue a put. If issue put on remove is configured, we will issue a - * remove. Either way, we create a lateral element descriptor, which is essentially a JCS TCP - * packet. It describes what operation the receiver should take when it gets the packet. - *

- * @see org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal#update(org.apache.commons.jcs.engine.behavior.ICacheElement, - * long) - */ - @Override - public void update( ICacheElement item, long requesterId ) - throws IOException - { - // if we don't allow put, see if we should remove on put - if ( !this.allowPut && - // if we can't remove on put, and we can't put then return - !this.issueRemoveOnPut ) - { - return; - } - - // if we shouldn't remove on put, then put - if ( !this.issueRemoveOnPut ) - { - LateralElementDescriptor led = new LateralElementDescriptor( item ); - led.requesterId = requesterId; - led.command = LateralCommand.UPDATE; - sender.send( led ); - } - // else issue a remove with the hashcode for remove check on - // on the other end, this will be a server config option - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Issuing a remove for a put" ); - } - // set the value to null so we don't send the item - CacheElement ce = new CacheElement( item.getCacheName(), item.getKey(), null ); - LateralElementDescriptor led = new LateralElementDescriptor( ce ); - led.requesterId = requesterId; - led.command = LateralCommand.REMOVE; - led.valHashCode = item.getVal().hashCode(); - sender.send( led ); - } - } - - /** - * Uses the default listener id and calls the next remove method. - *

- * @see org.apache.commons.jcs.engine.behavior.ICacheService#remove(String, Object) - */ - @Override - public void remove( String cacheName, K key ) - throws IOException - { - remove( cacheName, key, getListenerId() ); - } - - /** - * Wraps the key in a LateralElementDescriptor. - *

- * @see org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal#remove(String, Object, long) - */ - @Override - public void remove( String cacheName, K key, long requesterId ) - throws IOException - { - CacheElement ce = new CacheElement( cacheName, key, null ); - LateralElementDescriptor led = new LateralElementDescriptor( ce ); - led.requesterId = requesterId; - led.command = LateralCommand.REMOVE; - sender.send( led ); - } - - /** - * Does nothing. - *

- * @throws IOException - */ - @Override - public void release() - throws IOException - { - // nothing needs to be done - } - - /** - * Will close the connection. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void dispose( String cacheName ) - throws IOException - { - sender.dispose(); - } - - /** - * @param cacheName - * @param key - * @return ICacheElement<K, V> if found. - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key ) - throws IOException - { - return get( cacheName, key, getListenerId() ); - } - - /** - * If get is allowed, we will issues a get request. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement<K, V> if found. - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key, long requesterId ) - throws IOException - { - // if get is not allowed return - if ( this.allowGet ) - { - CacheElement ce = new CacheElement( cacheName, key, null ); - LateralElementDescriptor led = new LateralElementDescriptor( ce ); - // led.requesterId = requesterId; // later - led.command = LateralCommand.GET; - @SuppressWarnings("unchecked") // Need to cast from Object - ICacheElement response = (ICacheElement)sender.sendAndReceive( led ); - if ( response != null ) - { - return response; - } - return null; - } - else - { - // nothing needs to be done - return null; - } - } - - /** - * If allow get is true, we will issue a getmatching query. - *

- * @param cacheName - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching the pattern. - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern ) - throws IOException - { - return getMatching( cacheName, pattern, getListenerId() ); - } - - /** - * If allow get is true, we will issue a getmatching query. - *

- * @param cacheName - * @param pattern - * @param requesterId - our identity - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching the pattern. - * @throws IOException - */ - @Override - @SuppressWarnings("unchecked") // Need to cast from Object - public Map> getMatching( String cacheName, String pattern, long requesterId ) - throws IOException - { - // if get is not allowed return - if ( this.allowGet ) - { - CacheElement ce = new CacheElement( cacheName, pattern, null ); - LateralElementDescriptor led = new LateralElementDescriptor( ce ); - // led.requesterId = requesterId; // later - led.command = LateralCommand.GET_MATCHING; - - Object response = sender.sendAndReceive( led ); - if ( response != null ) - { - return (Map>) response; - } - return Collections.emptyMap(); - } - else - { - // nothing needs to be done - return null; - } - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys ) - throws IOException - { - return getMultiple( cacheName, keys, getListenerId() ); - } - - /** - * This issues a separate get for each item. - *

- * TODO We should change this. It should issue one request. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys, long requesterId ) - throws IOException - { - Map> elements = new HashMap>(); - - if ( keys != null && !keys.isEmpty() ) - { - for (K key : keys) - { - ICacheElement element = get( cacheName, key ); - - if ( element != null ) - { - elements.put( key, element ); - } - } - } - return elements; - } - - /** - * Return the keys in this cache. - *

- * @param cacheName the name of the cache region - * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - @SuppressWarnings("unchecked") // Need cast from Object - public Set getKeySet(String cacheName) throws IOException - { - CacheElement ce = new CacheElement(cacheName, null, null); - LateralElementDescriptor led = new LateralElementDescriptor(ce); - // led.requesterId = requesterId; // later - led.command = LateralCommand.GET_KEYSET; - Object response = sender.sendAndReceive(led); - if (response != null) - { - return (Set) response; - } - - return null; - } - - /** - * @param cacheName - * @throws IOException - */ - @Override - public void removeAll( String cacheName ) - throws IOException - { - removeAll( cacheName, getListenerId() ); - } - - /** - * @param cacheName - * @param requesterId - * @throws IOException - */ - @Override - public void removeAll( String cacheName, long requesterId ) - throws IOException - { - CacheElement ce = new CacheElement( cacheName, "ALL", null ); - LateralElementDescriptor led = new LateralElementDescriptor( ce ); - led.requesterId = requesterId; - led.command = LateralCommand.REMOVEALL; - sender.send( led ); - } - - /** - * @param args - */ - public static void main( String args[] ) - { - try - { - LateralTCPSender sender = new LateralTCPSender( new TCPLateralCacheAttributes() ); - - // process user input till done - boolean notDone = true; - String message = null; - // wait to dispose - BufferedReader br = new BufferedReader( new InputStreamReader( System.in, "UTF-8" ) ); - - while ( notDone ) - { - System.out.println( "enter message:" ); - message = br.readLine(); - - if (message == null) - { - notDone = false; - continue; - } - - CacheElement ce = new CacheElement( "test", "test", message ); - LateralElementDescriptor led = new LateralElementDescriptor( ce ); - sender.send( led ); - } - } - catch ( IOException e ) - { - System.out.println( e.toString() ); - } - } - - /** - * @param listernId The listernId to set. - */ - protected void setListenerId( long listernId ) - { - this.listenerId = listernId; - } - - /** - * @return Returns the listernId. - */ - protected long getListenerId() - { - return listenerId; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java deleted file mode 100644 index cac34db138e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java +++ /dev/null @@ -1,381 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.socket.tcp; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes; -import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; - -/** - * This interface defines functions that are particular to the TCP Lateral Cache plugin. It extends - * the generic LateralCacheAttributes interface which in turn extends the AuxiliaryCache interface. - */ -public class TCPLateralCacheAttributes - extends LateralCacheAttributes - implements ITCPLateralCacheAttributes -{ - /** Don't change. */ - private static final long serialVersionUID = 1077889204513905220L; - - /** default */ - private static final String DEFAULT_UDP_DISCOVERY_ADDRESS = "228.5.6.7"; - - /** default */ - private static final int DEFAULT_UDP_DISCOVERY_PORT = 6789; - - /** default */ - private static final boolean DEFAULT_UDP_DISCOVERY_ENABLED = true; - - /** default */ - private static final boolean DEFAULT_ALLOW_GET = true; - - /** default */ - private static final boolean DEFAULT_ALLOW_PUT = true; - - /** default */ - private static final boolean DEFAULT_ISSUE_REMOVE_FOR_PUT = false; - - /** default */ - private static final boolean DEFAULT_FILTER_REMOVE_BY_HASH_CODE = true; - - /** default - Only block for 1 second before timing out on a read.*/ - private static final int DEFAULT_SOCKET_TIME_OUT = 1000; - - /** default - Only block for 2 seconds before timing out on startup.*/ - private static final int DEFAULT_OPEN_TIMEOUT = 2000; - - /** TCP -------------------------------------------- */ - private String tcpServers = ""; - - /** used to identify the service that this manager will be operating on */ - private String tcpServer = ""; - - /** The pot */ - private int tcpListenerPort = 0; - - /** udp discovery for tcp server */ - private String udpDiscoveryAddr = DEFAULT_UDP_DISCOVERY_ADDRESS; - - /** discovery port */ - private int udpDiscoveryPort = DEFAULT_UDP_DISCOVERY_PORT; - - /** discovery switch */ - private boolean udpDiscoveryEnabled = DEFAULT_UDP_DISCOVERY_ENABLED; - - /** can we put */ - private boolean allowPut = DEFAULT_ALLOW_GET; - - /** can we go laterally for a get */ - private boolean allowGet = DEFAULT_ALLOW_PUT; - - /** call remove when there is a put */ - private boolean issueRemoveOnPut = DEFAULT_ISSUE_REMOVE_FOR_PUT; - - /** don't remove it the hashcode is the same */ - private boolean filterRemoveByHashCode = DEFAULT_FILTER_REMOVE_BY_HASH_CODE; - - /** Only block for socketTimeOut seconds before timing out on a read. */ - private int socketTimeOut = DEFAULT_SOCKET_TIME_OUT; - - /** Only block for openTimeOut seconds before timing out on startup. */ - private int openTimeOut = DEFAULT_OPEN_TIMEOUT; - - /** - * Sets the tcpServer attribute of the ILateralCacheAttributes object - *

- * @param val The new tcpServer value - */ - @Override - public void setTcpServer( String val ) - { - this.tcpServer = val; - } - - /** - * Gets the tcpServer attribute of the ILateralCacheAttributes object - *

- * @return The tcpServer value - */ - @Override - public String getTcpServer() - { - return this.tcpServer; - } - - /** - * Sets the tcpServers attribute of the ILateralCacheAttributes object - *

- * @param val The new tcpServers value - */ - @Override - public void setTcpServers( String val ) - { - this.tcpServers = val; - } - - /** - * Gets the tcpServers attribute of the ILateralCacheAttributes object - *

- * @return The tcpServers value - */ - @Override - public String getTcpServers() - { - return this.tcpServers; - } - - /** - * Sets the tcpListenerPort attribute of the ILateralCacheAttributes object - *

- * @param val The new tcpListenerPort value - */ - @Override - public void setTcpListenerPort( int val ) - { - this.tcpListenerPort = val; - } - - /** - * Gets the tcpListenerPort attribute of the ILateralCacheAttributes object - *

- * @return The tcpListenerPort value - */ - @Override - public int getTcpListenerPort() - { - return this.tcpListenerPort; - } - - /** - * Can setup UDP Discovery. This only works for TCp laterals right now. It allows TCP laterals - * to find each other by broadcasting to a multicast port. - *

- * @param udpDiscoveryEnabled The udpDiscoveryEnabled to set. - */ - @Override - public void setUdpDiscoveryEnabled( boolean udpDiscoveryEnabled ) - { - this.udpDiscoveryEnabled = udpDiscoveryEnabled; - } - - /** - * Whether or not TCP laterals can try to find each other by multicast communication. - *

- * @return Returns the udpDiscoveryEnabled. - */ - @Override - public boolean isUdpDiscoveryEnabled() - { - return this.udpDiscoveryEnabled; - } - - /** - * The port to use if UDPDiscovery is enabled. - *

- * @return Returns the udpDiscoveryPort. - */ - @Override - public int getUdpDiscoveryPort() - { - return this.udpDiscoveryPort; - } - - /** - * Sets the port to use if UDPDiscovery is enabled. - *

- * @param udpDiscoveryPort The udpDiscoveryPort to set. - */ - @Override - public void setUdpDiscoveryPort( int udpDiscoveryPort ) - { - this.udpDiscoveryPort = udpDiscoveryPort; - } - - /** - * The address to broadcast to if UDPDiscovery is enabled. - *

- * @return Returns the udpDiscoveryAddr. - */ - @Override - public String getUdpDiscoveryAddr() - { - return this.udpDiscoveryAddr; - } - - /** - * Sets the address to broadcast to if UDPDiscovery is enabled. - *

- * @param udpDiscoveryAddr The udpDiscoveryAddr to set. - */ - @Override - public void setUdpDiscoveryAddr( String udpDiscoveryAddr ) - { - this.udpDiscoveryAddr = udpDiscoveryAddr; - } - - /** - * Is the lateral allowed to try and get from other laterals. - *

- * This replaces the old putOnlyMode - *

- * @param allowGet - */ - @Override - public void setAllowGet( boolean allowGet ) - { - this.allowGet = allowGet; - } - - /** - * Is the lateral allowed to try and get from other laterals. - *

- * @return true if the lateral will try to get - */ - @Override - public boolean isAllowGet() - { - return this.allowGet; - } - - /** - * Is the lateral allowed to put objects to other laterals. - *

- * @param allowPut - */ - @Override - public void setAllowPut( boolean allowPut ) - { - this.allowPut = allowPut; - } - - /** - * Is the lateral allowed to put objects to other laterals. - *

- * @return true if puts are allowed - */ - @Override - public boolean isAllowPut() - { - return this.allowPut; - } - - /** - * Should the client send a remove command rather than a put when update is called. This is a - * client option, not a receiver option. This allows you to prevent the lateral from serializing - * objects. - *

- * @param issueRemoveOnPut - */ - @Override - public void setIssueRemoveOnPut( boolean issueRemoveOnPut ) - { - this.issueRemoveOnPut = issueRemoveOnPut; - } - - /** - * Should the client send a remove command rather than a put when update is called. This is a - * client option, not a receiver option. This allows you to prevent the lateral from serializing - * objects. - *

- * @return true if updates will result in a remove command being sent. - */ - @Override - public boolean isIssueRemoveOnPut() - { - return this.issueRemoveOnPut; - } - - /** - * Should the receiver try to match hashcodes. If true, the receiver will see if the client - * supplied a hashcode. If it did, then it will try to get the item locally. If the item exists, - * then it will compare the hashcode. if they are the same, it will not remove. This isn't - * perfect since different objects can have the same hashcode, but it is unlikely of objects of - * the same type. - *

- * @return boolean - */ - @Override - public boolean isFilterRemoveByHashCode() - { - return this.filterRemoveByHashCode; - } - - /** - * Should the receiver try to match hashcodes. If true, the receiver will see if the client - * supplied a hashcode. If it did, then it will try to get the item locally. If the item exists, - * then it will compare the hashcode. if they are the same, it will not remove. This isn't - * perfect since different objects can have the same hashcode, but it is unlikely of objects of - * the same type. - *

- * @param filter - */ - @Override - public void setFilterRemoveByHashCode( boolean filter ) - { - this.filterRemoveByHashCode = filter; - } - - /** - * @param socketTimeOut the socketTimeOut to set - */ - @Override - public void setSocketTimeOut( int socketTimeOut ) - { - this.socketTimeOut = socketTimeOut; - } - - /** - * @return the socketTimeOut - */ - @Override - public int getSocketTimeOut() - { - return socketTimeOut; - } - - /** - * @param openTimeOut the openTimeOut to set - */ - @Override - public void setOpenTimeOut( int openTimeOut ) - { - this.openTimeOut = openTimeOut; - } - - /** - * @return the openTimeOut - */ - @Override - public int getOpenTimeOut() - { - return openTimeOut; - } - - /** - * Used to key the instance TODO create another method for this and use toString for debugging - * only. - *

- * @return String - */ - @Override - public String toString() - { - return this.getTcpServer() + ":" + this.getTcpListenerPort(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java deleted file mode 100644 index db1280034fb..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java +++ /dev/null @@ -1,218 +0,0 @@ -package org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes; - -/** - * This interface defines functions that are particular to the TCP Lateral Cache - * plugin. It extends the generic LateralCacheAttributes interface which in turn - * extends the AuxiliaryCache interface. - *

- * @author Aaron Smuts - */ -public interface ITCPLateralCacheAttributes - extends ILateralCacheAttributes -{ - /** - * Sets the tcpServer attribute of the ILateralCacheAttributes object - *

- * @param val - * The new tcpServer value - */ - void setTcpServer( String val ); - - /** - * Gets the tcpServer attribute of the ILateralCacheAttributes object - *

- * @return The tcpServer value - */ - String getTcpServer(); - - /** - * Sets the tcpServers attribute of the ILateralCacheAttributes object - *

- * @param val - * The new tcpServers value - */ - void setTcpServers( String val ); - - /** - * Gets the tcpServers attribute of the ILateralCacheAttributes object - *

- * @return The tcpServers value - */ - String getTcpServers(); - - /** - * Sets the tcpListenerPort attribute of the ILateralCacheAttributes object - *

- * @param val - * The new tcpListenerPort value - */ - void setTcpListenerPort( int val ); - - /** - * Gets the tcpListenerPort attribute of the ILateralCacheAttributes object - *

- * @return The tcpListenerPort value - */ - int getTcpListenerPort(); - - /** - * Can setup UDP Discovery. This only works for TCp laterals right now. It - * allows TCP laterals to find each other by broadcasting to a multicast - * port. - *

- * @param udpDiscoveryEnabled - * The udpDiscoveryEnabled to set. - */ - void setUdpDiscoveryEnabled( boolean udpDiscoveryEnabled ); - - /** - * Whether or not TCP laterals can try to find each other by multicast - * communication. - *

- * @return Returns the udpDiscoveryEnabled. - */ - boolean isUdpDiscoveryEnabled(); - - /** - * The port to use if UDPDiscovery is enabled. - *

- * @return Returns the udpDiscoveryPort. - */ - int getUdpDiscoveryPort(); - - /** - * Sets the port to use if UDPDiscovery is enabled. - *

- * @param udpDiscoveryPort - * The udpDiscoveryPort to set. - */ - void setUdpDiscoveryPort( int udpDiscoveryPort ); - - /** - * The address to broadcast to if UDPDiscovery is enabled. - *

- * @return Returns the udpDiscoveryAddr. - */ - String getUdpDiscoveryAddr(); - - /** - * Sets the address to broadcast to if UDPDiscovery is enabled. - *

- * @param udpDiscoveryAddr - * The udpDiscoveryAddr to set. - */ - void setUdpDiscoveryAddr( String udpDiscoveryAddr ); - - /** - * Is the lateral allowed to try and get from other laterals. - *

- * This replaces the old putOnlyMode - *

- * @param allowGet - */ - void setAllowGet( boolean allowGet ); - - /** - * Is the lateral allowed to try and get from other laterals. - *

- * @return true if the lateral will try to get - */ - boolean isAllowGet(); - - /** - * Is the lateral allowed to put objects to other laterals. - *

- * @param allowPut - */ - void setAllowPut( boolean allowPut ); - - /** - * Is the lateral allowed to put objects to other laterals. - *

- * @return true if puts are allowed - */ - boolean isAllowPut(); - - /** - * Should the client send a remove command rather than a put when update is - * called. This is a client option, not a receiver option. This allows you - * to prevent the lateral from serializing objects. - *

- * @param issueRemoveOnPut - */ - void setIssueRemoveOnPut( boolean issueRemoveOnPut ); - - /** - * Should the client send a remove command rather than a put when update is - * called. This is a client option, not a receiver option. This allows you - * to prevent the lateral from serializing objects. - *

- * @return true if updates will result in a remove command being sent. - */ - boolean isIssueRemoveOnPut(); - - /** - * Should the receiver try to match hashcodes. If true, the receiver will - * see if the client supplied a hashcode. If it did, then it will try to get - * the item locally. If the item exists, then it will compare the hashcode. - * if they are the same, it will not remove. This isn't perfect since - * different objects can have the same hashcode, but it is unlikely of - * objects of the same type. - *

- * @return boolean - */ - boolean isFilterRemoveByHashCode(); - - /** - * Should the receiver try to match hashcodes. If true, the receiver will - * see if the client supplied a hashcode. If it did, then it will try to get - * the item locally. If the item exists, then it will compare the hashcode. - * if they are the same, it will not remove. This isn't perfect since - * different objects can have the same hashcode, but it is unlikely of - * objects of the same type. - *

- * @param filter - */ - void setFilterRemoveByHashCode( boolean filter ); - - /** - * @param socketTimeOut the socketTimeOut to set - */ - void setSocketTimeOut( int socketTimeOut ); - - /** - * @return the socketTimeOut - */ - int getSocketTimeOut(); - - /** - * @param openTimeOut the openTimeOut to set - */ - void setOpenTimeOut( int openTimeOut ); - - /** - * @return the openTimeOut - */ - int getOpenTimeOut(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/package.html b/src/org/apache/commons/jcs/auxiliary/package.html deleted file mode 100644 index d1d712f8497..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - Root package for auxiliary caches. - - diff --git a/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java b/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java deleted file mode 100644 index 0b3d656e3e8..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java +++ /dev/null @@ -1,715 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheEventLogging; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.IZombie; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.jcs.utils.serialization.SerializationConversionUtil; -import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** Abstract base for remote caches. I'm trying to break out and reuse common functionality. */ -public abstract class AbstractRemoteAuxiliaryCache - extends AbstractAuxiliaryCacheEventLogging - implements IRemoteCacheClient -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( AbstractRemoteAuxiliaryCache.class ); - - /** - * This does the work. In an RMI instances, it will be a remote reference. In an http remote - * cache it will be an http client. In zombie mode it is replaced with a balking facade. - */ - private ICacheServiceNonLocal remoteCacheService; - - /** The cacheName */ - protected final String cacheName; - - /** The listener. This can be null. */ - private IRemoteCacheListener remoteCacheListener; - - /** The configuration values. TODO, we'll need a base here. */ - private IRemoteCacheAttributes remoteCacheAttributes; - - /** A thread pool for gets if configured. */ - private ExecutorService pool = null; - - /** Should we get asynchronously using a pool. */ - private boolean usePoolForGet = false; - - /** - * Creates the base. - *

- * @param cattr - * @param remote - * @param listener - */ - public AbstractRemoteAuxiliaryCache( IRemoteCacheAttributes cattr, ICacheServiceNonLocal remote, - IRemoteCacheListener listener ) - { - this.setRemoteCacheAttributes( cattr ); - this.cacheName = cattr.getCacheName(); - this.setRemoteCacheService( remote ); - this.setRemoteCacheListener( listener ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Construct> cacheName=" + cattr.getCacheName() ); - log.debug( "irca = " + getRemoteCacheAttributes() ); - log.debug( "remote = " + remote ); - log.debug( "listener = " + listener ); - } - - // use a pool if it is greater than 0 - if ( log.isDebugEnabled() ) - { - log.debug( "GetTimeoutMillis() = " + getRemoteCacheAttributes().getGetTimeoutMillis() ); - } - - if ( getRemoteCacheAttributes().getGetTimeoutMillis() > 0 ) - { - pool = ThreadPoolManager.getInstance().getExecutorService( getRemoteCacheAttributes().getThreadPoolName() ); - if ( log.isDebugEnabled() ) - { - log.debug( "Thread Pool = " + pool ); - } - usePoolForGet = true; - } - } - - /** - * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie. - *

- * @throws IOException - */ - @Override - protected void processDispose() - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "Disposing of remote cache." ); - } - try - { - if ( getRemoteCacheListener() != null ) - { - getRemoteCacheListener().dispose(); - } - } - catch ( IOException ex ) - { - log.error( "Couldn't dispose", ex ); - handleException( ex, "Failed to dispose [" + cacheName + "]", ICacheEventLogger.DISPOSE_EVENT ); - } - } - - /** - * Synchronously get from the remote cache; if failed, replace the remote handle with a zombie. - *

- * Use threadpool to timeout if a value is set for GetTimeoutMillis - *

- * If we are a cluster client, we need to leave the Element in its serialized form. Cluster - * clients cannot deserialize objects. Cluster clients get ICacheElementSerialized objects from - * other remote servers. - *

- * @param key - * @return ICacheElement, a wrapper around the key, value, and attributes - * @throws IOException - */ - @Override - protected ICacheElement processGet( K key ) - throws IOException - { - ICacheElement retVal = null; - try - { - if ( usePoolForGet ) - { - retVal = getUsingPool( key ); - } - else - { - retVal = getRemoteCacheService().get( cacheName, key, getListenerId() ); - } - - // Eventually the instance of will not be necessary. - if ( retVal instanceof ICacheElementSerialized ) - { - // Never try to deserialize if you are a cluster client. Cluster - // clients are merely intra-remote cache communicators. Remote caches are assumed - // to have no ability to deserialize the objects. - if ( this.getRemoteCacheAttributes().getRemoteType() != RemoteType.CLUSTER ) - { - retVal = SerializationConversionUtil.getDeSerializedCacheElement( (ICacheElementSerialized) retVal, - super.getElementSerializer() ); - } - } - } - catch ( Exception ex ) - { - handleException( ex, "Failed to get [" + key + "] from [" + cacheName + "]", ICacheEventLogger.GET_EVENT ); - } - return retVal; - } - - /** - * This allows gets to timeout in case of remote server machine shutdown. - *

- * @param key - * @return ICacheElement - * @throws IOException - */ - public ICacheElement getUsingPool( final K key ) - throws IOException - { - int timeout = getRemoteCacheAttributes().getGetTimeoutMillis(); - - try - { - Callable> command = new Callable>() - { - @Override - public ICacheElement call() - throws IOException - { - return getRemoteCacheService().get( cacheName, key, getListenerId() ); - } - }; - - // execute using the pool - Future> future = pool.submit(command); - - // used timed get in order to timeout - ICacheElement ice = future.get(timeout, TimeUnit.MILLISECONDS); - - if ( log.isDebugEnabled() ) - { - if ( ice == null ) - { - log.debug( "nothing found in remote cache" ); - } - else - { - log.debug( "found item in remote cache" ); - } - } - return ice; - } - catch ( TimeoutException te ) - { - log.warn( "TimeoutException, Get Request timed out after " + timeout ); - throw new IOException( "Get Request timed out after " + timeout ); - } - catch ( InterruptedException ex ) - { - log.warn( "InterruptedException, Get Request timed out after " + timeout ); - throw new IOException( "Get Request timed out after " + timeout ); - } - catch (ExecutionException ex) - { - // assume that this is an IOException thrown by the callable. - log.error( "ExecutionException, Assuming an IO exception thrown in the background.", ex ); - throw new IOException( "Get Request timed out after " + timeout ); - } - } - - /** - * Calls get matching on the server. Each entry in the result is unwrapped. - *

- * @param pattern - * @return Map - * @throws IOException - */ - @Override - public Map> processGetMatching( String pattern ) - throws IOException - { - Map> results = new HashMap>(); - try - { - Map> rawResults = getRemoteCacheService().getMatching( cacheName, pattern, getListenerId() ); - - // Eventually the instance of will not be necessary. - if ( rawResults != null ) - { - for (Map.Entry> entry : rawResults.entrySet()) - { - ICacheElement unwrappedResult = null; - if ( entry.getValue() instanceof ICacheElementSerialized ) - { - // Never try to deserialize if you are a cluster client. Cluster - // clients are merely intra-remote cache communicators. Remote caches are assumed - // to have no ability to deserialize the objects. - if ( this.getRemoteCacheAttributes().getRemoteType() != RemoteType.CLUSTER ) - { - unwrappedResult = SerializationConversionUtil - .getDeSerializedCacheElement( (ICacheElementSerialized) entry.getValue(), - super.getElementSerializer() ); - } - } - else - { - unwrappedResult = entry.getValue(); - } - results.put( entry.getKey(), unwrappedResult ); - } - } - } - catch ( Exception ex ) - { - handleException( ex, "Failed to getMatching [" + pattern + "] from [" + cacheName + "]", - ICacheEventLogger.GET_EVENT ); - } - return results; - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - protected Map> processGetMultiple( Set keys ) - throws IOException - { - Map> elements = new HashMap>(); - if ( keys != null && !keys.isEmpty() ) - { - for (K key : keys) - { - ICacheElement element = get( key ); - - if ( element != null ) - { - elements.put( key, element ); - } - } - } - return elements; - } - - /** - * Synchronously remove from the remote cache; if failed, replace the remote handle with a - * zombie. - *

- * @param key - * @return boolean, whether or not the item was removed - * @throws IOException - */ - @Override - protected boolean processRemove( K key ) - throws IOException - { - if ( !this.getRemoteCacheAttributes().getGetOnly() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "remove> key=" + key ); - } - try - { - getRemoteCacheService().remove( cacheName, key, getListenerId() ); - } - catch ( Exception ex ) - { - handleException( ex, "Failed to remove " + key + " from " + cacheName, ICacheEventLogger.REMOVE_EVENT ); - } - return true; - } - return false; - } - - /** - * Synchronously removeAll from the remote cache; if failed, replace the remote handle with a - * zombie. - *

- * @throws IOException - */ - @Override - protected void processRemoveAll() - throws IOException - { - if ( !this.getRemoteCacheAttributes().getGetOnly() ) - { - try - { - getRemoteCacheService().removeAll( cacheName, getListenerId() ); - } - catch ( Exception ex ) - { - handleException( ex, "Failed to remove all from " + cacheName, ICacheEventLogger.REMOVEALL_EVENT ); - } - } - } - - /** - * Serializes the object and then calls update on the remote server with the byte array. The - * byte array is wrapped in a ICacheElementSerialized. This allows the remote server to operate - * without any knowledge of caches classes. - *

- * @param ce - * @throws IOException - */ - @Override - protected void processUpdate( ICacheElement ce ) - throws IOException - { - if ( !getRemoteCacheAttributes().getGetOnly() ) - { - ICacheElementSerialized serialized = null; - try - { - if ( log.isDebugEnabled() ) - { - log.debug( "sending item to remote server" ); - } - - // convert so we don't have to know about the object on the - // other end. - serialized = SerializationConversionUtil.getSerializedCacheElement( ce, super.getElementSerializer() ); - - remoteCacheService.update( serialized, getListenerId() ); - } - catch ( NullPointerException npe ) - { - log.error( "npe for ce = " + ce + "ce.attr = " + ce.getElementAttributes(), npe ); - } - catch ( Exception ex ) - { - // event queue will wait and retry - handleException( ex, "Failed to put [" + ce.getKey() + "] to " + ce.getCacheName(), - ICacheEventLogger.UPDATE_EVENT ); - } - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "get only mode, not sending to remote server" ); - } - } - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet() - throws IOException - { - return getRemoteCacheService().getKeySet(cacheName); - } - - /** - * Allows other member of this package to access the listener. This is mainly needed for - * deregistering a listener. - *

- * @return IRemoteCacheListener, the listener for this remote server - */ - @Override - public IRemoteCacheListener getListener() - { - return getRemoteCacheListener(); - } - - /** - * let the remote cache set a listener_id. Since there is only one listener for all the regions - * and every region gets registered? the id shouldn't be set if it isn't zero. If it is we - * assume that it is a reconnect. - *

- * @param id The new listenerId value - */ - public void setListenerId( long id ) - { - if ( getRemoteCacheListener() != null ) - { - try - { - getRemoteCacheListener().setListenerId( id ); - - if ( log.isDebugEnabled() ) - { - log.debug( "set listenerId = " + id ); - } - } - catch ( Exception e ) - { - log.error( "Problem setting listenerId", e ); - } - } - } - - /** - * Gets the listenerId attribute of the RemoteCacheListener object - *

- * @return The listenerId value - */ - @Override - public long getListenerId() - { - if ( getRemoteCacheListener() != null ) - { - try - { - if ( log.isDebugEnabled() ) - { - log.debug( "get listenerId = " + getRemoteCacheListener().getListenerId() ); - } - return getRemoteCacheListener().getListenerId(); - } - catch ( Exception e ) - { - log.error( "Problem getting listenerId", e ); - } - } - return -1; - } - - /** - * Returns the current cache size. - * @return The size value - */ - @Override - public int getSize() - { - return 0; - } - - /** - * Custom exception handling some children. This should be used to initiate failover. - *

- * @param ex - * @param msg - * @param eventName - * @throws IOException - */ - protected abstract void handleException( Exception ex, String msg, String eventName ) - throws IOException; - - /** - * Gets the stats attribute of the RemoteCache object. - *

- * @return The stats value - */ - @Override - public String getStats() - { - return getStatistics().toString(); - } - - /** - * @return IStats object - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "AbstractRemoteAuxiliaryCache" ); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "Remote Type", this.getRemoteCacheAttributes().getRemoteTypeName() ) ); - -// if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER ) -// { -// // something cluster specific -// } - - elems.add(new StatElement( "UsePoolForGet", Boolean.valueOf(usePoolForGet) ) ); - - if ( pool != null ) - { - elems.add(new StatElement( "Pool", pool ) ); - } - - if ( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) - { - elems.add(new StatElement( "Zombie Queue Size", - Integer.valueOf(( (ZombieCacheServiceNonLocal) getRemoteCacheService() ).getQueueSize()) ) ); - } - - stats.setStatElements( elems ); - - return stats; - } - - /** - * Returns the cache status. An error status indicates the remote connection is not available. - *

- * @return The status value - */ - @Override - public CacheStatus getStatus() - { - return getRemoteCacheService() instanceof IZombie ? CacheStatus.ERROR : CacheStatus.ALIVE; - } - - /** - * Replaces the current remote cache service handle with the given handle. If the current remote - * is a Zombie, then it propagates any events that are queued to the restored service. - *

- * @param restoredRemote ICacheServiceNonLocal -- the remote server or proxy to the remote server - */ - @Override - public void fixCache( ICacheServiceNonLocal restoredRemote ) - { - @SuppressWarnings("unchecked") // Don't know how to do this properly - ICacheServiceNonLocal remote = (ICacheServiceNonLocal)restoredRemote; - ICacheServiceNonLocal prevRemote = getRemoteCacheService(); - if ( prevRemote instanceof ZombieCacheServiceNonLocal ) - { - ZombieCacheServiceNonLocal zombie = (ZombieCacheServiceNonLocal) prevRemote; - setRemoteCacheService( remote ); - try - { - zombie.propagateEvents( remote ); - } - catch ( Exception e ) - { - try - { - handleException( e, "Problem propagating events from Zombie Queue to new Remote Service.", - "fixCache" ); - } - catch ( IOException e1 ) - { - // swallow, since this is just expected kick back. Handle always throws - } - } - } - else - { - setRemoteCacheService( remote ); - } - } - - - /** - * Gets the cacheType attribute of the RemoteCache object - * @return The cacheType value - */ - @Override - public CacheType getCacheType() - { - return CacheType.REMOTE_CACHE; - } - - /** - * Gets the cacheName attribute of the RemoteCache object. - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return cacheName; - } - - /** - * @param remote the remote to set - */ - protected void setRemoteCacheService( ICacheServiceNonLocal remote ) - { - this.remoteCacheService = remote; - } - - /** - * @return the remote - */ - protected ICacheServiceNonLocal getRemoteCacheService() - { - return remoteCacheService; - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return getRemoteCacheAttributes(); - } - - /** - * @param remoteCacheAttributes the remoteCacheAttributes to set - */ - protected void setRemoteCacheAttributes( IRemoteCacheAttributes remoteCacheAttributes ) - { - this.remoteCacheAttributes = remoteCacheAttributes; - } - - /** - * @return the remoteCacheAttributes - */ - protected IRemoteCacheAttributes getRemoteCacheAttributes() - { - return remoteCacheAttributes; - } - - /** - * @param remoteCacheListener the remoteCacheListener to set - */ - protected void setRemoteCacheListener( IRemoteCacheListener remoteCacheListener ) - { - this.remoteCacheListener = remoteCacheListener; - } - - /** - * @return the remoteCacheListener - */ - protected IRemoteCacheListener getRemoteCacheListener() - { - return remoteCacheListener; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheListener.java b/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheListener.java deleted file mode 100644 index 090011d09e7..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheListener.java +++ /dev/null @@ -1,323 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.net.UnknownHostException; - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.control.CompositeCacheManager; -import org.apache.commons.jcs.utils.net.HostNameUtil; -import org.apache.commons.jcs.utils.serialization.SerializationConversionUtil; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** Shared listener base. */ -public abstract class AbstractRemoteCacheListener - implements IRemoteCacheListener -{ - /** The logger */ - private static final Log log = LogFactory.getLog( AbstractRemoteCacheListener.class ); - - /** The cached name of the local host. The remote server gets this for logging purposes. */ - private static String localHostName = null; - - /** - * The cache manager used to put items in different regions. This is set lazily and should not - * be sent to the remote server. - */ - private ICompositeCacheManager cacheMgr; - - /** The remote cache configuration object. */ - private final IRemoteCacheAttributes irca; - - /** This is set by the remote cache server. */ - private long listenerId = 0; - - /** Custom serializer. */ - private IElementSerializer elementSerializer; - - /** - * Only need one since it does work for all regions, just reference by multiple region names. - *

- * The constructor exports this object, making it available to receive incoming calls. The - * callback port is anonymous unless a local port value was specified in the configuration. - *

- * @param irca cache configuration - * @param cacheMgr the cache hub - * @param elementSerializer a custom serializer - */ - public AbstractRemoteCacheListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer ) - { - this.irca = irca; - this.cacheMgr = cacheMgr; - this.elementSerializer = elementSerializer; - } - - /** - * Let the remote cache set a listener_id. Since there is only one listener for all the regions - * and every region gets registered? the id shouldn't be set if it isn't zero. If it is we - * assume that it is a reconnect. - *

- * @param id The new listenerId value - * @throws IOException - */ - @Override - public void setListenerId( long id ) - throws IOException - { - listenerId = id; - if ( log.isInfoEnabled() ) - { - log.info( "set listenerId = [" + id + "]" ); - } - } - - /** - * Gets the listenerId attribute of the RemoteCacheListener object. This is stored in the - * object. The RemoteCache object contains a reference to the listener and get the id this way. - *

- * @return The listenerId value - * @throws IOException - */ - @Override - public long getListenerId() - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "get listenerId = [" + listenerId + "]" ); - } - return listenerId; - - } - - /** - * Gets the remoteType attribute of the RemoteCacheListener object - *

- * @return The remoteType value - * @throws IOException - */ - @Override - public RemoteType getRemoteType() - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "getRemoteType = [" + irca.getRemoteType() + "]" ); - } - return irca.getRemoteType(); - } - - /** - * If this is configured to remove on put, then remove the element since it has been updated - * elsewhere. cd should be incomplete for faster transmission. We don't want to pass data only - * invalidation. The next time it is used the local cache will get the new version from the - * remote store. - *

- * If remove on put is not configured, then update the item. - * @param cb - * @throws IOException - */ - @Override - public void handlePut( ICacheElement cb ) - throws IOException - { - if ( irca.getRemoveUponRemotePut() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "PUTTING ELEMENT FROM REMOTE, ( invalidating ) " ); - } - handleRemove( cb.getCacheName(), cb.getKey() ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "PUTTING ELEMENT FROM REMOTE, ( updating ) " ); - log.debug( "cb = " + cb ); - } - - // Eventually the instance of will not be necessary. - if ( cb instanceof ICacheElementSerialized ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Object needs to be deserialized." ); - } - try - { - cb = SerializationConversionUtil.getDeSerializedCacheElement( - (ICacheElementSerialized) cb, this.elementSerializer ); - if ( log.isDebugEnabled() ) - { - log.debug( "Deserialized result = " + cb ); - } - } - catch ( IOException e ) - { - throw e; - } - catch ( ClassNotFoundException e ) - { - log.error( "Received a serialized version of a class that we don't know about.", e ); - } - } - - getCacheManager().getCache( cb.getCacheName() ).localUpdate( cb ); - } - } - - /** - * Calls localRemove on the CompositeCache. - *

- * @param cacheName - * @param key - * @throws IOException - */ - @Override - public void handleRemove( String cacheName, K key ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "handleRemove> cacheName=" + cacheName + ", key=" + key ); - } - - getCacheManager().getCache( cacheName ).localRemove( key ); - } - - /** - * Calls localRemoveAll on the CompositeCache. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void handleRemoveAll( String cacheName ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "handleRemoveAll> cacheName=" + cacheName ); - } - - getCacheManager().getCache( cacheName ).localRemoveAll(); - } - - /** - * @param cacheName - * @throws IOException - */ - @Override - public void handleDispose( String cacheName ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "handleDispose> cacheName=" + cacheName ); - } - // TODO consider what to do here, we really don't want to - // dispose, we just want to disconnect. - // just allow the cache to go into error recovery mode. - // getCacheManager().freeCache( cacheName, true ); - } - - /** - * Gets the cacheManager attribute of the RemoteCacheListener object. This is one of the few - * places that force the cache to be a singleton. - */ - protected ICompositeCacheManager getCacheManager() - { - if ( cacheMgr == null ) - { - try - { - cacheMgr = CompositeCacheManager.getInstance(); - - if ( log.isDebugEnabled() ) - { - log.debug( "had to get cacheMgr" ); - log.debug( "cacheMgr = " + cacheMgr ); - } - } - catch (CacheException e) - { - log.error( "Could not get cacheMgr", e ); - } - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "already got cacheMgr = " + cacheMgr ); - } - } - - return cacheMgr; - } - - /** - * This is for debugging. It allows the remote server to log the address of clients. - *

- * @return String - * @throws IOException - */ - @Override - public synchronized String getLocalHostAddress() - throws IOException - { - if ( localHostName == null ) - { - try - { - localHostName = HostNameUtil.getLocalHostAddress(); - } - catch ( UnknownHostException uhe ) - { - localHostName = "unknown"; - } - } - return localHostName; - } - - /** - * For easier debugging. - *

- * @return Basic info on this listener. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n AbstractRemoteCacheListener: " ); - buf.append( "\n RemoteHost = " + irca.getRemoteLocation().toString() ); - buf.append( "\n ListenerId = " + listenerId ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java b/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java deleted file mode 100644 index da541d54710..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java +++ /dev/null @@ -1,439 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** An abstract base for the No Wait Facade. Different implementations will failover differently. */ -public abstract class AbstractRemoteCacheNoWaitFacade - extends AbstractAuxiliaryCache -{ - /** log instance */ - private static final Log log = LogFactory.getLog( AbstractRemoteCacheNoWaitFacade.class ); - - /** The connection to a remote server, or a zombie. */ - protected List> noWaits; - - /** holds failover and cluster information */ - private IRemoteCacheAttributes remoteCacheAttributes; - - /** - * Constructs with the given remote cache, and fires events to any listeners. - *

- * @param noWaits - * @param rca - * @param cacheEventLogger - * @param elementSerializer - */ - public AbstractRemoteCacheNoWaitFacade( List> noWaits, IRemoteCacheAttributes rca, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "CONSTRUCTING NO WAIT FACADE" ); - } - this.remoteCacheAttributes = rca; - setCacheEventLogger( cacheEventLogger ); - setElementSerializer( elementSerializer ); - this.noWaits = new ArrayList>(noWaits); - for (RemoteCacheNoWait nw : this.noWaits) - { - // FIXME: This cast is very brave. Remove this. - ((RemoteCache)nw.getRemoteCache()).setFacade(this); - } - } - - /** - * Put an element in the cache. - *

- * @param ce - * @throws IOException - */ - @Override - public void update( ICacheElement ce ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "updating through cache facade, noWaits.length = " + noWaits.size() ); - } - - for (RemoteCacheNoWait nw : noWaits) - { - try - { - nw.update( ce ); - // an initial move into a zombie will lock this to primary - // recovery. will not discover other servers until primary - // reconnect - // and subsequent error - } - catch ( IOException ex ) - { - String message = "Problem updating no wait. Will initiate failover if the noWait is in error."; - log.error( message, ex ); - - if ( getCacheEventLogger() != null ) - { - getCacheEventLogger().logError( "RemoteCacheNoWaitFacade", - ICacheEventLogger.UPDATE_EVENT, - message + ":" + ex.getMessage() + " REGION: " + ce.getCacheName() - + " ELEMENT: " + ce ); - } - - // can handle failover here? Is it safe to try the others? - // check to see it the noWait is now a zombie - // if it is a zombie, then move to the next in the failover list - // will need to keep them in order or a count - failover( nw ); - // should start a failover thread - // should probably only failover if there is only one in the noWait - // list - // Should start a background thread to restore the original primary if we are in failover state. - } - } - } - - /** - * Synchronously reads from the remote cache. - *

- * @param key - * @return Either an ICacheElement<K, V> or null if it is not found. - */ - @Override - public ICacheElement get( K key ) - { - for (RemoteCacheNoWait nw : noWaits) - { - try - { - ICacheElement obj = nw.get( key ); - if ( obj != null ) - { - return obj; - } - } - catch ( IOException ex ) - { - log.debug( "Failed to get." ); - return null; - } - } - return null; - } - - /** - * Synchronously read from the remote cache. - *

- * @param pattern - * @return map - * @throws IOException - */ - @Override - public Map> getMatching( String pattern ) - throws IOException - { - for (RemoteCacheNoWait nw : noWaits) - { - try - { - return nw.getMatching( pattern ); - } - catch ( IOException ex ) - { - log.debug( "Failed to getMatching." ); - } - } - return Collections.emptyMap(); - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - */ - @Override - public Map> getMultiple( Set keys ) - { - if ( keys != null && !keys.isEmpty() ) - { - for (RemoteCacheNoWait nw : noWaits) - { - try - { - return nw.getMultiple( keys ); - } - catch ( IOException ex ) - { - log.debug( "Failed to get." ); - } - } - } - - return Collections.emptyMap(); - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - HashSet allKeys = new HashSet(); - for (RemoteCacheNoWait nw : noWaits) - { - if ( nw != null ) - { - Set keys = nw.getKeySet(); - if(keys != null) - { - allKeys.addAll( keys ); - } - } - } - return allKeys; - } - - /** - * Adds a remove request to the remote cache. - *

- * @param key - * @return whether or not it was removed, right now it return false. - */ - @Override - public boolean remove( K key ) - { - try - { - for (RemoteCacheNoWait nw : noWaits) - { - nw.remove( key ); - } - } - catch ( IOException ex ) - { - log.error( ex ); - } - return false; - } - - /** - * Adds a removeAll request to the remote cache. - */ - @Override - public void removeAll() - { - try - { - for (RemoteCacheNoWait nw : noWaits) - { - nw.removeAll(); - } - } - catch ( IOException ex ) - { - log.error( ex ); - } - } - - /** Adds a dispose request to the remote cache. */ - @Override - public void dispose() - { - for (RemoteCacheNoWait nw : noWaits) - { - nw.dispose(); - } - } - - /** - * No remote invocation. - *

- * @return The size value - */ - @Override - public int getSize() - { - return 0; - // cache.getSize(); - } - - /** - * Gets the cacheType attribute of the RemoteCacheNoWaitFacade object. - *

- * @return The cacheType value - */ - @Override - public CacheType getCacheType() - { - return CacheType.REMOTE_CACHE; - } - - /** - * Gets the cacheName attribute of the RemoteCacheNoWaitFacade object. - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return remoteCacheAttributes.getCacheName(); - } - - /** - * Gets the status attribute of the RemoteCacheNoWaitFacade object - *

- * Return ALIVE if any are alive. - *

- * @return The status value - */ - @Override - public CacheStatus getStatus() - { - for (RemoteCacheNoWait nw : noWaits) - { - if ( nw.getStatus() == CacheStatus.ALIVE ) - { - return CacheStatus.ALIVE; - } - } - - return CacheStatus.DISPOSED; - } - - /** - * String form of some of the configuration information for the remote cache. - *

- * @return Some info for logging. - */ - @Override - public String toString() - { - return "RemoteCacheNoWaitFacade: " + remoteCacheAttributes.getCacheName() + ", rca = " + remoteCacheAttributes; - } - - /** - * Begin the failover process if this is a local cache. Clustered remote caches do not failover. - *

- * @param rcnw The no wait in error. - */ - protected abstract void failover( RemoteCacheNoWait rcnw ); - - /** - * Get the primary server from the list of failovers - * - * @return a no wait - */ - public RemoteCacheNoWait getPrimaryServer() - { - return noWaits.get(0); - } - - /** - * restore the primary server in the list of failovers - * - */ - public void restorePrimaryServer(RemoteCacheNoWait rcnw) - { - noWaits.clear(); - noWaits.add(rcnw); - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public IRemoteCacheAttributes getAuxiliaryCacheAttributes() - { - return this.remoteCacheAttributes; - } - - /** - * getStats - * @return String - */ - @Override - public String getStats() - { - return getStatistics().toString(); - } - - /** - * @return statistics about the cache region - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Remote Cache No Wait Facade" ); - - ArrayList> elems = new ArrayList>(); - - if ( noWaits != null ) - { - elems.add(new StatElement( "Number of No Waits", Integer.valueOf(noWaits.size()) ) ); - - for ( RemoteCacheNoWait rcnw : noWaits ) - { - // get the stats from the super too - IStats sStats = rcnw.getStatistics(); - elems.addAll(sStats.getStatElements()); - } - } - - stats.setStatElements( elems ); - - return stats; - } - - /** - * This typically returns end point info . - *

- * @return the name - */ - @Override - public String getEventLoggingExtraInfo() - { - return "Remote Cache No Wait Facade"; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/CommonRemoteCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/CommonRemoteCacheAttributes.java deleted file mode 100644 index 7ef69f99f0b..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/CommonRemoteCacheAttributes.java +++ /dev/null @@ -1,295 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.ICommonRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; - -/** - * Attributes common to remote cache client and server. - */ -public class CommonRemoteCacheAttributes - extends AbstractAuxiliaryCacheAttributes - implements ICommonRemoteCacheAttributes -{ - /** Don't change */ - private static final long serialVersionUID = -1555143736942374000L; - - /** The service name */ - private String remoteServiceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL; - - /** server host and port */ - private RemoteLocation location; - - /** Cluster chain */ - private String clusterServers = ""; - - /** THe type of remote cache, local or cluster */ - private RemoteType remoteType = RemoteType.LOCAL; - - /** Should we issue a local remove if we get a put from a remote server */ - private boolean removeUponRemotePut = true; - - /** Can we receive from or put to the remote. this probably shouldn't be used. Use receive. */ - private boolean getOnly = false; - - /** Should we put and get from the clusters. */ - private boolean localClusterConsistency = false; - - /** read and connect timeout */ - private int rmiSocketFactoryTimeoutMillis = DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS; - - /** Default constructor for the RemoteCacheAttributes object */ - public CommonRemoteCacheAttributes() - { - super(); - } - - /** - * Gets the remoteTypeName attribute of the RemoteCacheAttributes object. - *

- * @return The remoteTypeName value - */ - @Override - public String getRemoteTypeName() - { - return remoteType != null ? remoteType.toString() : RemoteType.LOCAL.toString(); - } - - /** - * Sets the remoteTypeName attribute of the RemoteCacheAttributes object. - *

- * @param s The new remoteTypeName value - */ - @Override - public void setRemoteTypeName( String s ) - { - RemoteType rt = RemoteType.valueOf(s); - if (rt != null) - { - this.remoteType = rt; - } - } - - /** - * Gets the remoteType attribute of the RemoteCacheAttributes object. - *

- * @return The remoteType value - */ - @Override - public RemoteType getRemoteType() - { - return remoteType; - } - - /** - * Sets the remoteType attribute of the RemoteCacheAttributes object. - *

- * @param p The new remoteType value - */ - @Override - public void setRemoteType( RemoteType p ) - { - this.remoteType = p; - } - - /** - * Gets the remoteServiceName attribute of the RemoteCacheAttributes object. - *

- * @return The remoteServiceName value - */ - @Override - public String getRemoteServiceName() - { - return this.remoteServiceName; - } - - /** - * Sets the remoteServiceName attribute of the RemoteCacheAttributes object. - *

- * @param s The new remoteServiceName value - */ - @Override - public void setRemoteServiceName( String s ) - { - this.remoteServiceName = s; - } - - /** - * Sets the location attribute of the RemoteCacheAttributes object. - *

- * @param location The new location value - */ - @Override - public void setRemoteLocation( RemoteLocation location ) - { - this.location = location; - } - - /** - * Sets the location attribute of the RemoteCacheAttributes object. - *

- * @param host The new remoteHost value - * @param port The new remotePort value - */ - @Override - public void setRemoteLocation( String host, int port ) - { - this.location = new RemoteLocation(host, port); - } - - /** - * Gets the location attribute of the RemoteCacheAttributes object. - *

- * @return The remote location value - */ - @Override - public RemoteLocation getRemoteLocation() - { - return this.location; - } - - /** - * Gets the clusterServers attribute of the RemoteCacheAttributes object. - *

- * @return The clusterServers value - */ - @Override - public String getClusterServers() - { - return this.clusterServers; - } - - /** - * Sets the clusterServers attribute of the RemoteCacheAttributes object. - *

- * @param s The new clusterServers value - */ - @Override - public void setClusterServers( String s ) - { - this.clusterServers = s; - } - - /** - * Gets the removeUponRemotePut attribute of the RemoteCacheAttributes object. - *

- * @return The removeUponRemotePut value - */ - @Override - public boolean getRemoveUponRemotePut() - { - return this.removeUponRemotePut; - } - - /** - * Sets the removeUponRemotePut attribute of the RemoteCacheAttributes object. - *

- * @param r The new removeUponRemotePut value - */ - @Override - public void setRemoveUponRemotePut( boolean r ) - { - this.removeUponRemotePut = r; - } - - /** - * Gets the getOnly attribute of the RemoteCacheAttributes object. - *

- * @return The getOnly value - */ - @Override - public boolean getGetOnly() - { - return this.getOnly; - } - - /** - * Sets the getOnly attribute of the RemoteCacheAttributes object - * @param r The new getOnly value - */ - @Override - public void setGetOnly( boolean r ) - { - this.getOnly = r; - } - - /** - * Should cluster updates be propagated to the locals. - *

- * @return The localClusterConsistency value - */ - @Override - public boolean isLocalClusterConsistency() - { - return localClusterConsistency; - } - - /** - * Should cluster updates be propagated to the locals. - *

- * @param r The new localClusterConsistency value - */ - @Override - public void setLocalClusterConsistency( boolean r ) - { - this.localClusterConsistency = r; - } - - /** - * @param rmiSocketFactoryTimeoutMillis The rmiSocketFactoryTimeoutMillis to set. - */ - @Override - public void setRmiSocketFactoryTimeoutMillis( int rmiSocketFactoryTimeoutMillis ) - { - this.rmiSocketFactoryTimeoutMillis = rmiSocketFactoryTimeoutMillis; - } - - /** - * @return Returns the rmiSocketFactoryTimeoutMillis. - */ - @Override - public int getRmiSocketFactoryTimeoutMillis() - { - return rmiSocketFactoryTimeoutMillis; - } - - /** - * @return String, all the important values that can be configured - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n RemoteCacheAttributes " ); - if (this.location != null) - { - buf.append( "\n remoteHost = [" + this.location.getHost() + "]" ); - buf.append( "\n remotePort = [" + this.location.getPort() + "]" ); - } - buf.append( "\n cacheName = [" + getCacheName() + "]" ); - buf.append( "\n remoteType = [" + remoteType + "]" ); - buf.append( "\n removeUponRemotePut = [" + this.removeUponRemotePut + "]" ); - buf.append( "\n getOnly = [" + getOnly + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCache.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCache.java deleted file mode 100644 index ec0a2696706..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCache.java +++ /dev/null @@ -1,215 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.ArrayList; - -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Client proxy for an RMI remote cache. - *

- * This handles gets, updates, and removes. It also initiates failover recovery when an error is - * encountered. - */ -public class RemoteCache - extends AbstractRemoteAuxiliaryCache -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( RemoteCache.class ); - - /** for error notifications */ - private RemoteCacheMonitor monitor; - - /** back link for failover initiation */ - private AbstractRemoteCacheNoWaitFacade facade; - - /** - * Constructor for the RemoteCache object. This object communicates with a remote cache server. - * One of these exists for each region. This also holds a reference to a listener. The same - * listener is used for all regions for one remote server. Holding a reference to the listener - * allows this object to know the listener id assigned by the remote cache. - *

- * @param cattr the cache configuration - * @param remote the remote cache server handle - * @param listener a listener - * @param monitor the cache monitor - */ - public RemoteCache( IRemoteCacheAttributes cattr, - ICacheServiceNonLocal remote, - IRemoteCacheListener listener, - RemoteCacheMonitor monitor ) - { - super( cattr, remote, listener ); - this.monitor = monitor; - - RemoteUtils.configureGlobalCustomSocketFactory( getRemoteCacheAttributes().getRmiSocketFactoryTimeoutMillis() ); - } - - /** - * @return IStats object - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Remote Cache" ); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "Remote Host:Port", getIPAddressForService() ) ); - elems.add(new StatElement( "Remote Type", this.getRemoteCacheAttributes().getRemoteTypeName() ) ); - -// if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER ) -// { -// // something cluster specific -// } - - // get the stats from the super too - IStats sStats = super.getStatistics(); - elems.addAll(sStats.getStatElements()); - - stats.setStatElements( elems ); - - return stats; - } - - /** - * Set facade - * - * @param facade the facade to set - */ - protected void setFacade(AbstractRemoteCacheNoWaitFacade facade) - { - this.facade = facade; - } - - /** - * Get facade - * - * @return the facade - */ - protected AbstractRemoteCacheNoWaitFacade getFacade() - { - return facade; - } - - /** - * Handles exception by disabling the remote cache service before re-throwing the exception in - * the form of an IOException. - *

- * @param ex - * @param msg - * @param eventName - * @throws IOException - */ - @Override - protected void handleException( Exception ex, String msg, String eventName ) - throws IOException - { - String message = "Disabling remote cache due to error: " + msg; - - logError( cacheName, "", message ); - log.error( message, ex ); - - // we should not switch if the existing is a zombie. - if ( getRemoteCacheService() == null || !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) ) - { - // TODO make configurable - setRemoteCacheService( new ZombieCacheServiceNonLocal( getRemoteCacheAttributes().getZombieQueueMaxSize() ) ); - } - // may want to flush if region specifies - // Notify the cache monitor about the error, and kick off the recovery - // process. - monitor.notifyError(); - - if ( log.isDebugEnabled() ) - { - log.debug( "Initiating failover, rcnwf = " + facade ); - } - - if ( facade != null && facade.getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Found facade, calling failover" ); - } - // may need to remove the noWait index here. It will be 0 if it is - // local since there is only 1 possible listener. - facade.failover( facade.getPrimaryServer() ); - } - - if ( ex instanceof IOException ) - { - throw (IOException) ex; - } - throw new IOException( ex ); - } - - /** - * Debugging info. - *

- * @return basic info about the RemoteCache - */ - @Override - public String toString() - { - return "RemoteCache: " + cacheName + " attributes = " + getRemoteCacheAttributes(); - } - - /** - * Gets the extra info for the event log. - *

- * @return disk location - */ - @Override - public String getEventLoggingExtraInfo() - { - return getIPAddressForService(); - } - - /** - * IP address for the service, if one is stored. - *

- * Protected for testing. - *

- * @return String - */ - protected String getIPAddressForService() - { - String ipAddress = "(null)"; - if (this.getRemoteCacheAttributes().getRemoteLocation() != null) - { - ipAddress = this.getRemoteCacheAttributes().getRemoteLocation().toString(); - } - return ipAddress; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheAttributes.java deleted file mode 100644 index 7d1fad44e4b..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheAttributes.java +++ /dev/null @@ -1,263 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.List; - -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; - -/** - * These objects are used to configure the remote cache client. - */ -public class RemoteCacheAttributes - extends CommonRemoteCacheAttributes - implements IRemoteCacheAttributes -{ - /** Don't change */ - private static final long serialVersionUID = -1555143736942374000L; - - /** - * Failover servers will be used by local caches one at a time. Listeners will be registered - * with all cluster servers. If we add a get from cluster attribute we will have the ability to - * chain clusters and have them get from each other. - */ - private String failoverServers = ""; - - /** callback */ - private int localPort = 0; - - /** what failover server we are connected to. */ - private int failoverIndex = 0; - - /** List of failover server addresses */ - private List failovers; - - /** default name is remote_cache_client */ - private String threadPoolName = "remote_cache_client"; - - /** must be greater than 0 for a pool to be used. */ - private int getTimeoutMillis = -1; - - /** - * Can we receive from the server. You might have a 0 local store and keep everything on the - * remote. If so, you don't want to be notified of updates. - */ - private boolean receive = DEFAULT_RECEIVE; - - /** If the primary fails, we will queue items before reconnect. This limits the number of items that can be queued. */ - private int zombieQueueMaxSize = DEFAULT_ZOMBIE_QUEUE_MAX_SIZE; - - /** Default constructor for the RemoteCacheAttributes object */ - public RemoteCacheAttributes() - { - super(); - } - - /** - * Gets the failoverIndex attribute of the RemoteCacheAttributes object. - *

- * @return The failoverIndex value - */ - @Override - public int getFailoverIndex() - { - return failoverIndex; - } - - /** - * Sets the failoverIndex attribute of the RemoteCacheAttributes object. - *

- * @param p The new failoverIndex value - */ - @Override - public void setFailoverIndex( int p ) - { - this.failoverIndex = p; - } - - /** - * Gets the failovers attribute of the RemoteCacheAttributes object. - *

- * @return The failovers value - */ - @Override - public List getFailovers() - { - return this.failovers; - } - - /** - * Sets the failovers attribute of the RemoteCacheAttributes object. - *

- * @param failovers The new failovers value - */ - @Override - public void setFailovers( List failovers ) - { - this.failovers = failovers; - } - - /** - * Gets the failoverServers attribute of the RemoteCacheAttributes object. - *

- * @return The failoverServers value - */ - @Override - public String getFailoverServers() - { - return this.failoverServers; - } - - /** - * Sets the failoverServers attribute of the RemoteCacheAttributes object. - *

- * @param s The new failoverServers value - */ - @Override - public void setFailoverServers( String s ) - { - this.failoverServers = s; - } - - /** - * Gets the localPort attribute of the RemoteCacheAttributes object. - *

- * @return The localPort value - */ - @Override - public int getLocalPort() - { - return this.localPort; - } - - /** - * Sets the localPort attribute of the RemoteCacheAttributes object - * @param p The new localPort value - */ - @Override - public void setLocalPort( int p ) - { - this.localPort = p; - } - - /** - * @return the name of the pool - */ - @Override - public String getThreadPoolName() - { - return threadPoolName; - } - - /** - * @param name - */ - @Override - public void setThreadPoolName( String name ) - { - threadPoolName = name; - } - - /** - * @return getTimeoutMillis - */ - @Override - public int getGetTimeoutMillis() - { - return getTimeoutMillis; - } - - /** - * @param millis - */ - @Override - public void setGetTimeoutMillis( int millis ) - { - getTimeoutMillis = millis; - } - - /** - * By default this option is true. If you set it to false, you will not receive updates or - * removes from the remote server. - *

- * @param receive - */ - @Override - public void setReceive( boolean receive ) - { - this.receive = receive; - } - - /** - * If RECEIVE is false then the remote cache will not register a listener with the remote - * server. This allows you to configure a remote server as a repository from which you can get - * and to which you put, but from which you do not receive any notifications. That is, you will - * not receive updates or removes. - *

- * If you set this option to false, you should set your local memory size to 0. - *

- * The remote cache manager uses this value to decide whether or not to register a listener. - * @return the receive value. - */ - @Override - public boolean isReceive() - { - return this.receive; - } - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @param zombieQueueMaxSize The zombieQueueMaxSize to set. - */ - @Override - public void setZombieQueueMaxSize( int zombieQueueMaxSize ) - { - this.zombieQueueMaxSize = zombieQueueMaxSize; - } - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @return Returns the zombieQueueMaxSize. - */ - @Override - public int getZombieQueueMaxSize() - { - return zombieQueueMaxSize; - } - - /** - * @return String, all the important values that can be configured - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(super.toString()); - buf.append( "\n receive = [" + isReceive() + "]" ); - buf.append( "\n getTimeoutMillis = [" + getGetTimeoutMillis() + "]" ); - buf.append( "\n threadPoolName = [" + getThreadPoolName() + "]" ); - buf.append( "\n localClusterConsistency = [" + isLocalClusterConsistency() + "]" ); - buf.append( "\n zombieQueueMaxSize = [" + getZombieQueueMaxSize() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFactory.java deleted file mode 100644 index 3c1ef01dc83..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFactory.java +++ /dev/null @@ -1,272 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.rmi.registry.Registry; -import java.util.ArrayList; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; - -/** - * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which - * is a wrapper around a no wait. The no wait object is either an active connection to a remote - * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the - * clients. - */ -public class RemoteCacheFactory - extends AbstractAuxiliaryCacheFactory -{ - /** Monitor thread */ - private RemoteCacheMonitor monitor; - - /** Contains mappings of RemoteLocation instance to RemoteCacheManager instance. */ - private ConcurrentMap managers; - - /** Lock for initialization of manager instances */ - private Lock managerLock; - - /** - * For LOCAL clients we get a handle to all the failovers, but we do not register a listener - * with them. We create the RemoteCacheManager, but we do not get a cache. - *

- * The failover runner will get a cache from the manager. When the primary is restored it will - * tell the manager for the failover to deregister the listener. - *

- * @param iaca - * @param cacheMgr - * @param cacheEventLogger - * @param elementSerializer - * @return AuxiliaryCache - */ - @Override - public AuxiliaryCache createCache( - AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - { - RemoteCacheAttributes rca = (RemoteCacheAttributes) iaca; - - ArrayList> noWaits = new ArrayList>(); - - switch (rca.getRemoteType()) - { - case LOCAL: - // a list to be turned into an array of failover server information - ArrayList failovers = new ArrayList(); - - // not necessary if a failover list is defined - // REGISTER PRIMARY LISTENER - // if it is a primary - boolean primaryDefined = false; - if ( rca.getRemoteLocation() != null ) - { - primaryDefined = true; - - failovers.add( rca.getRemoteLocation() ); - RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer ); - RemoteCacheNoWait ic = rcm.getCache( rca ); - noWaits.add( ic ); - } - - // GET HANDLE BUT DONT REGISTER A LISTENER FOR FAILOVERS - String failoverList = rca.getFailoverServers(); - if ( failoverList != null ) - { - StringTokenizer fit = new StringTokenizer( failoverList, "," ); - int fCnt = 0; - while ( fit.hasMoreTokens() ) - { - fCnt++; - - String server = fit.nextToken(); - RemoteLocation location = RemoteLocation.parseServerAndPort(server); - - if (location != null) - { - failovers.add( location ); - rca.setRemoteLocation(location); - RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer ); - - // add a listener if there are none, need to tell rca what - // number it is at - if ( ( !primaryDefined && fCnt == 1 ) || noWaits.size() <= 0 ) - { - RemoteCacheNoWait ic = rcm.getCache( rca ); - noWaits.add( ic ); - } - } - } - // end while - } - // end if failoverList != null - - rca.setFailovers( failovers ); - break; - - case CLUSTER: - // REGISTER LISTENERS FOR EACH SYSTEM CLUSTERED CACHEs - StringTokenizer it = new StringTokenizer( rca.getClusterServers(), "," ); - while ( it.hasMoreElements() ) - { - String server = (String) it.nextElement(); - RemoteLocation location = RemoteLocation.parseServerAndPort(server); - - if (location != null) - { - rca.setRemoteLocation(location); - RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer ); - rca.setRemoteType( RemoteType.CLUSTER ); - RemoteCacheNoWait ic = rcm.getCache( rca ); - noWaits.add( ic ); - } - } - break; - } - - RemoteCacheNoWaitFacade rcnwf = - new RemoteCacheNoWaitFacade(noWaits, rca, cacheEventLogger, elementSerializer, this ); - - return rcnwf; - } - - // end createCache - - /** - * Returns an instance of RemoteCacheManager for the given connection parameters. - *

- * Host and Port uniquely identify a manager instance. - *

- * @param cattr - * - * @return The instance value or null if no such manager exists - */ - public RemoteCacheManager getManager( IRemoteCacheAttributes cattr ) - { - if ( cattr.getRemoteLocation() == null ) - { - cattr.setRemoteLocation("", Registry.REGISTRY_PORT); - } - - RemoteLocation loc = cattr.getRemoteLocation(); - RemoteCacheManager ins = managers.get( loc ); - - return ins; - } - - /** - * Returns an instance of RemoteCacheManager for the given connection parameters. - *

- * Host and Port uniquely identify a manager instance. - *

- * If the connection cannot be established, zombie objects will be used for future recovery - * purposes. - *

- * @param cattr - * @param cacheMgr - * @param cacheEventLogger - * @param elementSerializer - * @return The instance value, never null - */ - public RemoteCacheManager getManager( IRemoteCacheAttributes cattr, ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, - IElementSerializer elementSerializer ) - { - RemoteCacheManager ins = getManager( cattr ); - - if ( ins == null ) - { - managerLock.lock(); - - try - { - ins = managers.get( cattr.getRemoteLocation() ); - - if (ins == null) - { - ins = new RemoteCacheManager( cattr, cacheMgr, monitor, cacheEventLogger, elementSerializer); - managers.put( cattr.getRemoteLocation(), ins ); - monitor.addManager(ins); - } - } - finally - { - managerLock.unlock(); - } - } - - return ins; - } - - /** - * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#initialize() - */ - @Override - public void initialize() - { - super.initialize(); - - managers = new ConcurrentHashMap(); - managerLock = new ReentrantLock(); - - monitor = new RemoteCacheMonitor(); - monitor.setDaemon(true); - } - - /** - * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#dispose() - */ - @Override - public void dispose() - { - for (RemoteCacheManager manager : managers.values()) - { - manager.release(); - } - - managers.clear(); - - if (monitor != null) - { - monitor.notifyShutdown(); - try - { - monitor.join(5000); - } - catch (InterruptedException e) - { - // swallow - } - monitor = null; - } - - super.dispose(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFailoverRunner.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFailoverRunner.java deleted file mode 100644 index 8a8c4a94419..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFailoverRunner.java +++ /dev/null @@ -1,417 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.List; -import java.util.ListIterator; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.ICache; - -/** - * The RemoteCacheFailoverRunner tries to establish a connection with a failover - * server, if any are defined. Once a failover connection is made, it will - * attempt to replace the failover with the primary remote server. - *

- * It works by switching out the RemoteCacheNoWait inside the Facade. - *

- * Client (i.e.) the CompositeCache has reference to a RemoteCacheNoWaitFacade. - * This facade is created by the RemoteCacheFactory. The factory maintains a set - * of managers, one for each remote server. Typically, there will only be one - * manager. - *

- * If you use multiple remote servers, you may want to set one or more as - * failovers. If a local cache cannot connect to the primary server, or looses - * its connection to the primary server, it will attempt to restore that - * Connection in the background. If failovers are defined, the Failover runner - * will try to connect to a failover until the primary is restored. - * - */ -public class RemoteCacheFailoverRunner extends AbstractAuxiliaryCacheMonitor -{ - /** The facade returned to the composite cache. */ - private final RemoteCacheNoWaitFacade facade; - - /** Factory instance */ - private final RemoteCacheFactory cacheFactory; - - /** - * Constructor for the RemoteCacheFailoverRunner object. This allows the - * FailoverRunner to modify the facade that the CompositeCache references. - * - * @param facade the facade the CompositeCache talks to. - * @param cacheFactory the cache factory instance - */ - public RemoteCacheFailoverRunner( RemoteCacheNoWaitFacade facade, RemoteCacheFactory cacheFactory ) - { - super("JCS-RemoteCacheFailoverRunner"); - this.facade = facade; - this.cacheFactory = cacheFactory; - setIdlePeriod(20000L); - } - - /** - * Clean up all resources before shutdown - */ - @Override - protected void dispose() - { - // empty - } - - /** - * do actual work - */ - @Override - protected void doWork() - { - // empty - } - - - /** - * Main processing method for the RemoteCacheFailoverRunner object. - *

- * If we do not have a connection with any failover server, this will try to - * connect one at a time. If no connection can be made, it goes to sleep for - * a while (20 seconds). - *

- * Once a connection with a failover is made, we will try to reconnect to - * the primary server. - *

- * The primary server is the first server defines in the FailoverServers - * list. - */ - @Override - public void run() - { - // start the main work of connecting to a failover and then restoring - // the primary. - connectAndRestore(); - - if ( log.isInfoEnabled() ) - { - int failoverIndex = facade.getAuxiliaryCacheAttributes().getFailoverIndex(); - log.info( "Exiting failover runner. Failover index = " + failoverIndex); - - if ( failoverIndex <= 0 ) - { - log.info( "Failover index is <= 0, meaning we are not connected to a failover server." ); - } - else if ( failoverIndex > 0 ) - { - log.info( "Failover index is > 0, meaning we are connected to a failover server." ); - } - // log if we are allright or not. - } - } - - /** - * This is the main loop. If there are failovers defined, then this will - * continue until the primary is re-connected. If no failovers are defined, - * this will exit automatically. - */ - private void connectAndRestore() - { - IRemoteCacheAttributes rca0 = facade.getAuxiliaryCacheAttributes(); - - do - { - log.info( "Remote cache FAILOVER RUNNING." ); - - // there is no active listener - if ( !allright.get() ) - { - // Monitor each RemoteCacheManager instance one after the other. - // Each RemoteCacheManager corresponds to one remote connection. - List failovers = rca0.getFailovers(); - // we should probably check to see if there are any failovers, - // even though the caller - // should have already. - - if ( failovers == null ) - { - log.warn( "Remote is misconfigured, failovers was null." ); - return; - } - else if ( failovers.size() == 1 ) - { - // if there is only the primary, return out of this - log.info( "No failovers defined, exiting failover runner." ); - return; - } - - int fidx = rca0.getFailoverIndex(); - log.debug( "fidx = " + fidx + " failovers.size = " + failovers.size() ); - - // shouldn't we see if the primary is backup? - // If we don't check the primary, if it gets connected in the - // background, - // we will disconnect it only to put it right back - ListIterator i = failovers.listIterator(fidx); // + 1; // +1 skips the primary - if ( log.isDebugEnabled() ) - { - log.debug( "starting at failover i = " + i.nextIndex() ); - } - - // try them one at a time until successful - for ( ; i.hasNext() && !allright.get();) - { - RemoteLocation server = i.next(); - if ( log.isDebugEnabled() ) - { - log.debug( "Trying server [" + server + "] at failover index i = " + i ); - } - - RemoteCacheAttributes rca = (RemoteCacheAttributes) rca0.clone(); - rca.setRemoteLocation(server); - RemoteCacheManager rcm = cacheFactory.getManager( rca ); - - if ( log.isDebugEnabled() ) - { - log.debug( "RemoteCacheAttributes for failover = " + rca.toString() ); - } - - if (rcm != null) - { - // add a listener if there are none, need to tell rca - // what number it is at - ICache ic = rcm.getCache( rca ); - if ( ic.getStatus() == CacheStatus.ALIVE ) - { - // may need to do this more gracefully - log.debug( "resetting no wait" ); - facade.restorePrimaryServer((RemoteCacheNoWait) ic); - rca0.setFailoverIndex( i.nextIndex() ); - - if ( log.isDebugEnabled() ) - { - log.debug( "setting ALLRIGHT to true" ); - if ( i.hasPrevious() ) - { - log.debug( "Moving to Primary Recovery Mode, failover index = " + i.nextIndex() ); - } - else - { - log.debug( "No need to connect to failover, the primary server is back up." ); - } - } - - allright.set(true); - - if ( log.isInfoEnabled() ) - { - log.info( "CONNECTED to host = [" + rca.getRemoteLocation() + "]" ); - } - } - } - } - } - // end if !allright - // get here if while index >0 and allright, meaning that we are - // connected to some backup server. - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "ALLRIGHT is true " ); - } - if ( log.isInfoEnabled() ) - { - log.info( "Failover runner is in primary recovery mode. Failover index = " - + rca0.getFailoverIndex() + "\n" + "Will now try to reconnect to primary server." ); - } - } - - boolean primaryRestoredSuccessfully = false; - // if we are not connected to the primary, try. - if ( rca0.getFailoverIndex() > 0 ) - { - primaryRestoredSuccessfully = restorePrimary(); - if ( log.isDebugEnabled() ) - { - log.debug( "Primary recovery success state = " + primaryRestoredSuccessfully ); - } - } - - if ( !primaryRestoredSuccessfully ) - { - // Time driven mode: sleep between each round of recovery - // attempt. - try - { - log.warn( "Failed to reconnect to primary server. Cache failover runner is going to sleep for " - + idlePeriod + " milliseconds." ); - Thread.sleep( idlePeriod ); - } - catch ( InterruptedException ex ) - { - // ignore; - } - } - - // try to bring the listener back to the primary - } - while ( rca0.getFailoverIndex() > 0 || !allright.get() ); - // continue if the primary is not restored or if things are not allright. - } - - /** - * Try to restore the primary server. - *

- * Once primary is restored the failover listener must be deregistered. - *

- * The primary server is the first server defines in the FailoverServers - * list. - * - * @return boolean value indicating whether the restoration was successful - */ - private boolean restorePrimary() - { - IRemoteCacheAttributes rca0 = facade.getAuxiliaryCacheAttributes(); - // try to move back to the primary - RemoteLocation server = rca0.getFailovers().get(0); - - if ( log.isInfoEnabled() ) - { - log.info( "Trying to restore connection to primary remote server [" + server + "]" ); - } - - RemoteCacheAttributes rca = (RemoteCacheAttributes) rca0.clone(); - rca.setRemoteLocation(server); - RemoteCacheManager rcm = cacheFactory.getManager( rca ); - - if (rcm != null) - { - // add a listener if there are none, need to tell rca what number it - // is at - ICache ic = rcm.getCache( rca ); - // by default the listener id should be 0, else it will be the - // listener - // Originally associated with the remote cache. either way is fine. - // We just don't want the listener id from a failover being used. - // If the remote server was rebooted this could be a problem if new - // locals were also added. - - if ( ic.getStatus() == CacheStatus.ALIVE ) - { - try - { - // we could have more than one listener registered right - // now. - // this will not result in a loop, only duplication - // stop duplicate listening. - if ( facade.getPrimaryServer() != null && facade.getPrimaryServer().getStatus() == CacheStatus.ALIVE ) - { - int fidx = rca0.getFailoverIndex(); - - if ( fidx > 0 ) - { - RemoteLocation serverOld = rca0.getFailovers().get(fidx); - - if ( log.isDebugEnabled() ) - { - log.debug( "Failover Index = " + fidx + " the server at that index is [" - + serverOld + "]" ); - } - - if ( serverOld != null ) - { - // create attributes that reflect the - // previous failed over configuration. - RemoteCacheAttributes rcaOld = (RemoteCacheAttributes) rca0.clone(); - rcaOld.setRemoteLocation(serverOld); - RemoteCacheManager rcmOld = cacheFactory.getManager( rcaOld ); - - if ( rcmOld != null ) - { - // manager can remove by name if - // necessary - rcmOld.removeRemoteCacheListener( rcaOld ); - } - if ( log.isInfoEnabled() ) - { - log.info( "Successfully deregistered from FAILOVER remote server = " - + serverOld ); - } - } - } - else if ( fidx == 0 ) - { - // this should never happen. If there are no - // failovers this shouldn't get called. - if ( log.isDebugEnabled() ) - { - log.debug( "No need to restore primary, it is already restored." ); - return true; - } - } - else if ( fidx < 0 ) - { - // this should never happen - log.warn( "Failover index is less than 0, this shouldn't happen" ); - } - } - } - catch ( IOException e ) - { - // TODO, should try again, or somehow stop the listener - log.error("Trouble trying to deregister old failover listener prior to restoring the primary = " - + server, e ); - } - - // Restore primary - // may need to do this more gracefully, letting the failover finish in the background - RemoteCacheNoWait failoverNoWait = facade.getPrimaryServer(); - - // swap in a new one - facade.restorePrimaryServer((RemoteCacheNoWait) ic); - rca0.setFailoverIndex( 0 ); - - if ( log.isInfoEnabled() ) - { - String message = "Successfully reconnected to PRIMARY remote server. Substituted primary for failoverNoWait [" - + failoverNoWait + "]"; - log.info( message ); - - if ( facade.getCacheEventLogger() != null ) - { - facade.getCacheEventLogger().logApplicationEvent( "RemoteCacheFailoverRunner", "RestoredPrimary", message ); - } - } - return true; - } - } - - // else all right - // if the failover index was at 0 here, we would be in a bad - // situation, unless there were just - // no failovers configured. - if ( log.isDebugEnabled() ) - { - log.debug( "Primary server status in error, not connected." ); - } - - return false; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListener.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListener.java deleted file mode 100644 index 2d5aa2f11a4..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListener.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.rmi.RemoteException; -import java.rmi.server.UnicastRemoteObject; - -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Registered with RemoteCache server. The server updates the local caches via this listener. Each - * server assigns a unique listener id for a listener. - *

- * One listener is used per remote cache server. The same listener is used for all the regions that - * talk to a particular server. - */ -public class RemoteCacheListener - extends AbstractRemoteCacheListener - implements IRemoteCacheConstants -{ - /** The logger */ - private static final Log log = LogFactory.getLog( RemoteCacheListener.class ); - - /** Has this client been shutdown. */ - private boolean disposed = false; - - /** - * Only need one since it does work for all regions, just reference by multiple region names. - *

- * The constructor exports this object, making it available to receive incoming calls. The - * callback port is anonymous unless a local port value was specified in the configuration. - *

- * @param irca cache configuration - * @param cacheMgr the cache hub - * @param elementSerializer a custom serializer - */ - public RemoteCacheListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer ) - { - super( irca, cacheMgr, elementSerializer ); - - // Export this remote object to make it available to receive incoming - // calls. - try - { - UnicastRemoteObject.exportObject( this, irca.getLocalPort() ); - } - catch ( RemoteException ex ) - { - log.error( "Problem exporting object.", ex ); - throw new IllegalStateException( ex.getMessage() ); - } - } - - /** - * Deregister itself. - *

- * @throws IOException - */ - @Override - public synchronized void dispose() - throws IOException - { - if ( !disposed ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Unexporting listener." ); - } - try - { - UnicastRemoteObject.unexportObject( this, true ); - } - catch ( RemoteException ex ) - { - log.error( "Problem unexporting the listener.", ex ); - throw new IllegalStateException( ex.getMessage() ); - } - disposed = true; - } - } - - /** - * For easier debugging. - *

- * @return Basic info on this listener. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n RemoteCacheListener: " ); - buf.append( super.toString() ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheManager.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheManager.java deleted file mode 100644 index f2165609f1e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheManager.java +++ /dev/null @@ -1,406 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.rmi.Naming; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.CacheWatchRepairable; -import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; -import org.apache.commons.jcs.engine.ZombieCacheWatch; -import org.apache.commons.jcs.engine.behavior.ICacheObserver; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * An instance of RemoteCacheManager corresponds to one remote connection of a specific host and - * port. All RemoteCacheManager instances are monitored by the singleton RemoteCacheMonitor - * monitoring daemon for error detection and recovery. - *

- * Getting an instance of the remote cache has the effect of getting a handle on the remote server. - * Listeners are not registered with the server until a cache is requested from the manager. - */ -public class RemoteCacheManager -{ - /** The logger */ - private static final Log log = LogFactory.getLog( RemoteCacheManager.class ); - - /** Contains instances of RemoteCacheNoWait managed by a RemoteCacheManager instance. */ - private final ConcurrentMap> caches = - new ConcurrentHashMap>(); - - /** Lock for initialization of caches */ - private ReentrantLock cacheLock = new ReentrantLock(); - - /** The event logger. */ - private final ICacheEventLogger cacheEventLogger; - - /** The serializer. */ - private final IElementSerializer elementSerializer; - - /** Handle to the remote cache service; or a zombie handle if failed to connect. */ - private ICacheServiceNonLocal remoteService; - - /** - * Wrapper of the remote cache watch service; or wrapper of a zombie service if failed to - * connect. - */ - private CacheWatchRepairable remoteWatch; - - /** The cache manager listeners will need to use to get a cache. */ - private final ICompositeCacheManager cacheMgr; - - /** For error notification */ - private final RemoteCacheMonitor monitor; - - /** The service found through lookup */ - private final String registry; - - /** can it be restored */ - private boolean canFix = true; - - /** - * Constructs an instance to with the given remote connection parameters. If the connection - * cannot be made, "zombie" services will be temporarily used until a successful re-connection - * is made by the monitoring daemon. - *

- * @param cattr cache attributes - * @param cacheMgr the cache hub - * @param monitor the cache monitor thread for error notifications - * @param cacheEventLogger - * @param elementSerializer - */ - protected RemoteCacheManager( IRemoteCacheAttributes cattr, ICompositeCacheManager cacheMgr, - RemoteCacheMonitor monitor, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer) - { - this.cacheMgr = cacheMgr; - this.monitor = monitor; - this.cacheEventLogger = cacheEventLogger; - this.elementSerializer = elementSerializer; - this.remoteWatch = new CacheWatchRepairable(); - - this.registry = RemoteUtils.getNamingURL(cattr.getRemoteLocation(), cattr.getRemoteServiceName()); - - try - { - lookupRemoteService(); - } - catch (IOException e) - { - log.error("Could not find server", e); - // Notify the cache monitor about the error, and kick off the - // recovery process. - monitor.notifyError(); - } - } - - /** - * Lookup remote service from registry - * @throws IOException if the remote service could not be found - * - */ - protected void lookupRemoteService() throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "Looking up server [" + registry + "]" ); - } - try - { - Object obj = Naming.lookup( registry ); - if ( log.isInfoEnabled() ) - { - log.info( "Server found: " + obj ); - } - - // Successful connection to the remote server. - this.remoteService = (ICacheServiceNonLocal) obj; - if ( log.isDebugEnabled() ) - { - log.debug( "Remote Service = " + remoteService ); - } - remoteWatch.setCacheWatch( (ICacheObserver) remoteService ); - } - catch ( Exception ex ) - { - // Failed to connect to the remote server. - // Configure this RemoteCacheManager instance to use the "zombie" - // services. - this.remoteService = new ZombieCacheServiceNonLocal(); - remoteWatch.setCacheWatch( new ZombieCacheWatch() ); - throw new IOException( "Problem finding server at [" + registry + "]", ex ); - } - } - - /** - * Adds the remote cache listener to the underlying cache-watch service. - *

- * @param cattr The feature to be added to the RemoteCacheListener attribute - * @param listener The feature to be added to the RemoteCacheListener attribute - * @throws IOException - */ - public void addRemoteCacheListener( IRemoteCacheAttributes cattr, IRemoteCacheListener listener ) - throws IOException - { - if ( cattr.isReceive() ) - { - if ( log.isInfoEnabled() ) - { - log.info( "The remote cache is configured to receive events from the remote server. " - + "We will register a listener. remoteWatch = " + remoteWatch + " | IRemoteCacheListener = " - + listener + " | cacheName " + cattr.getCacheName() ); - } - - remoteWatch.addCacheListener( cattr.getCacheName(), listener ); - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "The remote cache is configured to NOT receive events from the remote server. " - + "We will NOT register a listener." ); - } - } - } - - /** - * Removes a listener. When the primary recovers the failover must deregister itself for a - * region. The failover runner will call this method to de-register. We do not want to deregister - * all listeners to a remote server, in case a failover is a primary of another region. Having - * one regions failover act as another servers primary is not currently supported. - *

- * @param cattr - * @throws IOException - */ - public void removeRemoteCacheListener( IRemoteCacheAttributes cattr ) - throws IOException - { - RemoteCacheNoWait cache = caches.get( cattr.getCacheName() ); - if ( cache != null ) - { - removeListenerFromCache(cache); - } - else - { - if ( cattr.isReceive() ) - { - log.warn( "Trying to deregister Cache Listener that was never registered." ); - } - else if ( log.isDebugEnabled() ) - { - log.debug( "Since the remote cache is configured to not receive, " - + "there is no listener to deregister." ); - } - } - } - - // common helper method - private void removeListenerFromCache(RemoteCacheNoWait cache) throws IOException - { - IRemoteCacheClient rc = cache.getRemoteCache(); - if ( log.isDebugEnabled() ) - { - log.debug( "Found cache for [" + cache.getCacheName() + "], deregistering listener." ); - } - // could also store the listener for a server in the manager. - IRemoteCacheListener listener = rc.getListener(); - remoteWatch.removeCacheListener( cache.getCacheName(), listener ); - } - - /** - * Gets a RemoteCacheNoWait from the RemoteCacheManager. The RemoteCacheNoWait objects are - * identified by the cache name value of the RemoteCacheAttributes object. - *

- * If the client is configured to register a listener, this call results on a listener being - * created if one isn't already registered with the remote cache for this region. - *

- * @param cattr - * @return The cache value - */ - @SuppressWarnings("unchecked") // Need to cast because of common map for all caches - public RemoteCacheNoWait getCache( IRemoteCacheAttributes cattr ) - { - RemoteCacheNoWait remoteCacheNoWait = (RemoteCacheNoWait) caches.get( cattr.getCacheName() ); - - if ( remoteCacheNoWait == null ) - { - cacheLock.lock(); - - try - { - remoteCacheNoWait = (RemoteCacheNoWait) caches.get( cattr.getCacheName() ); - - if (remoteCacheNoWait == null) - { - remoteCacheNoWait = newRemoteCacheNoWait(cattr); - caches.put( cattr.getCacheName(), remoteCacheNoWait ); - } - } - finally - { - cacheLock.unlock(); - } - } - - // might want to do some listener sanity checking here. - - return remoteCacheNoWait; - } - - /** - * Create new RemoteCacheNoWait instance - * - * @param cattr the cache configuration - * @return the instance - */ - protected RemoteCacheNoWait newRemoteCacheNoWait(IRemoteCacheAttributes cattr) - { - RemoteCacheNoWait remoteCacheNoWait; - // create a listener first and pass it to the remotecache - // sender. - RemoteCacheListener listener = null; - try - { - listener = new RemoteCacheListener( cattr, cacheMgr, elementSerializer ); - addRemoteCacheListener( cattr, listener ); - } - catch ( IOException ioe ) - { - log.error( "Problem adding listener. Message: " + ioe.getMessage() - + " | RemoteCacheListener = " + listener, ioe ); - } - catch ( Exception e ) - { - log.error( "Problem adding listener. Message: " + e.getMessage() + " | RemoteCacheListener = " - + listener, e ); - } - - IRemoteCacheClient remoteCacheClient = - new RemoteCache( cattr, (ICacheServiceNonLocal) remoteService, listener, monitor ); - remoteCacheClient.setCacheEventLogger( cacheEventLogger ); - remoteCacheClient.setElementSerializer( elementSerializer ); - - remoteCacheNoWait = new RemoteCacheNoWait( remoteCacheClient ); - remoteCacheNoWait.setCacheEventLogger( cacheEventLogger ); - remoteCacheNoWait.setElementSerializer( elementSerializer ); - - return remoteCacheNoWait; - } - - /** Shutdown all. */ - public void release() - { - cacheLock.lock(); - - try - { - for (RemoteCacheNoWait c : caches.values()) - { - try - { - if ( log.isInfoEnabled() ) - { - log.info( "freeCache [" + c.getCacheName() + "]" ); - } - - removeListenerFromCache(c); - c.dispose(); - } - catch ( IOException ex ) - { - log.error( "Problem releasing " + c.getCacheName(), ex ); - } - } - - caches.clear(); - } - finally - { - cacheLock.unlock(); - } - } - - /** - * Fixes up all the caches managed by this cache manager. - */ - public void fixCaches() - { - if ( !canFix ) - { - return; - } - - if ( log.isInfoEnabled() ) - { - log.info( "Fixing caches. ICacheServiceNonLocal " + remoteService + " | IRemoteCacheObserver " + remoteWatch ); - } - - for (RemoteCacheNoWait c : caches.values()) - { - if (c.getStatus() == CacheStatus.ERROR) - { - c.fixCache( remoteService ); - } - } - - if ( log.isInfoEnabled() ) - { - String msg = "Remote connection to " + registry + " resumed."; - if ( cacheEventLogger != null ) - { - cacheEventLogger.logApplicationEvent( "RemoteCacheManager", "fix", msg ); - } - log.info( msg ); - } - } - - /** - * Returns true if the connection to the remote host can be - * successfully re-established. - *

- * @return true if we found a failover server - */ - public boolean canFixCaches() - { - try - { - lookupRemoteService(); - } - catch (IOException e) - { - log.error("Could not find server", e); - canFix = false; - } - - return canFix; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheMonitor.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheMonitor.java deleted file mode 100644 index 3894f4bf8af..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheMonitor.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor; - -/** - * Used to monitor and repair any failed connection for the remote cache service. By default the - * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an - * error. - * - * TODO consider moving this into an active monitoring mode. Upon the notification of a - * connection error, the monitor changes to operate in a time driven mode. That is, it attempts to - * recover the connections on a periodic basis. When all failed connections are restored, it changes - * back to the failure driven mode. - */ -public class RemoteCacheMonitor extends AbstractAuxiliaryCacheMonitor -{ - /** - * Map of managers to monitor - */ - private ConcurrentHashMap managers; - - /** Constructor for the RemoteCacheMonitor object */ - public RemoteCacheMonitor() - { - super("JCS-RemoteCacheMonitor"); - this.managers = new ConcurrentHashMap(); - setIdlePeriod(30000L); - } - - /** - * Add a manager to be monitored - * - * @param manager the remote cache manager - */ - public void addManager(RemoteCacheManager manager) - { - this.managers.put(manager, manager); - - // if not yet started, go ahead - if (this.getState() == Thread.State.NEW) - { - this.start(); - } - } - - /** - * Clean up all resources before shutdown - */ - @Override - public void dispose() - { - this.managers.clear(); - } - - // Avoid the use of any synchronization in the process of monitoring for - // performance reason. - // If exception is thrown owing to synchronization, - // just skip the monitoring until the next round. - /** Main processing method for the RemoteCacheMonitor object */ - @Override - public void doWork() - { - // Monitor each RemoteCacheManager instance one after the other. - // Each RemoteCacheManager corresponds to one remote connection. - for (RemoteCacheManager mgr : managers.values()) - { - // If we can't fix them, just skip and re-try in - // the next round. - if ( mgr.canFixCaches() ) - { - mgr.fixCaches(); - } - else - { - allright.set(false); - } - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWait.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWait.java deleted file mode 100644 index 122dbaab895..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWait.java +++ /dev/null @@ -1,537 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.rmi.UnmarshalException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient; -import org.apache.commons.jcs.engine.CacheAdaptor; -import org.apache.commons.jcs.engine.CacheEventQueueFactory; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * The RemoteCacheNoWait wraps the RemoteCacheClient. The client holds a handle on the - * RemoteCacheService. - *

- * Used to queue up update requests to the underlying cache. These requests will be processed in - * their order of arrival via the cache event queue processor. - *

- * Typically errors will be handled down stream. We only need to kill the queue if an error makes it - * to this level from the queue. That can only happen if the queue is damaged, since the events are - * Processed asynchronously. - *

- * There is no reason to create a queue on startup if the remote is not healthy. - *

- * If the remote cache encounters an error it will zombie--create a balking facade for the service. - * The Zombie will queue up items until the connection is restored. An alternative way to accomplish - * the same thing would be to stop, not destroy the queue at this level. That way items would be - * added to the queue and then when the connection is restored, we could start the worker threads - * again. This is a better long term solution, but it requires some significant changes to the - * complicated worker queues. - */ -public class RemoteCacheNoWait - extends AbstractAuxiliaryCache -{ - /** log instance */ - private static final Log log = LogFactory.getLog( RemoteCacheNoWait.class ); - - /** The remote cache client */ - private final IRemoteCacheClient remoteCacheClient; - - /** Event queue for queuing up calls like put and remove. */ - private ICacheEventQueue cacheEventQueue; - - /** how many times get has been called. */ - private int getCount = 0; - - /** how many times getMatching has been called. */ - private int getMatchingCount = 0; - - /** how many times getMultiple has been called. */ - private int getMultipleCount = 0; - - /** how many times remove has been called. */ - private int removeCount = 0; - - /** how many times put has been called. */ - private int putCount = 0; - - /** - * Constructs with the given remote cache, and fires up an event queue for asynchronous - * processing. - *

- * @param cache - */ - public RemoteCacheNoWait( IRemoteCacheClient cache ) - { - remoteCacheClient = cache; - this.cacheEventQueue = createCacheEventQueue(cache); - - if ( remoteCacheClient.getStatus() == CacheStatus.ERROR ) - { - cacheEventQueue.destroy(); - } - } - - /** - * Create a cache event queue from the parameters of the remote client - * @param client the remote client - */ - private ICacheEventQueue createCacheEventQueue( IRemoteCacheClient client ) - { - CacheEventQueueFactory factory = new CacheEventQueueFactory(); - ICacheEventQueue ceq = factory.createCacheEventQueue( - new CacheAdaptor( client ), - client.getListenerId(), - client.getCacheName(), - client.getAuxiliaryCacheAttributes().getEventQueuePoolName(), - client.getAuxiliaryCacheAttributes().getEventQueueType() ); - return ceq; - } - - /** - * Adds a put event to the queue. - *

- * @param element - * @throws IOException - */ - @Override - public void update( ICacheElement element ) - throws IOException - { - putCount++; - try - { - cacheEventQueue.addPutEvent( element ); - } - catch ( IOException e ) - { - log.error( "Problem adding putEvent to queue.", e ); - cacheEventQueue.destroy(); - throw e; - } - } - - /** - * Synchronously reads from the remote cache. - *

- * @param key - * @return element from the remote cache, or null if not present - * @throws IOException - */ - @Override - public ICacheElement get( K key ) - throws IOException - { - getCount++; - try - { - return remoteCacheClient.get( key ); - } - catch ( UnmarshalException ue ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Retrying the get owing to UnmarshalException." ); - } - - try - { - return remoteCacheClient.get( key ); - } - catch ( IOException ex ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Failed in retrying the get for the second time. " + ex.getMessage() ); - } - } - } - catch ( IOException ex ) - { - // We don't want to destroy the queue on a get failure. - // The RemoteCache will Zombie and queue. - // Since get does not use the queue, I don't want to kill the queue. - throw ex; - } - - return null; - } - - /** - * @param pattern - * @return Map - * @throws IOException - * - */ - @Override - public Map> getMatching( String pattern ) - throws IOException - { - getMatchingCount++; - try - { - return remoteCacheClient.getMatching( pattern ); - } - catch ( UnmarshalException ue ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Retrying the getMatching owing to UnmarshalException." ); - } - - try - { - return remoteCacheClient.getMatching( pattern ); - } - catch ( IOException ex ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Failed in retrying the getMatching for the second time. " + ex.getMessage() ); - } - } - } - catch ( IOException ex ) - { - // We don't want to destroy the queue on a get failure. - // The RemoteCache will Zombie and queue. - // Since get does not use the queue, I don't want to kill the queue. - throw ex; - } - - return Collections.emptyMap(); - } - - /** - * Gets multiple items from the cache based on the given set of keys. Sends the getMultiple - * request on to the server rather than looping through the requested keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( Set keys ) - throws IOException - { - getMultipleCount++; - try - { - return remoteCacheClient.getMultiple( keys ); - } - catch ( UnmarshalException ue ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Retrying the getMultiple owing to UnmarshalException..." ); - } - - try - { - return remoteCacheClient.getMultiple( keys ); - } - catch ( IOException ex ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Failed in retrying the getMultiple for the second time. " + ex.getMessage() ); - } - } - } - catch ( IOException ex ) - { - // We don't want to destroy the queue on a get failure. - // The RemoteCache will Zombie and queue. - // Since get does not use the queue, I don't want to kill the queue. - throw ex; - } - - return new HashMap>(); - } - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet() throws IOException - { - return remoteCacheClient.getKeySet(); - } - - /** - * Adds a remove request to the remote cache. - *

- * @param key - * @return if this was successful - * @throws IOException - */ - @Override - public boolean remove( K key ) - throws IOException - { - removeCount++; - try - { - cacheEventQueue.addRemoveEvent( key ); - } - catch ( IOException e ) - { - log.error( "Problem adding RemoveEvent to queue.", e ); - cacheEventQueue.destroy(); - throw e; - } - return false; - } - - /** - * Adds a removeAll request to the remote cache. - *

- * @throws IOException - */ - @Override - public void removeAll() - throws IOException - { - try - { - cacheEventQueue.addRemoveAllEvent(); - } - catch ( IOException e ) - { - log.error( "Problem adding RemoveAllEvent to queue.", e ); - cacheEventQueue.destroy(); - throw e; - } - } - - /** Adds a dispose request to the remote cache. */ - @Override - public void dispose() - { - try - { - cacheEventQueue.addDisposeEvent(); - } - catch ( IOException e ) - { - log.error( "Problem adding DisposeEvent to queue.", e ); - cacheEventQueue.destroy(); - } - } - - /** - * No remote invocation. - *

- * @return The size value - */ - @Override - public int getSize() - { - return remoteCacheClient.getSize(); - } - - /** - * No remote invocation. - *

- * @return The cacheType value - */ - @Override - public CacheType getCacheType() - { - return CacheType.REMOTE_CACHE; - } - - /** - * Returns the asyn cache status. An error status indicates either the remote connection is not - * available, or the asyn queue has been unexpectedly destroyed. No remote invocation. - *

- * @return The status value - */ - @Override - public CacheStatus getStatus() - { - return cacheEventQueue.isWorking() ? remoteCacheClient.getStatus() : CacheStatus.ERROR; - } - - /** - * Gets the cacheName attribute of the RemoteCacheNoWait object - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return remoteCacheClient.getCacheName(); - } - - /** - * Replaces the remote cache service handle with the given handle and reset the event queue by - * starting up a new instance. - *

- * @param remote - */ - public void fixCache( ICacheServiceNonLocal remote ) - { - remoteCacheClient.fixCache( remote ); - resetEventQ(); - } - - /** - * Resets the event q by first destroying the existing one and starting up new one. - *

- * There may be no good reason to kill the existing queue. We will sometimes need to set a new - * listener id, so we should create a new queue. We should let the old queue drain. If we were - * Connected to the failover, it would be best to finish sending items. - */ - public void resetEventQ() - { - ICacheEventQueue previousQueue = cacheEventQueue; - - this.cacheEventQueue = createCacheEventQueue(this.remoteCacheClient); - - if ( previousQueue.isWorking() ) - { - // we don't expect anything, it would have all gone to the zombie - if ( log.isInfoEnabled() ) - { - log.info( "resetEventQ, previous queue has [" + previousQueue.size() + "] items queued up." ); - } - previousQueue.destroy(); - } - } - - /** - * This is temporary. It allows the manager to get the lister. - *

- * @return the instance of the remote cache client used by this object - */ - protected IRemoteCacheClient getRemoteCache() - { - return remoteCacheClient; - } - - /** - * @return Returns the AuxiliaryCacheAttributes. - */ - @Override - public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() - { - return remoteCacheClient.getAuxiliaryCacheAttributes(); - } - - /** - * This is for testing only. It allows you to take a look at the event queue. - *

- * @return ICacheEventQueue - */ - protected ICacheEventQueue getCacheEventQueue() - { - return this.cacheEventQueue; - } - - /** - * Returns the stats and the cache.toString(). - *

- * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - return getStats() + "\n" + remoteCacheClient.toString(); - } - - /** - * Returns the statistics in String form. - *

- * @return String - */ - @Override - public String getStats() - { - return getStatistics().toString(); - } - - /** - * @return statistics about this communication - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Remote Cache No Wait" ); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "Status", getStatus() ) ); - - // get the stats from the cache queue too - IStats cStats = this.remoteCacheClient.getStatistics(); - if ( cStats != null ) - { - elems.addAll(cStats.getStatElements()); - } - - // get the stats from the event queue too - IStats eqStats = this.cacheEventQueue.getStatistics(); - elems.addAll(eqStats.getStatElements()); - - elems.add(new StatElement( "Get Count", Integer.valueOf(this.getCount) ) ); - elems.add(new StatElement( "GetMatching Count", Integer.valueOf(this.getMatchingCount) ) ); - elems.add(new StatElement( "GetMultiple Count", Integer.valueOf(this.getMultipleCount) ) ); - elems.add(new StatElement( "Remove Count", Integer.valueOf(this.removeCount) ) ); - elems.add(new StatElement( "Put Count", Integer.valueOf(this.putCount) ) ); - - stats.setStatElements( elems ); - - return stats; - } - - /** - * this won't be called since we don't do ICache logging here. - *

- * @return String - */ - @Override - public String getEventLoggingExtraInfo() - { - return "Remote Cache No Wait"; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacade.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacade.java deleted file mode 100644 index 3fd4e46a57e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacade.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.List; - -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Used to provide access to multiple services under nowait protection. Factory should construct - * NoWaitFacade to give to the composite cache out of caches it constructs from the varies manager - * to lateral services. - *

- * Typically, we only connect to one remote server per facade. We use a list of one - * RemoteCacheNoWait. - */ -public class RemoteCacheNoWaitFacade - extends AbstractRemoteCacheNoWaitFacade -{ - /** log instance */ - private static final Log log = LogFactory.getLog( RemoteCacheNoWaitFacade.class ); - - /** Provide factory instance to RemoteCacheFailoverRunner */ - private final RemoteCacheFactory cacheFactory; - - /** - * Constructs with the given remote cache, and fires events to any listeners. - *

- * @param noWaits - * @param rca - * @param cacheEventLogger - * @param elementSerializer - * @param cacheFactory - */ - public RemoteCacheNoWaitFacade( List> noWaits, - IRemoteCacheAttributes rca, - ICacheEventLogger cacheEventLogger, - IElementSerializer elementSerializer, - RemoteCacheFactory cacheFactory) - { - super( noWaits, rca, cacheEventLogger, elementSerializer ); - this.cacheFactory = cacheFactory; - } - - /** - * Begin the failover process if this is a local cache. Clustered remote caches do not failover. - *

- * @param rcnw The no wait in error. - */ - @Override - protected void failover( RemoteCacheNoWait rcnw ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "in failover for " + rcnw ); - } - - if ( getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL ) - { - if ( rcnw.getStatus() == CacheStatus.ERROR ) - { - // start failover, primary recovery process - RemoteCacheFailoverRunner runner = new RemoteCacheFailoverRunner( this, this.cacheFactory ); - runner.setDaemon( true ); - runner.start(); - runner.notifyError(); - - if ( getCacheEventLogger() != null ) - { - getCacheEventLogger().logApplicationEvent( "RemoteCacheNoWaitFacade", "InitiatedFailover", - rcnw + " was in error." ); - } - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "The noWait is not in error" ); - } - } - } - } - -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteLocation.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteLocation.java deleted file mode 100644 index 813aecf4fc4..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteLocation.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Location of the RMI registry. - */ -public final class RemoteLocation -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( RemoteLocation.class ); - - /** Pattern for parsing server:port */ - private static final Pattern SERVER_COLON_PORT = Pattern.compile("(\\S+)\\s*:\\s*(\\d+)"); - - /** Host name */ - private final String host; - - /** Port */ - private final int port; - - /** - * Constructor for the Location object - *

- * @param host - * @param port - */ - public RemoteLocation( String host, int port ) - { - this.host = host; - this.port = port; - } - - /** - * @return the host - */ - public String getHost() - { - return host; - } - - /** - * @return the port - */ - public int getPort() - { - return port; - } - - /** - * @param obj - * @return true if the host and port are equal - */ - @Override - public boolean equals( Object obj ) - { - if ( obj == this ) - { - return true; - } - if ( obj == null || !( obj instanceof RemoteLocation ) ) - { - return false; - } - RemoteLocation l = (RemoteLocation) obj; - if ( this.host == null ) - { - return l.host == null && port == l.port; - } - return host.equals( l.host ) && port == l.port; - } - - /** - * @return int - */ - @Override - public int hashCode() - { - return host == null ? port : host.hashCode() ^ port; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - if (this.host != null) - { - sb.append(this.host); - } - sb.append(':').append(this.port); - - return sb.toString(); - } - - /** - * Parse remote server and port from the string representation server:port and store them in - * a RemoteLocation object - * - * @param server the input string - * @return the remote location object - */ - public static RemoteLocation parseServerAndPort(final String server) - { - Matcher match = SERVER_COLON_PORT.matcher(server); - - if (match.find() && match.groupCount() == 2) - { - RemoteLocation location = new RemoteLocation( match.group(1), Integer.parseInt( match.group(2) ) ); - return location; - } - else - { - log.error("Invalid server descriptor: " + server); - } - - return null; - } -} \ No newline at end of file diff --git a/src/org/apache/commons/jcs/auxiliary/remote/RemoteUtils.java b/src/org/apache/commons/jcs/auxiliary/remote/RemoteUtils.java deleted file mode 100644 index fef1ac9279d..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/RemoteUtils.java +++ /dev/null @@ -1,275 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URL; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.RMISocketFactory; -import java.util.Enumeration; -import java.util.Properties; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class provides some basic utilities for doing things such as starting - * the registry properly. - */ -public class RemoteUtils -{ - /** The logger. */ - private static final Log log = LogFactory.getLog(RemoteUtils.class); - - /** No instances please. */ - private RemoteUtils() - { - super(); - } - - /** - * Creates and exports a registry on the specified port of the local host. - *

- * - * @param port - * @return the registry - */ - public static Registry createRegistry(int port) - { - Registry registry = null; - - // if ( log.isInfoEnabled() ) - // { - // log.info( "createRegistry> Setting security manager" ); - // } - // - // System.setSecurityManager( new RMISecurityManager() ); - - if (port < 1024) - { - if (log.isWarnEnabled()) - { - log.warn("createRegistry> Port chosen was less than 1024, will use default [" + Registry.REGISTRY_PORT + "] instead."); - } - port = Registry.REGISTRY_PORT; - } - - try - { - registry = LocateRegistry.createRegistry(port); - log.info("createRegistry> Created the registry on port " + port); - } - catch (RemoteException e) - { - log.warn("createRegistry> Problem creating registry. It may already be started. " + e.getMessage()); - } - catch (Throwable t) - { - log.error("createRegistry> Problem creating registry.", t); - } - - if (registry == null) - { - try - { - registry = LocateRegistry.getRegistry(port); - } - catch (RemoteException e) - { - log.error("createRegistry> Problem getting a registry reference.", e); - } - } - - return registry; - } - - /** - * Loads properties for the named props file. - * First tries class path, then file, then URL - *

- * - * @param propFile - * @return The properties object for the file - * @throws IOException - */ - public static Properties loadProps(String propFile) - throws IOException - { - InputStream is = RemoteUtils.class.getResourceAsStream(propFile); - - if (null == is) // not found in class path - { - // Try root of class path - if (propFile != null && !propFile.startsWith("/")) - { - is = RemoteUtils.class.getResourceAsStream("/" + propFile); - } - } - - if (null == is) // not found in class path - { - if (new File(propFile).exists()) - { - // file found - is = new FileInputStream(propFile); - } - else - { - // try URL - is = new URL(propFile).openStream(); - } - } - - Properties props = new Properties(); - try - { - props.load(is); - if (log.isDebugEnabled()) - { - log.debug("props.size=" + props.size()); - } - - if (log.isDebugEnabled()) - { - Enumeration en = props.keys(); - StringBuilder buf = new StringBuilder(); - while (en.hasMoreElements()) - { - String key = (String) en.nextElement(); - buf.append("\n" + key + " = " + props.getProperty(key)); - } - log.debug(buf.toString()); - } - - } - catch (Exception ex) - { - log.error("Error loading remote properties, for file name [" + propFile + "]", ex); - } - finally - { - if (is != null) - { - is.close(); - } - } - return props; - } - - /** - * Configure a custom socket factory to set the timeout value. This sets the - * global socket factory. It's used only if a custom factory is not - * configured for the specific object. - *

- * - * @param timeoutMillis - */ - public static void configureGlobalCustomSocketFactory(final int timeoutMillis) - { - try - { - // Don't set a socket factory if the setting is -1 - if (timeoutMillis > 0) - { - if (log.isInfoEnabled()) - { - log.info("RmiSocketFactoryTimeoutMillis [" + timeoutMillis + "]. " - + " Configuring a custom socket factory."); - } - - // use this socket factory to add a timeout. - RMISocketFactory.setSocketFactory(new RMISocketFactory() - { - @Override - public Socket createSocket(String host, int port) - throws IOException - { - Socket socket = new Socket(); - socket.setSoTimeout(timeoutMillis); - socket.setSoLinger(false, 0); - socket.connect(new InetSocketAddress(host, port), timeoutMillis); - return socket; - } - - @Override - public ServerSocket createServerSocket(int port) - throws IOException - { - return new ServerSocket(port); - } - }); - } - } - catch (IOException e) - { - // Only try to do it once. Otherwise we - // Generate errors for each region on construction. - RMISocketFactory factoryInUse = RMISocketFactory.getSocketFactory(); - if (factoryInUse != null && !factoryInUse.getClass().getName().startsWith("org.apache.commons.jcs")) - { - log.info("Could not create new custom socket factory. " + e.getMessage() + " Factory in use = " - + RMISocketFactory.getSocketFactory()); - } - } - } - - /** - * Get the naming url used for RMI registration - * - * @param location - * the remote location - * @param serviceName - * the remote service name - * @return the URL for RMI lookup - */ - public static String getNamingURL(final RemoteLocation location, final String serviceName) - { - return getNamingURL(location.getHost(), location.getPort(), serviceName); - } - - /** - * Get the naming url used for RMI registration - * - * @param registryHost - * the remote host - * @param registryPort - * the remote port - * @param serviceName - * the remote service name - * @return the URL for RMI lookup - */ - public static String getNamingURL(final String registryHost, final int registryPort, final String serviceName) - { - if (registryHost.contains(":")) - { // TODO improve this check? See also JCS-133 - return "//[" + registryHost.replaceFirst("%", "%25") + "]:" + registryPort + "/" + serviceName; - } - final String registryURL = "//" + registryHost + ":" + registryPort + "/" + serviceName; - return registryURL; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java deleted file mode 100644 index 2b1e20e2898..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java +++ /dev/null @@ -1,172 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.RemoteLocation; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; - -/** - * This specifies what a remote cache configuration object should look like. - */ -public interface ICommonRemoteCacheAttributes - extends AuxiliaryCacheAttributes -{ - /** The default timeout for the custom RMI socket factory */ - int DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS = 10000; - - /** - * Gets the remoteTypeName attribute of the IRemoteCacheAttributes object - *

- * @return The remoteTypeName value - */ - String getRemoteTypeName(); - - /** - * Sets the remoteTypeName attribute of the IRemoteCacheAttributes object - *

- * @param s The new remoteTypeName value - */ - void setRemoteTypeName( String s ); - - /** - * Gets the remoteType attribute of the IRemoteCacheAttributes object - *

- * @return The remoteType value - */ - RemoteType getRemoteType(); - - /** - * Sets the remoteType attribute of the IRemoteCacheAttributes object - *

- * @param p The new remoteType value - */ - void setRemoteType( RemoteType p ); - - /** - * Gets the remoteServiceName attribute of the IRemoteCacheAttributes object - *

- * @return The remoteServiceName value - */ - String getRemoteServiceName(); - - /** - * Sets the remoteServiceName attribute of the IRemoteCacheAttributes object - *

- * @param s The new remoteServiceName value - */ - void setRemoteServiceName( String s ); - - /** - * Sets the location attribute of the RemoteCacheAttributes object. - *

- * @param location The new location value - */ - void setRemoteLocation( RemoteLocation location ); - - /** - * Sets the location attribute of the RemoteCacheAttributes object. - *

- * @param host The new remoteHost value - * @param port The new remotePort value - */ - void setRemoteLocation( String host, int port ); - - /** - * Gets the location attribute of the RemoteCacheAttributes object. - *

- * @return The remote location value - */ - public RemoteLocation getRemoteLocation(); - - /** - * Gets the clusterServers attribute of the IRemoteCacheAttributes object - *

- * @return The clusterServers value - */ - String getClusterServers(); - - /** - * Sets the clusterServers attribute of the IRemoteCacheAttributes object - *

- * @param s The new clusterServers value - */ - void setClusterServers( String s ); - - /** - * Gets the removeUponRemotePut attribute of the IRemoteCacheAttributes object - *

- * @return The removeUponRemotePut value - */ - boolean getRemoveUponRemotePut(); - - /** - * Sets the removeUponRemotePut attribute of the IRemoteCacheAttributes object - *

- * @param r The new removeUponRemotePut value - */ - void setRemoveUponRemotePut( boolean r ); - - /** - * Gets the getOnly attribute of the IRemoteCacheAttributes object - *

- * @return The getOnly value - */ - boolean getGetOnly(); - - /** - * Sets the getOnly attribute of the IRemoteCacheAttributes object - *

- * @param r The new getOnly value - */ - void setGetOnly( boolean r ); - - /** - * Should cluster updates be propagated to the locals - *

- * @return The localClusterConsistency value - */ - boolean isLocalClusterConsistency(); - - /** - * Should cluster updates be propagated to the locals - *

- * @param r The new localClusterConsistency value - */ - void setLocalClusterConsistency( boolean r ); - - /** - * This sets a general timeout on the rmi socket factory. By default the socket factory will - * block forever. - *

- * We have a default setting. The default rmi behavior should never be used. - *

- * @return int milliseconds - */ - int getRmiSocketFactoryTimeoutMillis(); - - /** - * This sets a general timeout on the RMI socket factory. By default the socket factory will - * block forever. - *

- * @param rmiSocketFactoryTimeoutMillis - */ - void setRmiSocketFactoryTimeoutMillis( int rmiSocketFactoryTimeoutMillis ); -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheAttributes.java deleted file mode 100644 index aa528ba97f6..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheAttributes.java +++ /dev/null @@ -1,182 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.behavior; - -import java.util.List; - -import org.apache.commons.jcs.auxiliary.remote.RemoteLocation; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This specifies what a remote cache configuration object should look like. - */ -public interface IRemoteCacheAttributes - extends ICommonRemoteCacheAttributes -{ - /** - * If RECEIVE is false then the remote cache will not register a listener with the remote - * server. This allows you to configure a remote server as a repository from which you can get - * and to which you put, but from which you do not receive any notifications. That is, you will - * not receive updates or removes. - *

- * If you set this option to false, you should set your local memory size to 0. - */ - boolean DEFAULT_RECEIVE = true; - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - */ - int DEFAULT_ZOMBIE_QUEUE_MAX_SIZE = 1000; - - /** - * Gets the failoverIndex attribute of the IRemoteCacheAttributes object. - *

- * This specifies which server in the list we are listening to if the number is greater than 0 - * we will try to move to 0 position the primary is added as position 1 if it is present - *

- * @return The failoverIndex value - */ - int getFailoverIndex(); - - /** - * Sets the failoverIndex attribute of the IRemoteCacheAttributes object - *

- * @param p The new failoverIndex value - */ - void setFailoverIndex( int p ); - - /** - * Gets the failovers attribute of the IRemoteCacheAttributes object - *

- * @return The failovers value - */ - List getFailovers(); - - /** - * Sets the failovers attribute of the IRemoteCacheAttributes object - *

- * @param failovers The new failovers value - */ - void setFailovers( List failovers ); - - /** - * Gets the localPort attribute of the IRemoteCacheAttributes object - *

- * @return The localPort value - */ - int getLocalPort(); - - /** - * Sets the localPort attribute of the IRemoteCacheAttributes object - *

- * @param p The new localPort value - */ - void setLocalPort( int p ); - - /** - * Gets the failoverServers attribute of the IRemoteCacheAttributes object - *

- * @return The failoverServers value - */ - String getFailoverServers(); - - /** - * Sets the failoverServers attribute of the IRemoteCacheAttributes object - *

- * @param s The new failoverServers value - */ - void setFailoverServers( String s ); - - /** - * The thread pool the remote cache should use. At first this will only be for gets. - *

- * The default name is "remote_cache_client" - *

- * @return the name of the pool - */ - String getThreadPoolName(); - - /** - * Set the name of the pool to use. Pools should be defined in the cache.ccf. - *

- * @param name - */ - void setThreadPoolName( String name ); - - /** - * -1 and 0 mean no timeout, this is the default if the timeout is -1 or 0, no threadpool will - * be used. - *

- * @return the time in millis - */ - int getGetTimeoutMillis(); - - /** - * -1 means no timeout, this is the default if the timeout is -1 or 0, no threadpool will be - * used. If the timeout is greater than 0 a threadpool will be used for get requests. - *

- * @param millis - */ - void setGetTimeoutMillis( int millis ); - - /** - * By default this option is true. If you set it to false, you will not receive updates or - * removes from the remote server. - *

- * @param receive - */ - void setReceive( boolean receive ); - - /** - * If RECEIVE is false then the remote cache will not register a listener with the remote - * server. This allows you to configure a remote server as a repository from which you can get - * and to which you put, but from which you do not receive any notifications. That is, you will - * not receive updates or removes. - *

- * If you set this option to false, you should set your local memory size to 0. - *

- * The remote cache manager uses this value to decide whether or not to register a listener. - *

- * It makes no sense to configure a cluster remote cache to no receive. - *

- * Since a non-receiving remote cache client will not register a listener, it will not have a - * listener id assigned from the server. As such the remote server cannot determine if it is a - * cluster or a normal client. It will assume that it is a normal client. - *

- * @return the receive value. - */ - boolean isReceive(); - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @param zombieQueueMaxSize The zombieQueueMaxSize to set. - */ - void setZombieQueueMaxSize( int zombieQueueMaxSize ); - - /** - * The number of elements the zombie queue will hold. This queue is used to store events if we - * loose our connection with the server. - *

- * @return Returns the zombieQueueMaxSize. - */ - int getZombieQueueMaxSize(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheClient.java b/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheClient.java deleted file mode 100644 index acb68f65d8d..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheClient.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; - -/** - * This defines the behavior expected of a remote cache client. This extends Auxiliary cache which - * in turn extends ICache. - *

- * I'd like generalize this a bit. - *

- * @author Aaron Smuts - */ -public interface IRemoteCacheClient - extends AuxiliaryCache -{ - /** - * Replaces the current remote cache service handle with the given handle. If the current remote - * is a Zombie, the propagate the events that may be queued to the restored service. - *

- * @param remote ICacheServiceNonLocal -- the remote server or proxy to the remote server - */ - void fixCache( ICacheServiceNonLocal remote ); - - /** - * Gets the listenerId attribute of the RemoteCacheListener object. - *

- * All requests to the remote cache must include a listener id. This allows the server to avoid - * sending updates the the listener associated with this client. - *

- * @return The listenerId value - */ - long getListenerId(); - - /** - * This returns the listener associated with this remote cache. TODO we should try to get this - * out of the interface. - *

- * @return IRemoteCacheListener - */ - IRemoteCacheListener getListener(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheConstants.java b/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheConstants.java deleted file mode 100644 index 0dd06a9d10e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheConstants.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; - - -/** - * This holds constants that are used by the remote cache. - */ -public interface IRemoteCacheConstants -{ - /** Mapping to props file value */ - String REMOTE_CACHE_SERVICE_VAL = ICacheServiceNonLocal.class.getName(); - - /** The prefix for cache server config. */ - String CACHE_SERVER_PREFIX = "jcs.remotecache"; - - /** - * I'm trying to migrate everything to use this prefix. All those below will be replaced. Any of - * the RemoteCacheServerAttributes can be configured this way. - */ - String CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX = CACHE_SERVER_PREFIX + ".serverattributes"; - - /** - * This is the name of the class that will be used for an object specific socket factory. - */ - String CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX = CACHE_SERVER_PREFIX + ".customrmisocketfactory"; - - /** Property prefix, should be jcs.remote but this would break existing config. */ - String PROPERTY_PREFIX = "remote"; - - /** Mapping to props file value */ - String SOCKET_TIMEOUT_MILLIS = PROPERTY_PREFIX + ".cache.rmiSocketFactoryTimeoutMillis"; - - /** Mapping to props file value */ - String REMOTE_CACHE_SERVICE_NAME = PROPERTY_PREFIX + ".cache.service.name"; - - /** Mapping to props file value */ - String TOMCAT_XML = PROPERTY_PREFIX + ".tomcat.xml"; - - /** Mapping to props file value */ - String TOMCAT_ON = PROPERTY_PREFIX + ".tomcat.on"; - - /** Mapping to props file value */ - String REMOTE_CACHE_SERVICE_PORT = PROPERTY_PREFIX + ".cache.service.port"; - - /** Mapping to props file value */ - String REMOTE_LOCAL_CLUSTER_CONSISTENCY = PROPERTY_PREFIX + ".cluster.LocalClusterConsistency"; - - /** Mapping to props file value */ - String REMOTE_ALLOW_CLUSTER_GET = PROPERTY_PREFIX + ".cluster.AllowClusterGet"; -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheDispatcher.java b/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheDispatcher.java deleted file mode 100644 index c5d0b0dd91d..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheDispatcher.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse; - -import java.io.IOException; - -/** - * In the future, this can be used as a generic dispatcher abstraction. - *

- * At the time of creation, only the http remote cache uses it. The RMI remote could be converted to - * use it as well. - */ -public interface IRemoteCacheDispatcher -{ - /** - * All requests will go through this method. The dispatcher implementation will send the request - * remotely. - *

- * @param remoteCacheRequest - * @return RemoteCacheResponse - * @throws IOException - */ - - RemoteCacheResponse dispatchRequest( RemoteCacheRequest remoteCacheRequest ) - throws IOException; -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheListener.java b/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheListener.java deleted file mode 100644 index b6733830f2f..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheListener.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.behavior.ICacheListener; - -import java.io.IOException; -import java.rmi.Remote; - -/** - * Listens for remote cache event notification ( rmi callback ). - */ -public interface IRemoteCacheListener - extends ICacheListener, Remote -{ - /** - * Get the id to be used by this manager. - *

- * @return long - * @throws IOException - */ - @Override - long getListenerId() - throws IOException; - - /** - * Set the id to be used by this manager. The remote cache server identifies clients by this id. - * The value will be set by the server through the remote cache listener. - *

- * @param id - * @throws IOException - */ - @Override - void setListenerId( long id ) - throws IOException; - - /** - * Gets the remoteType attribute of the IRemoteCacheListener object - *

- * @return The remoteType value - * @throws IOException - */ - RemoteType getRemoteType() - throws IOException; - - /** - * This is for debugging. It allows the remote cache server to log the address of any listeners - * that register. - *

- * @return the local host address. - * @throws IOException - */ - String getLocalHostAddress() - throws IOException; - - /** - * Deregisters itself. - *

- * @throws IOException - */ - void dispose() - throws IOException; -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java b/src/org/apache/commons/jcs/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java deleted file mode 100644 index 49515f3ff63..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** Constants used throughout the HTTP remote cache. */ -public interface IRemoteHttpCacheConstants -{ - /** The prefix for cache server config. */ - String HTTP_CACHE_SERVER_PREFIX = "jcs.remotehttpcache"; - - /** All of the RemoteHttpCacheServiceAttributes can be configured this way. */ - String HTTP_CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX = HTTP_CACHE_SERVER_PREFIX - + ".serverattributes"; -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/AbstractHttpClient.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/AbstractHttpClient.java deleted file mode 100644 index 9862887a861..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/AbstractHttpClient.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.http.HttpResponse; -import org.apache.http.HttpVersion; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.CookieSpecs; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.methods.RequestBuilder; -import org.apache.http.impl.client.HttpClientBuilder; - -/** - * This class simply configures the http multithreaded connection manager. - *

- * This is abstract because it can do anything. Child classes can overwrite whatever they want. - */ -public abstract class AbstractHttpClient -{ - /** The client */ - private HttpClient httpClient; - - /** The protocol version */ - private HttpVersion httpVersion; - - /** Configuration settings. */ - private RemoteHttpCacheAttributes remoteHttpCacheAttributes; - - /** The Logger. */ - private static final Log log = LogFactory.getLog( AbstractHttpClient.class ); - - /** - * Sets the default Properties File and Heading, and creates the HttpClient and connection - * manager. - *

- * @param remoteHttpCacheAttributes - */ - public AbstractHttpClient( RemoteHttpCacheAttributes remoteHttpCacheAttributes ) - { - this.remoteHttpCacheAttributes = remoteHttpCacheAttributes; - - String httpVersion = getRemoteHttpCacheAttributes().getHttpVersion(); - if ( "1.1".equals( httpVersion ) ) - { - this.httpVersion = HttpVersion.HTTP_1_1; - } - else if ( "1.0".equals( httpVersion ) ) - { - this.httpVersion = HttpVersion.HTTP_1_0; - } - else - { - log.warn( "Unrecognized value for 'httpVersion': [" + httpVersion + "], defaulting to 1.1" ); - this.httpVersion = HttpVersion.HTTP_1_1; - } - - HttpClientBuilder builder = HttpClientBuilder.create(); - configureClient(builder); - this.httpClient = builder.build(); - } - - /** - * Configures the http client. - * - * @param builder client builder to configure - */ - protected void configureClient(HttpClientBuilder builder) - { - if ( getRemoteHttpCacheAttributes().getMaxConnectionsPerHost() > 0 ) - { - builder.setMaxConnTotal(getRemoteHttpCacheAttributes().getMaxConnectionsPerHost()); - builder.setMaxConnPerRoute(getRemoteHttpCacheAttributes().getMaxConnectionsPerHost()); - } - - builder.setDefaultRequestConfig(RequestConfig.custom() - .setConnectTimeout(getRemoteHttpCacheAttributes().getConnectionTimeoutMillis()) - .setSocketTimeout(getRemoteHttpCacheAttributes().getSocketTimeoutMillis()) - // By default we instruct HttpClient to ignore cookies. - .setCookieSpec(CookieSpecs.IGNORE_COOKIES) - .build()); - } - - /** - * Execute the web service call - *

- * @param builder builder for the post request - * - * @return the call response - * - * @throws IOException on i/o error - */ - protected final HttpResponse doWebserviceCall( RequestBuilder builder ) - throws IOException - { - preProcessWebserviceCall( builder.setVersion(httpVersion) ); - HttpUriRequest request = builder.build(); - HttpResponse httpResponse = this.httpClient.execute( request ); - postProcessWebserviceCall( request, httpResponse ); - - return httpResponse; - } - - /** - * Called before the execute call on the client. - *

- * @param requestBuilder http method request builder - * - * @throws IOException - */ - protected abstract void preProcessWebserviceCall( RequestBuilder requestBuilder ) - throws IOException; - - /** - * Called after the execute call on the client. - *

- * @param request http request - * @param httpState result of execution - * - * @throws IOException - */ - protected abstract void postProcessWebserviceCall( HttpUriRequest request, HttpResponse httpState ) - throws IOException; - - /** - * @return the remoteHttpCacheAttributes - */ - protected RemoteHttpCacheAttributes getRemoteHttpCacheAttributes() - { - return remoteHttpCacheAttributes; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCache.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCache.java deleted file mode 100644 index 54ead3b5dc6..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCache.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -import java.io.IOException; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.AbstractRemoteAuxiliaryCache; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener; -import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This uses an http client as the service. - */ -public class RemoteHttpCache - extends AbstractRemoteAuxiliaryCache -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( RemoteHttpCache.class ); - - /** for error notifications */ - private RemoteHttpCacheMonitor monitor; - - /** Keep the child copy here for the restore process. */ - private RemoteHttpCacheAttributes remoteHttpCacheAttributes; - - /** - * Constructor for the RemoteCache object. This object communicates with a remote cache server. - * One of these exists for each region. This also holds a reference to a listener. The same - * listener is used for all regions for one remote server. Holding a reference to the listener - * allows this object to know the listener id assigned by the remote cache. - *

- * @param remoteHttpCacheAttributes - * @param remote - * @param listener - * @param monitor the cache monitor - */ - public RemoteHttpCache( RemoteHttpCacheAttributes remoteHttpCacheAttributes, ICacheServiceNonLocal remote, - IRemoteCacheListener listener, RemoteHttpCacheMonitor monitor ) - { - super( remoteHttpCacheAttributes, remote, listener ); - - this.remoteHttpCacheAttributes = remoteHttpCacheAttributes; - this.monitor = monitor; - } - - /** - * Nothing right now. This should setup a zombie and initiate recovery. - *

- * @param ex - * @param msg - * @param eventName - * @throws IOException - */ - @Override - protected void handleException( Exception ex, String msg, String eventName ) - throws IOException - { - // we should not switch if the existing is a zombie. - if ( !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) ) - { - String message = "Disabling remote cache due to error: " + msg; - logError( cacheName, "", message ); - log.error( message, ex ); - - setRemoteCacheService( new ZombieCacheServiceNonLocal( getRemoteCacheAttributes().getZombieQueueMaxSize() ) ); - - monitor.notifyError( this ); - } - - if ( ex instanceof IOException ) - { - throw (IOException) ex; - } - throw new IOException( ex.getMessage() ); - } - - /** - * @return url of service - */ - @Override - public String getEventLoggingExtraInfo() - { - return null; - } - - /** - * @return the remoteHttpCacheAttributes - */ - public RemoteHttpCacheAttributes getRemoteHttpCacheAttributes() - { - return remoteHttpCacheAttributes; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java deleted file mode 100644 index c68670d274a..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes; - -/** Http client specific settings. */ -public class RemoteHttpCacheAttributes - extends RemoteCacheAttributes -{ - /** Don't change. */ - private static final long serialVersionUID = -5944327125140505212L; - - /** http verison to use. */ - private static final String DEFAULT_HTTP_VERSION = "1.1"; - - /** The max connections allowed per host */ - private int maxConnectionsPerHost = 100; - - /** The socket timeout. */ - private int socketTimeoutMillis = 3000; - - /** The socket connections timeout */ - private int connectionTimeoutMillis = 5000; - - /** http verison to use. */ - private String httpVersion = DEFAULT_HTTP_VERSION; - - /** The cache name will be included on the parameters */ - private boolean includeCacheNameAsParameter = true; - - /** keys and patterns will be included in the parameters */ - private boolean includeKeysAndPatternsAsParameter = true; - - /** keys and patterns will be included in the parameters */ - private boolean includeRequestTypeasAsParameter = true; - - /** The complete URL to the service. */ - private String url; - - /** The default classname for the client. */ - public static final String DEFAULT_REMOTE_HTTP_CLIENT_CLASS_NAME = RemoteHttpCacheClient.class.getName(); - - /** This allows users to inject their own client implementation. */ - private String remoteHttpClientClassName = DEFAULT_REMOTE_HTTP_CLIENT_CLASS_NAME; - - /** - * @param maxConnectionsPerHost the maxConnectionsPerHost to set - */ - public void setMaxConnectionsPerHost( int maxConnectionsPerHost ) - { - this.maxConnectionsPerHost = maxConnectionsPerHost; - } - - /** - * @return the maxConnectionsPerHost - */ - public int getMaxConnectionsPerHost() - { - return maxConnectionsPerHost; - } - - /** - * @param socketTimeoutMillis the socketTimeoutMillis to set - */ - public void setSocketTimeoutMillis( int socketTimeoutMillis ) - { - this.socketTimeoutMillis = socketTimeoutMillis; - } - - /** - * @return the socketTimeoutMillis - */ - public int getSocketTimeoutMillis() - { - return socketTimeoutMillis; - } - - /** - * @param httpVersion the httpVersion to set - */ - public void setHttpVersion( String httpVersion ) - { - this.httpVersion = httpVersion; - } - - /** - * @return the httpVersion - */ - public String getHttpVersion() - { - return httpVersion; - } - - /** - * @param connectionTimeoutMillis the connectionTimeoutMillis to set - */ - public void setConnectionTimeoutMillis( int connectionTimeoutMillis ) - { - this.connectionTimeoutMillis = connectionTimeoutMillis; - } - - /** - * @return the connectionTimeoutMillis - */ - public int getConnectionTimeoutMillis() - { - return connectionTimeoutMillis; - } - - /** - * @param includeCacheNameInURL the includeCacheNameInURL to set - */ - public void setIncludeCacheNameAsParameter( boolean includeCacheNameInURL ) - { - this.includeCacheNameAsParameter = includeCacheNameInURL; - } - - /** - * @return the includeCacheNameInURL - */ - public boolean isIncludeCacheNameAsParameter() - { - return includeCacheNameAsParameter; - } - - /** - * @param includeKeysAndPatternsInURL the includeKeysAndPatternsInURL to set - */ - public void setIncludeKeysAndPatternsAsParameter( boolean includeKeysAndPatternsInURL ) - { - this.includeKeysAndPatternsAsParameter = includeKeysAndPatternsInURL; - } - - /** - * @return the includeKeysAndPatternsInURL - */ - public boolean isIncludeKeysAndPatternsAsParameter() - { - return includeKeysAndPatternsAsParameter; - } - - /** - * @param includeRequestTypeasAsParameter the includeRequestTypeasAsParameter to set - */ - public void setIncludeRequestTypeasAsParameter( boolean includeRequestTypeasAsParameter ) - { - this.includeRequestTypeasAsParameter = includeRequestTypeasAsParameter; - } - - /** - * @return the includeRequestTypeasAsParameter - */ - public boolean isIncludeRequestTypeasAsParameter() - { - return includeRequestTypeasAsParameter; - } - - /** - * @param url the url to set - */ - public void setUrl( String url ) - { - this.url = url; - } - - /** - * @return the url - */ - public String getUrl() - { - return url; - } - - /** - * @param remoteHttpClientClassName the remoteHttpClientClassName to set - */ - public void setRemoteHttpClientClassName( String remoteHttpClientClassName ) - { - this.remoteHttpClientClassName = remoteHttpClientClassName; - } - - /** - * @return the remoteHttpClientClassName - */ - public String getRemoteHttpClientClassName() - { - return remoteHttpClientClassName; - } - - /** - * @return String details - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n RemoteHttpCacheAttributes" ); - buf.append( "\n maxConnectionsPerHost = [" + getMaxConnectionsPerHost() + "]" ); - buf.append( "\n socketTimeoutMillis = [" + getSocketTimeoutMillis() + "]" ); - buf.append( "\n httpVersion = [" + getHttpVersion() + "]" ); - buf.append( "\n connectionTimeoutMillis = [" + getConnectionTimeoutMillis() + "]" ); - buf.append( "\n includeCacheNameAsParameter = [" + isIncludeCacheNameAsParameter() + "]" ); - buf.append( "\n includeKeysAndPatternsAsParameter = [" + isIncludeKeysAndPatternsAsParameter() + "]" ); - buf.append( "\n includeRequestTypeasAsParameter = [" + isIncludeRequestTypeasAsParameter() + "]" ); - buf.append( "\n url = [" + getUrl() + "]" ); - buf.append( "\n remoteHttpClientClassName = [" + getRemoteHttpClientClassName() + "]" ); - buf.append( super.toString() ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClient.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClient.java deleted file mode 100644 index 9a5c9b0d29d..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClient.java +++ /dev/null @@ -1,496 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheDispatcher; -import org.apache.commons.jcs.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient; -import org.apache.commons.jcs.auxiliary.remote.util.RemoteCacheRequestFactory; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.IOException; -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -/** This is the service used by the remote http auxiliary cache. */ -public class RemoteHttpCacheClient - implements IRemoteHttpCacheClient -{ - /** The Logger. */ - private static final Log log = LogFactory.getLog( RemoteHttpCacheClient.class ); - - /** The internal client. */ - private IRemoteCacheDispatcher remoteDispatcher; - - /** The remote attributes */ - private RemoteHttpCacheAttributes remoteHttpCacheAttributes; - - /** Set to true when initialize is called */ - private boolean initialized = false; - - /** For factory construction. */ - public RemoteHttpCacheClient() - { - // does nothing - } - - /** - * Constructs a client. - *

- * @param attributes - */ - public RemoteHttpCacheClient( RemoteHttpCacheAttributes attributes ) - { - setRemoteHttpCacheAttributes( attributes ); - initialize( attributes ); - } - - /** - * The provides an extension point. If you want to extend this and use a special dispatcher, - * here is the place to do it. - *

- * @param attributes - */ - @Override - public void initialize( RemoteHttpCacheAttributes attributes ) - { - setRemoteDispatcher( new RemoteHttpCacheDispatcher( attributes ) ); - - if ( log.isInfoEnabled() ) - { - log.info( "Created remote Dispatcher." + getRemoteDispatcher() ); - } - setInitialized( true ); - } - - /** - * Create a request, process, extract the payload. - *

- * @param cacheName - * @param key - * @return ICacheElement - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key ) - throws IOException - { - return get( cacheName, key, 0 ); - } - - /** - * Create a request, process, extract the payload. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key, long requesterId ) - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createGetRequest( cacheName, key, requesterId ); - - RemoteCacheResponse> remoteHttpCacheResponse = - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Get [" + key + "] = " + remoteHttpCacheResponse ); - } - - if ( remoteHttpCacheResponse != null) - { - return remoteHttpCacheResponse.getPayload(); - } - - return null; - } - - /** - * Gets multiple items from the cache matching the pattern. - *

- * @param cacheName - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching the pattern. - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern ) - throws IOException - { - return getMatching( cacheName, pattern, 0 ); - } - - /** - * Gets multiple items from the cache matching the pattern. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching the pattern. - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern, long requesterId ) - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createGetMatchingRequest( cacheName, pattern, requesterId ); - - RemoteCacheResponse>> remoteHttpCacheResponse = - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - - if ( log.isDebugEnabled() ) - { - log.debug( "GetMatching [" + pattern + "] = " + remoteHttpCacheResponse ); - } - - return remoteHttpCacheResponse.getPayload(); - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys ) - throws IOException - { - return getMultiple( cacheName, keys, 0 ); - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys, long requesterId ) - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createGetMultipleRequest( cacheName, keys, requesterId ); - - RemoteCacheResponse>> remoteHttpCacheResponse = - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - - if ( log.isDebugEnabled() ) - { - log.debug( "GetMultiple [" + keys + "] = " + remoteHttpCacheResponse ); - } - - return remoteHttpCacheResponse.getPayload(); - } - - /** - * Removes the given key from the specified cache. - *

- * @param cacheName - * @param key - * @throws IOException - */ - @Override - public void remove( String cacheName, K key ) - throws IOException - { - remove( cacheName, key, 0 ); - } - - /** - * Removes the given key from the specified cache. - *

- * @param cacheName - * @param key - * @param requesterId - * @throws IOException - */ - @Override - public void remove( String cacheName, K key, long requesterId ) - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createRemoveRequest( cacheName, key, requesterId ); - - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - } - - /** - * Remove all keys from the specified cache. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void removeAll( String cacheName ) - throws IOException - { - removeAll( cacheName, 0 ); - } - - /** - * Remove all keys from the sepcified cache. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - @Override - public void removeAll( String cacheName, long requesterId ) - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createRemoveAllRequest( cacheName, requesterId ); - - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - } - - /** - * Puts a cache item to the cache. - *

- * @param item - * @throws IOException - */ - @Override - public void update( ICacheElement item ) - throws IOException - { - update( item, 0 ); - } - - /** - * Puts a cache item to the cache. - *

- * @param cacheElement - * @param requesterId - * @throws IOException - */ - @Override - public void update( ICacheElement cacheElement, long requesterId ) - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createUpdateRequest( cacheElement, requesterId ); - - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - } - - /** - * Frees the specified cache. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void dispose( String cacheName ) - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createDisposeRequest( cacheName, 0 ); - - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - } - - /** - * Frees the specified cache. - *

- * @throws IOException - */ - @Override - public void release() - throws IOException - { - // noop - } - - /** - * Return the keys in this cache. - *

- * @param cacheName the name of the cache - * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet( String cacheName ) throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = - RemoteCacheRequestFactory.createGetKeySetRequest(cacheName, 0 ); - - RemoteCacheResponse> remoteHttpCacheResponse = getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - - if ( remoteHttpCacheResponse != null && remoteHttpCacheResponse.getPayload() != null ) - { - return remoteHttpCacheResponse.getPayload(); - } - - return Collections.emptySet(); - } - - /** - * Make and alive request. - *

- * @return true if we make a successful alive request. - * @throws IOException - */ - @Override - public boolean isAlive() - throws IOException - { - if ( !isInitialized() ) - { - String message = "The Remote Http Client is not initialized. Cannot process request."; - log.warn( message ); - throw new IOException( message ); - } - - RemoteCacheRequest remoteHttpCacheRequest = RemoteCacheRequestFactory.createAliveCheckRequest( 0 ); - RemoteCacheResponse remoteHttpCacheResponse = - getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest ); - - if ( remoteHttpCacheResponse != null ) - { - return remoteHttpCacheResponse.isSuccess(); - } - - return false; - } - - /** - * @param remoteDispatcher the remoteDispatcher to set - */ - public void setRemoteDispatcher( IRemoteCacheDispatcher remoteDispatcher ) - { - this.remoteDispatcher = remoteDispatcher; - } - - /** - * @return the remoteDispatcher - */ - public IRemoteCacheDispatcher getRemoteDispatcher() - { - return remoteDispatcher; - } - - /** - * @param remoteHttpCacheAttributes the remoteHttpCacheAttributes to set - */ - public void setRemoteHttpCacheAttributes( RemoteHttpCacheAttributes remoteHttpCacheAttributes ) - { - this.remoteHttpCacheAttributes = remoteHttpCacheAttributes; - } - - /** - * @return the remoteHttpCacheAttributes - */ - public RemoteHttpCacheAttributes getRemoteHttpCacheAttributes() - { - return remoteHttpCacheAttributes; - } - - /** - * @param initialized the initialized to set - */ - protected void setInitialized( boolean initialized ) - { - this.initialized = initialized; - } - - /** - * @return the initialized - */ - protected boolean isInitialized() - { - return initialized; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java deleted file mode 100644 index 3bf3c991208..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java +++ /dev/null @@ -1,195 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.nio.charset.Charset; - -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheDispatcher; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse; -import org.apache.commons.jcs.utils.serialization.StandardSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.http.HttpException; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.methods.RequestBuilder; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.util.EntityUtils; - -/** Calls the service. */ -public class RemoteHttpCacheDispatcher - extends AbstractHttpClient - implements IRemoteCacheDispatcher -{ - /** Parameter encoding */ - private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8"); - - /** Named of the parameter */ - private static final String PARAMETER_REQUEST_TYPE = "RequestType"; - - /** Named of the parameter */ - private static final String PARAMETER_KEY = "Key"; - - /** Named of the parameter */ - private static final String PARAMETER_CACHE_NAME = "CacheName"; - - /** The Logger. */ - private static final Log log = LogFactory.getLog( RemoteHttpCacheDispatcher.class ); - - /** This needs to be standard, since the other side is standard */ - private StandardSerializer serializer = new StandardSerializer(); - - /** - * @param remoteHttpCacheAttributes - */ - public RemoteHttpCacheDispatcher( RemoteHttpCacheAttributes remoteHttpCacheAttributes ) - { - super( remoteHttpCacheAttributes ); - } - - /** - * All requests will go through this method. - *

- * TODO consider taking in a URL instead of using the one in the configuration. - *

- * @param remoteCacheRequest - * @return RemoteCacheResponse - * @throws IOException - */ - @Override - public - RemoteCacheResponse dispatchRequest( RemoteCacheRequest remoteCacheRequest ) - throws IOException - { - try - { - byte[] requestAsByteArray = serializer.serialize( remoteCacheRequest ); - - byte[] responseAsByteArray = processRequest( requestAsByteArray, - remoteCacheRequest, - getRemoteHttpCacheAttributes().getUrl()); - - RemoteCacheResponse remoteCacheResponse = null; - try - { - remoteCacheResponse = serializer.deSerialize( responseAsByteArray, null ); - } - catch ( ClassNotFoundException e ) - { - log.error( "Couldn't deserialize the response.", e ); - } - return remoteCacheResponse; - } - catch ( Exception e ) - { - throw new IOException("Problem dispatching request.", e); - } - } - - /** - * Process single request - * - * @param requestAsByteArray request body - * @param remoteCacheRequest the cache request - * @param url target url - * - * @return byte[] - the response - * - * @throws IOException - * @throws HttpException - */ - protected byte[] processRequest( byte[] requestAsByteArray, - RemoteCacheRequest remoteCacheRequest, String url ) - throws IOException, HttpException - { - RequestBuilder builder = RequestBuilder.post( url ).setCharset( DEFAULT_ENCODING ); - - if ( getRemoteHttpCacheAttributes().isIncludeCacheNameAsParameter() - && remoteCacheRequest.getCacheName() != null ) - { - builder.addParameter( PARAMETER_CACHE_NAME, remoteCacheRequest.getCacheName() ); - } - if ( getRemoteHttpCacheAttributes().isIncludeKeysAndPatternsAsParameter() ) - { - String keyValue = ""; - switch ( remoteCacheRequest.getRequestType() ) - { - case GET: - case REMOVE: - case GET_KEYSET: - keyValue = remoteCacheRequest.getKey().toString(); - break; - case GET_MATCHING: - keyValue = remoteCacheRequest.getPattern(); - break; - case GET_MULTIPLE: - keyValue = remoteCacheRequest.getKeySet().toString(); - break; - case UPDATE: - keyValue = remoteCacheRequest.getCacheElement().getKey().toString(); - break; - default: - break; - } - builder.addParameter( PARAMETER_KEY, keyValue ); - } - if ( getRemoteHttpCacheAttributes().isIncludeRequestTypeasAsParameter() ) - { - builder.addParameter( PARAMETER_REQUEST_TYPE, - remoteCacheRequest.getRequestType().toString() ); - } - - builder.setEntity(new ByteArrayEntity( requestAsByteArray )); - HttpResponse httpResponse = doWebserviceCall( builder ); - byte[] response = EntityUtils.toByteArray( httpResponse.getEntity() ); - return response; - } - - /** - * Called before the execute call on the client. - *

- * @param requestBuilder http method request builder - * - * @throws IOException - */ - @Override - protected void preProcessWebserviceCall( RequestBuilder requestBuilder ) - throws IOException - { - // do nothing. Child can override. - } - - /** - * Called after the execute call on the client. - *

- * @param request http request - * @param httpState result of execution - * - * @throws IOException - */ - @Override - protected void postProcessWebserviceCall( HttpUriRequest request, HttpResponse httpState ) - throws IOException - { - // do nothing. Child can override. - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactory.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactory.java deleted file mode 100644 index 67d243e0b7e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactory.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory; -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.RemoteCacheNoWait; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient; -import org.apache.commons.jcs.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.utils.config.OptionConverter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which - * is a wrapper around a no wait. The no wait object is either an active connection to a remote - * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the - * clients. - */ -public class RemoteHttpCacheFactory - extends AbstractAuxiliaryCacheFactory -{ - /** The logger */ - private static final Log log = LogFactory.getLog( RemoteHttpCacheFactory.class ); - - /** Monitor thread instance */ - private RemoteHttpCacheMonitor monitor; - - /** - * For LOCAL clients we get a handle to all the failovers, but we do not register a listener - * with them. We create the RemoteCacheManager, but we do not get a cache. - *

- * The failover runner will get a cache from the manager. When the primary is restored it will - * tell the manager for the failover to deregister the listener. - *

- * @param iaca - * @param cacheMgr - * @param cacheEventLogger - * @param elementSerializer - * @return AuxiliaryCache - */ - @Override - public AuxiliaryCache createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr, - ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) - { - RemoteHttpCacheAttributes rca = (RemoteHttpCacheAttributes) iaca; - - // TODO, use the configured value. - rca.setRemoteType( RemoteType.LOCAL ); - - RemoteHttpClientListener listener = new RemoteHttpClientListener( rca, cacheMgr, elementSerializer ); - - IRemoteHttpCacheClient remoteService = createRemoteHttpCacheClientForAttributes(rca); - - IRemoteCacheClient remoteCacheClient = - new RemoteHttpCache( rca, remoteService, listener, monitor ); - remoteCacheClient.setCacheEventLogger( cacheEventLogger ); - remoteCacheClient.setElementSerializer( elementSerializer ); - - RemoteCacheNoWait remoteCacheNoWait = new RemoteCacheNoWait( remoteCacheClient ); - remoteCacheNoWait.setCacheEventLogger( cacheEventLogger ); - remoteCacheNoWait.setElementSerializer( elementSerializer ); - - return remoteCacheNoWait; - } - - /** - * This is an extension point. The manager and other classes will only create - * RemoteHttpCacheClient through this method. - - * @param cattr the cache configuration - * @return the client instance - */ - protected IRemoteHttpCacheClient createRemoteHttpCacheClientForAttributes(RemoteHttpCacheAttributes cattr) - { - IRemoteHttpCacheClient remoteService = OptionConverter.instantiateByClassName( cattr - .getRemoteHttpClientClassName(), null ); - - if ( remoteService == null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Creating the default client for " + cattr.getCacheName()); - } - remoteService = new RemoteHttpCacheClient( ); - } - - remoteService.initialize( cattr ); - return remoteService; - } - - /** - * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#initialize() - */ - @Override - public void initialize() - { - super.initialize(); - monitor = new RemoteHttpCacheMonitor(this); - monitor.setDaemon(true); - monitor.start(); - } - - /** - * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#dispose() - */ - @Override - public void dispose() - { - if (monitor != null) - { - monitor.notifyShutdown(); - try - { - monitor.join(5000); - } - catch (InterruptedException e) - { - // swallow - } - monitor = null; - } - - super.dispose(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java deleted file mode 100644 index feb121012ba..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.Serializable; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor; -import org.apache.commons.jcs.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient; -import org.apache.commons.jcs.engine.CacheStatus; - -/** - * Upon the notification of a connection error, the monitor changes to operate in a time driven - * mode. That is, it attempts to recover the connections on a periodic basis. When all failed - * connections are restored, it changes back to the failure driven mode. - */ -public class RemoteHttpCacheMonitor extends AbstractAuxiliaryCacheMonitor -{ - /** Set of remote caches to monitor. This are added on error, if not before. */ - private final ConcurrentHashMap, RemoteHttpCache> remoteHttpCaches; - - /** Factory instance */ - private RemoteHttpCacheFactory factory = null; - - /** - * Constructor for the RemoteCacheMonitor object - * - * @param factory the factory to set - */ - public RemoteHttpCacheMonitor(RemoteHttpCacheFactory factory) - { - super("JCS-RemoteHttpCacheMonitor"); - this.factory = factory; - this.remoteHttpCaches = new ConcurrentHashMap, RemoteHttpCache>(); - setIdlePeriod(3000L); - } - - /** - * Notifies the cache monitor that an error occurred, and kicks off the error recovery process. - *

- * @param remoteCache - */ - public void notifyError( RemoteHttpCache remoteCache ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Notified of an error. " + remoteCache ); - } - - remoteHttpCaches.put( remoteCache, remoteCache ); - notifyError(); - } - - /** - * Clean up all resources before shutdown - */ - @Override - protected void dispose() - { - this.remoteHttpCaches.clear(); - } - - // Avoid the use of any synchronization in the process of monitoring for - // performance reasons. - // If exception is thrown owing to synchronization, - // just skip the monitoring until the next round. - /** Main processing method for the RemoteHttpCacheMonitor object */ - @Override - protected void doWork() - { - // If no factory has been set, skip - if (factory == null) - { - return; - } - - // If any cache is in error, it strongly suggests all caches - // managed by the same RmicCacheManager instance are in error. So we fix - // them once and for all. - for (RemoteHttpCache remoteCache : this.remoteHttpCaches.values()) - { - try - { - if ( remoteCache.getStatus() == CacheStatus.ERROR ) - { - RemoteHttpCacheAttributes attributes = remoteCache.getRemoteHttpCacheAttributes(); - - IRemoteHttpCacheClient remoteService = - factory.createRemoteHttpCacheClientForAttributes( attributes ); - - if ( log.isInfoEnabled() ) - { - log.info( "Performing Alive check on service " + remoteService ); - } - // If we can't fix them, just skip and re-try in - // the next round. - if ( remoteService.isAlive() ) - { - remoteCache.fixCache( remoteService ); - } - else - { - allright.set(false); - } - break; - } - } - catch ( IOException ex ) - { - allright.set(false); - // Problem encountered in fixing the caches managed by a - // RemoteCacheManager instance. - // Soldier on to the next RemoteHttpCache. - log.error( ex ); - } - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpClientListener.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpClientListener.java deleted file mode 100644 index 4129724d3bc..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpClientListener.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.AbstractRemoteCacheListener; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; - -/** Does nothing */ -public class RemoteHttpClientListener - extends AbstractRemoteCacheListener -{ - /** - * Only need one since it does work for all regions, just reference by multiple region names. - *

- * The constructor exports this object, making it available to receive incoming calls. The - * callback port is anonymous unless a local port value was specified in the configuration. - *

- * @param irca cache configuration - * @param cacheMgr the cache hub - * @param elementSerializer a custom serializer - */ - public RemoteHttpClientListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer ) - { - super( irca, cacheMgr, elementSerializer ); - } - - /** Nothing */ - @Override - public void dispose() - { - // noop - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java b/src/org/apache/commons/jcs/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java deleted file mode 100644 index 9949b7ebf97..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.client.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.http.client.RemoteHttpCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; - -import java.io.IOException; - - -/** - * It's not entirely clear that this interface is needed. I simply wanted the initialization method. - * This could be added to the ICacheSerice method. - */ -public interface IRemoteHttpCacheClient - extends ICacheServiceNonLocal -{ - /** - * The provides an extension point. If you want to extend this and use a special dispatcher, - * here is the place to do it. - *

- * @param attributes - */ - void initialize( RemoteHttpCacheAttributes attributes ); - - /** - * Make and alive request. - *

- * @return true if we make a successful alive request. - * @throws IOException - */ - boolean isAlive() - throws IOException; -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/server/AbstractRemoteCacheService.java b/src/org/apache/commons/jcs/auxiliary/remote/http/server/AbstractRemoteCacheService.java deleted file mode 100644 index dca2e371a9c..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/server/AbstractRemoteCacheService.java +++ /dev/null @@ -1,603 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.Serializable; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.logging.CacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class contains common methods for remote cache services. Eventually I hope to extract out - * much of the RMI server to use this as well. I'm starting with the Http service. - */ -public abstract class AbstractRemoteCacheService - implements ICacheServiceNonLocal -{ - /** An optional event logger */ - private transient ICacheEventLogger cacheEventLogger; - - /** The central hub */ - private ICompositeCacheManager cacheManager; - - /** Name of the event log source. */ - private String eventLogSourceName = "AbstractRemoteCacheService"; - - /** Number of puts into the cache. */ - private int puts = 0; - - /** The interval at which we will log updates. */ - private final int logInterval = 100; - - /** log instance */ - private static final Log log = LogFactory.getLog( AbstractRemoteCacheService.class ); - - /** - * Creates the super with the needed items. - *

- * @param cacheManager - * @param cacheEventLogger - */ - public AbstractRemoteCacheService( ICompositeCacheManager cacheManager, ICacheEventLogger cacheEventLogger ) - { - this.cacheManager = cacheManager; - this.cacheEventLogger = cacheEventLogger; - } - - /** - * @param item - * @throws IOException - */ - @Override - public void update( ICacheElement item ) - throws IOException - { - update( item, 0 ); - } - - /** - * The internal processing is wrapped in event logging calls. - *

- * @param item - * @param requesterId - * @throws IOException - */ - @Override - public void update( ICacheElement item, long requesterId ) - throws IOException - { - ICacheEvent> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT ); - try - { - logUpdateInfo( item ); - - processUpdate( item, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * The internal processing is wrapped in event logging calls. - *

- * @param item - * @param requesterId - * @throws IOException - */ - abstract void processUpdate( ICacheElement item, long requesterId ) - throws IOException; - - /** - * Log some details. - *

- * @param item - */ - private void logUpdateInfo( ICacheElement item ) - { - if ( log.isInfoEnabled() ) - { - // not thread safe, but it doesn't have to be accurate - puts++; - if ( puts % logInterval == 0 ) - { - log.info( "puts = " + puts ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "In update, put [" + item.getKey() + "] in [" + item.getCacheName() + "]" ); - } - } - - /** - * Returns a cache value from the specified remote cache; or null if the cache or key does not - * exist. - *

- * @param cacheName - * @param key - * @return ICacheElement - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key ) - throws IOException - { - return this.get( cacheName, key, 0 ); - } - - /** - * Returns a cache bean from the specified cache; or null if the key does not exist. - *

- * Adding the requestor id, allows the cache to determine the source of the get. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key, long requesterId ) - throws IOException - { - ICacheElement element = null; - ICacheEvent cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT ); - try - { - element = processGet( cacheName, key, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - return element; - } - - /** - * Returns a cache bean from the specified cache; or null if the key does not exist. - *

- * Adding the requestor id, allows the cache to determine the source of the get. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement - * @throws IOException - */ - abstract ICacheElement processGet( String cacheName, K key, long requesterId ) - throws IOException; - - /** - * Gets all matching items. - *

- * @param cacheName - * @param pattern - * @return Map of keys and wrapped objects - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern ) - throws IOException - { - return getMatching( cacheName, pattern, 0 ); - } - - /** - * Retrieves all matching keys. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return Map of keys and wrapped objects - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, pattern, requesterId, - ICacheEventLogger.GETMATCHING_EVENT ); - try - { - return processGetMatching( cacheName, pattern, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Retrieves all matching keys. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return Map of keys and wrapped objects - * @throws IOException - */ - abstract Map> processGetMatching( String cacheName, String pattern, long requesterId ) - throws IOException; - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys ) - throws IOException - { - return this.getMultiple( cacheName, keys, 0 ); - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId, - ICacheEventLogger.GETMULTIPLE_EVENT ); - try - { - return processGetMultiple( cacheName, keys, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - abstract Map> processGetMultiple( String cacheName, Set keys, long requesterId ) - throws IOException; - - /** - * Return the keys in this cache. - *

- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet( String cacheName ) - { - return processGetKeySet( cacheName ); - } - - /** - * Gets the set of keys of objects currently in the cache. - *

- * @param cacheName - * @return Set - */ - public Set processGetKeySet( String cacheName ) - { - CompositeCache cache = getCacheManager().getCache( cacheName ); - - return cache.getKeySet(); - } - - /** - * Removes the given key from the specified remote cache. Defaults the listener id to 0. - *

- * @param cacheName - * @param key - * @throws IOException - */ - @Override - public void remove( String cacheName, K key ) - throws IOException - { - remove( cacheName, key, 0 ); - } - - /** - * Remove the key from the cache region and don't tell the source listener about it. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param key - * @param requesterId - * @throws IOException - */ - @Override - public void remove( String cacheName, K key, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT ); - try - { - processRemove( cacheName, key, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Remove the key from the cache region and don't tell the source listener about it. - *

- * @param cacheName - * @param key - * @param requesterId - * @throws IOException - */ - abstract void processRemove( String cacheName, K key, long requesterId ) - throws IOException; - - /** - * Remove all keys from the specified remote cache. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void removeAll( String cacheName ) - throws IOException - { - removeAll( cacheName, 0 ); - } - - /** - * Remove all keys from the specified remote cache. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - @Override - public void removeAll( String cacheName, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT ); - try - { - processRemoveAll( cacheName, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Remove all keys from the specified remote cache. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - abstract void processRemoveAll( String cacheName, long requesterId ) - throws IOException; - - /** - * Frees the specified remote cache. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void dispose( String cacheName ) - throws IOException - { - dispose( cacheName, 0 ); - } - - /** - * Frees the specified remote cache. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - public void dispose( String cacheName, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT ); - try - { - processDispose( cacheName, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * @param cacheName - * @param requesterId - * @throws IOException - */ - abstract void processDispose( String cacheName, long requesterId ) - throws IOException; - - /** - * Gets the stats attribute of the RemoteCacheServer object. - *

- * @return The stats value - * @throws IOException - */ - public String getStats() - throws IOException - { - return cacheManager.getStats(); - } - - /** - * Logs an event if an event logger is configured. - *

- * @param item - * @param requesterId - * @param eventName - * @return ICacheEvent - */ - protected ICacheEvent> createICacheEvent( ICacheElement item, long requesterId, String eventName ) - { - if ( cacheEventLogger == null ) - { - return new CacheEvent>(); - } - String ipAddress = getExtraInfoForRequesterId( requesterId ); - return cacheEventLogger.createICacheEvent( getEventLogSourceName(), item.getCacheName(), eventName, ipAddress, - item ); - } - - /** - * Logs an event if an event logger is configured. - *

- * @param cacheName - * @param key - * @param requesterId - * @param eventName - * @return ICacheEvent - */ - protected ICacheEvent createICacheEvent( String cacheName, T key, long requesterId, String eventName ) - { - if ( cacheEventLogger == null ) - { - return new CacheEvent(); - } - String ipAddress = getExtraInfoForRequesterId( requesterId ); - return cacheEventLogger.createICacheEvent( getEventLogSourceName(), cacheName, eventName, ipAddress, key ); - } - - /** - * Logs an event if an event logger is configured. - *

- * @param source - * @param eventName - * @param optionalDetails - */ - protected void logApplicationEvent( String source, String eventName, String optionalDetails ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails ); - } - } - - /** - * Logs an event if an event logger is configured. - *

- * @param cacheEvent - */ - protected void logICacheEvent( ICacheEvent cacheEvent ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logICacheEvent( cacheEvent ); - } - } - - /** - * Ip address for the client, if one is stored. - *

- * Protected for testing. - *

- * @param requesterId - * @return String - */ - protected abstract String getExtraInfoForRequesterId( long requesterId ); - - /** - * Allows it to be injected. - *

- * @param cacheEventLogger - */ - public void setCacheEventLogger( ICacheEventLogger cacheEventLogger ) - { - this.cacheEventLogger = cacheEventLogger; - } - - /** - * @param cacheManager the cacheManager to set - */ - protected void setCacheManager( ICompositeCacheManager cacheManager ) - { - this.cacheManager = cacheManager; - } - - /** - * @return the cacheManager - */ - protected ICompositeCacheManager getCacheManager() - { - return cacheManager; - } - - /** - * @param eventLogSourceName the eventLogSourceName to set - */ - protected void setEventLogSourceName( String eventLogSourceName ) - { - this.eventLogSourceName = eventLogSourceName; - } - - /** - * @return the eventLogSourceName - */ - protected String getEventLogSourceName() - { - return eventLogSourceName; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java deleted file mode 100644 index bbe025701f8..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes; - -/** - * Configuration for the RemoteHttpCacheServer. Most of these properties are used only by the - * service. - */ -public class RemoteHttpCacheServerAttributes - extends AbstractAuxiliaryCacheAttributes -{ - /** Don't change. */ - private static final long serialVersionUID = -3987239306108780496L; - - /** Can a cluster remote put to other remotes */ - private boolean localClusterConsistency = true; - - /** Can a cluster remote get from other remotes */ - private boolean allowClusterGet = true; - - /** - * Should cluster updates be propagated to the locals - *

- * @return The localClusterConsistency value - */ - public boolean isLocalClusterConsistency() - { - return localClusterConsistency; - } - - /** - * Should cluster updates be propagated to the locals - *

- * @param r The new localClusterConsistency value - */ - public void setLocalClusterConsistency( boolean r ) - { - this.localClusterConsistency = r; - } - - /** - * Should gets from non-cluster clients be allowed to get from other remote auxiliaries. - *

- * @return The localClusterConsistency value - */ - public boolean isAllowClusterGet() - { - return allowClusterGet; - } - - /** - * Should we try to get from other cluster servers if we don't find the items locally. - *

- * @param r The new localClusterConsistency value - */ - public void setAllowClusterGet( boolean r ) - { - allowClusterGet = r; - } - - /** - * @return String details - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nRemoteHttpCacheServiceAttributes" ); - buf.append( "\n cacheName = [" + this.getCacheName() + "]" ); - buf.append( "\n allowClusterGet = [" + this.isAllowClusterGet() + "]" ); - buf.append( "\n localClusterConsistency = [" + this.isLocalClusterConsistency() + "]" ); - buf.append( "\n eventQueueType = [" + this.getEventQueueType() + "]" ); - buf.append( "\n eventQueuePoolName = [" + this.getEventQueuePoolName() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheService.java b/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheService.java deleted file mode 100644 index f250e9186b6..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheService.java +++ /dev/null @@ -1,269 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; - -/** - * This does the work. It's called by the processor. The base class wraps the processing calls in - * event logs, if an event logger is present. - *

- * For now we assume that all clients are non-cluster clients. And listener notification is not - * supported. - */ -public class RemoteHttpCacheService - extends AbstractRemoteCacheService -{ - /** The name used in the event logs. */ - private static final String EVENT_LOG_SOURCE_NAME = "RemoteHttpCacheServer"; - - /** The configuration */ - private final RemoteHttpCacheServerAttributes remoteHttpCacheServerAttributes; - - /** - * Create a process with a cache manager. - *

- * @param cacheManager - * @param remoteHttpCacheServerAttributes - * @param cacheEventLogger - */ - public RemoteHttpCacheService( ICompositeCacheManager cacheManager, - RemoteHttpCacheServerAttributes remoteHttpCacheServerAttributes, - ICacheEventLogger cacheEventLogger ) - { - super( cacheManager, cacheEventLogger ); - setEventLogSourceName( EVENT_LOG_SOURCE_NAME ); - this.remoteHttpCacheServerAttributes = remoteHttpCacheServerAttributes; - } - - /** - * Processes a get request. - *

- * If isAllowClusterGet is enabled we will treat this as a normal request or non-remote origins. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement - * @throws IOException - */ - @Override - public ICacheElement processGet( String cacheName, K key, long requesterId ) - throws IOException - { - CompositeCache cache = getCacheManager().getCache( cacheName ); - - boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet(); - if ( keepLocal ) - { - return cache.localGet( key ); - } - else - { - return cache.get( key ); - } - } - - /** - * Processes a get request. - *

- * If isAllowClusterGet is enabled we will treat this as a normal request of non-remote - * origination. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return Map - * @throws IOException - */ - @Override - public Map> processGetMultiple( String cacheName, Set keys, long requesterId ) - throws IOException - { - CompositeCache cache = getCacheManager().getCache( cacheName ); - - boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet(); - if ( keepLocal ) - { - return cache.localGetMultiple( keys ); - } - else - { - return cache.getMultiple( keys ); - } - } - - /** - * Processes a get request. - *

- * If isAllowClusterGet is enabled we will treat this as a normal request of non-remote - * origination. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return Map - * @throws IOException - */ - @Override - public Map> processGetMatching( String cacheName, String pattern, long requesterId ) - throws IOException - { - CompositeCache cache = getCacheManager().getCache( cacheName ); - - boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet(); - if ( keepLocal ) - { - return cache.localGetMatching( pattern ); - } - else - { - return cache.getMatching( pattern ); - } - } - - /** - * Processes an update request. - *

- * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote - * origination. - *

- * @param item - * @param requesterId - * @throws IOException - */ - @Override - public void processUpdate( ICacheElement item, long requesterId ) - throws IOException - { - CompositeCache cache = getCacheManager().getCache( item.getCacheName() ); - - boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency(); - if ( keepLocal ) - { - cache.localUpdate( item ); - } - else - { - cache.update( item ); - } - } - - /** - * Processes a remove request. - *

- * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote - * origination. - *

- * @param cacheName - * @param key - * @param requesterId - * @throws IOException - */ - @Override - public void processRemove( String cacheName, K key, long requesterId ) - throws IOException - { - CompositeCache cache = getCacheManager().getCache( cacheName ); - - boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency(); - if ( keepLocal ) - { - cache.localRemove( key ); - } - else - { - cache.remove( key ); - } - } - - /** - * Processes a removeAll request. - *

- * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote - * origination. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - @Override - public void processRemoveAll( String cacheName, long requesterId ) - throws IOException - { - CompositeCache cache = getCacheManager().getCache( cacheName ); - - boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency(); - if ( keepLocal ) - { - cache.localRemoveAll(); - } - else - { - cache.removeAll(); - } - } - - /** - * Processes a shutdown request. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - @Override - public void processDispose( String cacheName, long requesterId ) - throws IOException - { - CompositeCache cache = getCacheManager().getCache( cacheName ); - cache.dispose(); - } - - /** - * This general method should be deprecated. - *

- * @throws IOException - */ - @Override - public void release() - throws IOException - { - //nothing. - } - - /** - * This is called by the event log. - *

- * @param requesterId - * @return requesterId + "" - */ - @Override - protected String getExtraInfoForRequesterId( long requesterId ) - { - return requesterId + ""; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServlet.java b/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServlet.java deleted file mode 100644 index 761efe97759..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServlet.java +++ /dev/null @@ -1,394 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.http.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator; -import org.apache.commons.jcs.auxiliary.remote.http.behavior.IRemoteHttpCacheConstants; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.control.CompositeCacheManager; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware; -import org.apache.commons.jcs.utils.config.PropertySetter; -import org.apache.commons.jcs.utils.serialization.StandardSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This servlet simply reads and writes objects. The requests are packaged in a general wrapper. The - * processor works on the wrapper object and returns a response wrapper. - */ -public class RemoteHttpCacheServlet - extends HttpServlet -{ - /** Don't change. */ - private static final long serialVersionUID = 8752849397531933346L; - - /** The Logger. */ - private static final Log log = LogFactory.getLog( RemoteHttpCacheServlet.class ); - - /** The cache manager */ - private static CompositeCacheManager cacheMgr; - - /** The service that does the work. */ - private static ICacheServiceNonLocal remoteCacheService; - - /** This needs to be standard, since the other side is standard */ - private final StandardSerializer serializer = new StandardSerializer(); - - /** Number of service calls. */ - private int serviceCalls = 0; - - /** The interval at which we will log the count. */ - private final int logInterval = 100; - - /** - * Initializes the cache. - *

- * This provides an easy extension point. Simply extend this servlet and override the init - * method to change the way the properties are loaded. - * @param config - * @throws ServletException - */ - @Override - public void init( ServletConfig config ) - throws ServletException - { - try - { - cacheMgr = CompositeCacheManager.getInstance(); - } - catch (CacheException e) - { - throw new ServletException(e); - } - - remoteCacheService = createRemoteHttpCacheService( cacheMgr ); - - super.init( config ); - } - - /** - * Read the request, call the processor, write the response. - *

- * @param request - * @param response - * @throws ServletException - * @throws IOException - */ - @Override - public void service( HttpServletRequest request, HttpServletResponse response ) - throws ServletException, IOException - { - incrementServiceCallCount(); - if ( log.isDebugEnabled() ) - { - log.debug( "Servicing a request. " + request ); - } - - RemoteCacheRequest remoteRequest = readRequest( request ); - RemoteCacheResponse cacheResponse = processRequest( remoteRequest ); - - writeResponse( response, cacheResponse ); - } - - /** - * Read the request from the input stream. - *

- * @param request - * @return RemoteHttpCacheRequest - */ - protected RemoteCacheRequest readRequest( HttpServletRequest request ) - { - RemoteCacheRequest remoteRequest = null; - try - { - InputStream inputStream = request.getInputStream(); - if ( log.isDebugEnabled() ) - { - log.debug( "After getting input stream and before reading it" ); - } - - remoteRequest = readRequestFromStream( inputStream ); - } - catch ( Exception e ) - { - log.error( "Could not get a RemoteHttpCacheRequest object from the input stream.", e ); - } - return remoteRequest; - } - - /** - * Reads the response from the stream and then closes it. - *

- * @param inputStream - * @return RemoteHttpCacheRequest - * @throws IOException - * @throws ClassNotFoundException - */ - protected RemoteCacheRequest readRequestFromStream( InputStream inputStream ) - throws IOException, ClassNotFoundException - { - ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( inputStream, null ); - - @SuppressWarnings("unchecked") // Need to cast from Object - RemoteCacheRequest remoteRequest - = (RemoteCacheRequest) ois.readObject(); - ois.close(); - return remoteRequest; - } - - /** - * Write the response to the output stream. - *

- * @param response - * @param cacheResponse - */ - protected void writeResponse( HttpServletResponse response, RemoteCacheResponse cacheResponse ) - { - try - { - response.setContentType( "application/octet-stream" ); - - byte[] responseAsByteAray = serializer.serialize( cacheResponse ); - response.setContentLength( responseAsByteAray.length ); - - OutputStream outputStream = response.getOutputStream(); - if ( log.isDebugEnabled() ) - { - log.debug( "Opened output stream. Response size: " + responseAsByteAray.length ); - } - // WRITE - outputStream.write( responseAsByteAray ); - outputStream.flush(); - outputStream.close(); - } - catch ( IOException e ) - { - log.error( "Problem writing response. " + cacheResponse, e ); - } - } - - /** - * Processes the request. It will call the appropriate method on the service - *

- * @param request - * @return RemoteHttpCacheResponse, never null - */ - protected RemoteCacheResponse processRequest( RemoteCacheRequest request ) - { - RemoteCacheResponse response = new RemoteCacheResponse(); - - if ( request == null ) - { - String message = "The request is null. Cannot process"; - log.warn( message ); - response.setSuccess( false ); - response.setErrorMessage( message ); - } - else - { - try - { - switch ( request.getRequestType() ) - { - case GET: - ICacheElement element = - remoteCacheService.get( request.getCacheName(), request.getKey(), request.getRequesterId() ); - response.setPayload(element); - break; - case GET_MULTIPLE: - Map> elementMap = - remoteCacheService.getMultiple( request.getCacheName(), request.getKeySet(), request.getRequesterId() ); - if ( elementMap != null ) - { - Map> map = new HashMap>(); - map.putAll(elementMap); - response.setPayload(map); - } - break; - case GET_MATCHING: - Map> elementMapMatching = - remoteCacheService.getMatching( request.getCacheName(), request.getPattern(), request.getRequesterId() ); - if ( elementMapMatching != null ) - { - Map> map = new HashMap>(); - map.putAll(elementMapMatching); - response.setPayload(map); - } - break; - case REMOVE: - remoteCacheService.remove( request.getCacheName(), request.getKey(), request.getRequesterId() ); - break; - case REMOVE_ALL: - remoteCacheService.removeAll( request.getCacheName(), request.getRequesterId() ); - break; - case UPDATE: - remoteCacheService.update( request.getCacheElement(), request.getRequesterId() ); - break; - case ALIVE_CHECK: - case DISPOSE: - response.setSuccess( true ); - // DO NOTHING - break; - case GET_KEYSET: - Set keys = remoteCacheService.getKeySet( request.getCacheName() ); - response.setPayload( keys ); - break; - default: - String message = "Unknown event type. Cannot process " + request; - log.warn( message ); - response.setSuccess( false ); - response.setErrorMessage( message ); - break; - } - } - catch ( IOException e ) - { - String message = "Problem processing request. " + request + " Error: " + e.getMessage(); - log.error( message, e ); - response.setSuccess( false ); - response.setErrorMessage( message ); - } - } - - return response; - } - - /** - * Configures the attributes and the event logger and constructs a service. - *

- * @param cacheManager - * @return RemoteHttpCacheService - */ - protected RemoteHttpCacheService createRemoteHttpCacheService( ICompositeCacheManager cacheManager ) - { - Properties props = cacheManager.getConfigurationProperties(); - ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props ); - RemoteHttpCacheServerAttributes attributes = configureRemoteHttpCacheServerAttributes( props ); - - RemoteHttpCacheService service = new RemoteHttpCacheService( cacheManager, attributes, cacheEventLogger ); - if ( log.isInfoEnabled() ) - { - log.info( "Created new RemoteHttpCacheService " + service ); - } - return service; - } - - /** - * Tries to get the event logger. - *

- * @param props - * @return ICacheEventLogger - */ - protected ICacheEventLogger configureCacheEventLogger( Properties props ) - { - ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator - .parseCacheEventLogger( props, IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_PREFIX ); - - return cacheEventLogger; - } - - /** - * Configure. - *

- * jcs.remotehttpcache.serverattributes.ATTRIBUTENAME=ATTRIBUTEVALUE - *

- * @param prop - * @return RemoteCacheServerAttributesconfigureRemoteCacheServerAttributes - */ - protected RemoteHttpCacheServerAttributes configureRemoteHttpCacheServerAttributes( Properties prop ) - { - RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes(); - - // configure automatically - PropertySetter.setProperties( rcsa, prop, - IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." ); - - return rcsa; - } - - /** - * @param rcs the remoteCacheService to set - */ - protected void setRemoteCacheService(ICacheServiceNonLocal rcs) - { - remoteCacheService = rcs; - } - - /** - * Log some details. - */ - private void incrementServiceCallCount() - { - // not thread safe, but it doesn't have to be accurate - serviceCalls++; - if ( log.isInfoEnabled() ) - { - if ( serviceCalls % logInterval == 0 ) - { - log.info( "serviceCalls = " + serviceCalls ); - } - } - } - - /** Release the cache manager. */ - @Override - public void destroy() - { - if ( log.isInfoEnabled() ) - { - log.info( "Servlet Destroyed, shutting down JCS." ); - } - - cacheMgr.shutDown(); - } - - /** - * Get servlet information - *

- * @return basic info - */ - @Override - public String getServletInfo() - { - return "RemoteHttpCacheServlet"; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/package.html b/src/org/apache/commons/jcs/auxiliary/remote/package.html deleted file mode 100644 index e002b4e0111..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - Root package for the remote auxiliary cache. - - diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java b/src/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java deleted file mode 100644 index fe82a3b1a2e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.rmi.Naming; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; - -import org.apache.commons.jcs.auxiliary.remote.RemoteUtils; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class tries to keep the registry alive. If if is able to create a registry, it will also - * rebind the remote cache server. - */ -public class RegistryKeepAliveRunner - implements Runnable -{ - /** The logger */ - private static final Log log = LogFactory.getLog( RegistryKeepAliveRunner.class ); - - /** The URL of the service to look for. */ - private String namingURL; - - /** the port on which to start the registry */ - private int registryPort; - - /** An optional event logger */ - private ICacheEventLogger cacheEventLogger; - - /** - * @param registryHost - Hostname of the registry - * @param registryPort - the port on which to start the registry - * @param serviceName - */ - public RegistryKeepAliveRunner( String registryHost, int registryPort, String serviceName ) - { - this.namingURL = RemoteUtils.getNamingURL(registryHost, registryPort, serviceName); - this.registryPort = registryPort; - } - - /** - * Tries to lookup the server. If unsuccessful it will rebind the server using the factory - * rebind method. - *

- */ - @Override - public void run() - { - checkAndRestoreIfNeeded(); - } - - /** - * Tries to lookup the server. If unsuccessful it will rebind the server using the factory - * rebind method. - */ - protected void checkAndRestoreIfNeeded() - { - if ( log.isDebugEnabled() ) - { - log.debug( "looking up server " + namingURL ); - } - try - { - Object obj = Naming.lookup( namingURL ); - - // Successful connection to the remote server. - String message = "RMI registry looks fine. Found [" + obj + "] in registry [" + namingURL + "]"; - if ( cacheEventLogger != null ) - { - cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "Naming.lookup", message ); - } - if ( log.isDebugEnabled() ) - { - log.debug( message ); - } - } - catch ( Exception ex ) - { - // Failed to connect to the remote server. - String message = "Problem finding server at [" + namingURL - + "]. Will attempt to start registry and rebind."; - log.error( message, ex ); - if ( cacheEventLogger != null ) - { - cacheEventLogger.logError( "RegistryKeepAliveRunner", "Naming.lookup", message + ":" + ex.getMessage() ); - } - createAndRegister( namingURL ); - } - } - - /** - * Creates the registry and registers the server. - *

- * @param registry - */ - protected void createAndRegister( String registry ) - { - createReqistry( registry ); - registerServer( registry ); - } - - /** - * Try to create the registry. Log errors - *

- * @param registry - */ - protected void createReqistry( String registry ) - { - Registry reg = RemoteUtils.createRegistry(registryPort); - - if ( cacheEventLogger != null ) - { - if (reg != null) - { - cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "createRegistry", - "Successfully created registry [" + registry + "]." ); - } - else - { - cacheEventLogger.logError( "RegistryKeepAliveRunner", "createRegistry", - "Could not start registry [" + registry + "]." ); - } - } - } - - /** - * Try to rebind the server. - *

- * @param registry - */ - protected void registerServer( String registry ) - { - try - { - // try to rebind anyway - RemoteCacheServerFactory.registerServer( registry, RemoteCacheServerFactory.getRemoteCacheServer() ); - String message = "Successfully rebound server to registry [" + registry + "]."; - if ( cacheEventLogger != null ) - { - cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "registerServer", message ); - } - if ( log.isInfoEnabled() ) - { - log.info( message ); - } - } - catch ( RemoteException e ) - { - String message = "Could not rebind server to registry [" + registry + "]."; - log.error( message, e ); - if ( cacheEventLogger != null ) - { - cacheEventLogger.logError( "RegistryKeepAliveRunner", "registerServer", message + ":" - + e.getMessage() ); - } - } - } - - /** - * Allows it to be injected. - *

- * @param cacheEventLogger - */ - public void setCacheEventLogger( ICacheEventLogger cacheEventLogger ) - { - this.cacheEventLogger = cacheEventLogger; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java b/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java deleted file mode 100644 index 507f109cacb..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java +++ /dev/null @@ -1,1727 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.Serializable; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.rmi.server.RMISocketFactory; -import java.rmi.server.UnicastRemoteObject; -import java.rmi.server.Unreferenced; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.IRemoteCacheServer; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType; -import org.apache.commons.jcs.engine.CacheEventQueueFactory; -import org.apache.commons.jcs.engine.CacheListeners; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.CompositeCacheManager; -import org.apache.commons.jcs.engine.logging.CacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class provides remote cache services. The remote cache server propagates events from local - * caches to other local caches. It can also store cached data, making it available to new clients. - *

- * Remote cache servers can be clustered. If the cache used by this remote cache is configured to - * use a remote cache of type cluster, the two remote caches will communicate with each other. - * Remote and put requests can be sent from one remote to another. If they are configured to - * broadcast such event to their client, then remove an puts can be sent to all locals in the - * cluster. - *

- * Get requests are made between clustered servers if AllowClusterGet is true. You can setup several - * clients to use one remote server and several to use another. The get local will be distributed - * between the two servers. Since caches are usually high get and low put, this should allow you to - * scale. - */ -public class RemoteCacheServer - extends UnicastRemoteObject - implements IRemoteCacheServer, Unreferenced -{ - public static final String DFEAULT_REMOTE_CONFIGURATION_FILE = "/remote.cache.ccf"; - - /** For serialization. Don't change. */ - private static final long serialVersionUID = -8072345435941473116L; - - /** log instance */ - private static final Log log = LogFactory.getLog( RemoteCacheServer.class ); - - /** timing -- if we should record operation times. */ - private static final boolean timing = true; - - /** Number of puts into the cache. */ - private int puts = 0; - - /** Maps cache name to CacheListeners object. association of listeners (regions). */ - private final transient ConcurrentMap> cacheListenersMap = - new ConcurrentHashMap>(); - - /** maps cluster listeners to regions. */ - private final transient ConcurrentMap> clusterListenersMap = - new ConcurrentHashMap>(); - - /** The central hub */ - private transient CompositeCacheManager cacheManager; - - /** relates listener id with a type */ - private final ConcurrentMap idTypeMap = new ConcurrentHashMap(); - - /** relates listener id with an ip address */ - private final ConcurrentMap idIPMap = new ConcurrentHashMap(); - - /** Used to get the next listener id. */ - private final int[] listenerId = new int[1]; - - /** Configuration settings. */ - // package protected for access by unit test code - final IRemoteCacheServerAttributes remoteCacheServerAttributes; - - /** The interval at which we will log updates. */ - private final int logInterval = 100; - - /** An optional event logger */ - private transient ICacheEventLogger cacheEventLogger; - - /** Lock for Cache listener initialization */ - private ReentrantLock cacheListenersLock = new ReentrantLock(); - - /** Lock for Cluster listener initialization */ - private ReentrantLock clusterListenersLock = new ReentrantLock(); - - /** - * Constructor for the RemoteCacheServer object. This initializes the server with the values - * from the properties object. - *

- * @param rcsa - * @param config cache hub configuration - * @throws RemoteException - */ - protected RemoteCacheServer( IRemoteCacheServerAttributes rcsa, Properties config ) - throws RemoteException - { - super( rcsa.getServicePort() ); - this.remoteCacheServerAttributes = rcsa; - init( config ); - } - - /** - * Constructor for the RemoteCacheServer object. This initializes the server with the values - * from the properties object. - *

- * @param rcsa - * @param config cache hub configuration - * @param customRMISocketFactory - * @throws RemoteException - */ - protected RemoteCacheServer( IRemoteCacheServerAttributes rcsa, Properties config, RMISocketFactory customRMISocketFactory ) - throws RemoteException - { - super( rcsa.getServicePort(), customRMISocketFactory, customRMISocketFactory ); - this.remoteCacheServerAttributes = rcsa; - init( config ); - } - - /** - * Initialize the RMI Cache Server from a properties object. - *

- * @param prop the configuration properties - * @throws RemoteException if the configuration of the cache manager instance fails - */ - private void init( Properties prop ) throws RemoteException - { - try - { - cacheManager = createCacheManager( prop ); - } - catch (CacheException e) - { - throw new RemoteException(e.getMessage(), e); - } - - // cacheManager would have created a number of ICache objects. - // Use these objects to set up the cacheListenersMap. - String[] list = cacheManager.getCacheNames(); - for ( int i = 0; i < list.length; i++ ) - { - String name = list[i]; - CompositeCache cache = cacheManager.getCache( name ); - cacheListenersMap.put( name, new CacheListeners( cache ) ); - } - } - - /** - * Subclass can override this method to create the specific cache manager. - *

- * @param prop the configuration object. - * @return The cache hub configured with this configuration. - * - * @throws CacheException if the configuration cannot be loaded - */ - private CompositeCacheManager createCacheManager( Properties prop ) throws CacheException - { - CompositeCacheManager hub = CompositeCacheManager.getUnconfiguredInstance(); - hub.configure( prop ); - return hub; - } - - /** - * Puts a cache bean to the remote cache and notifies all listeners which
- *

    - *
  1. have a different listener id than the originating host;
  2. - *
  3. are currently subscribed to the related cache.
  4. - *
- *

- * @param item - * @throws IOException - */ - public void put( ICacheElement item ) - throws IOException - { - update( item ); - } - - /** - * @param item - * @throws IOException - */ - @Override - public void update( ICacheElement item ) - throws IOException - { - update( item, 0 ); - } - - /** - * The internal processing is wrapped in event logging calls. - *

- * @param item - * @param requesterId - * @throws IOException - */ - @Override - public void update( ICacheElement item, long requesterId ) - throws IOException - { - ICacheEvent> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT ); - try - { - processUpdate( item, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * An update can come from either a local cache's remote auxiliary, or it can come from a remote - * server. A remote server is considered a a source of type cluster. - *

- * If the update came from a cluster, then we should tell the cache manager that this was a - * remote put. This way, any lateral and remote auxiliaries configured for the region will not - * be updated. This is basically how a remote listener works when plugged into a local cache. - *

- * If the cluster is configured to keep local cluster consistency, then all listeners will be - * updated. This allows cluster server A to update cluster server B and then B to update its - * clients if it is told to keep local cluster consistency. Otherwise, server A will update - * server B and B will not tell its clients. If you cluster using lateral caches for instance, - * this is how it will work. Updates to a cluster node, will never get to the leaves. The remote - * cluster, with local cluster consistency, allows you to update leaves. This basically allows - * you to have a failover remote server. - *

- * Since currently a cluster will not try to get from other cluster servers, you can scale a bit - * with a cluster configuration. Puts and removes will be broadcasted to all clients, but the - * get load on a remote server can be reduced. - *

- * @param item - * @param requesterId - */ - private void processUpdate( ICacheElement item, long requesterId ) - { - long start = 0; - if ( timing ) - { - start = System.currentTimeMillis(); - } - - logUpdateInfo( item ); - - try - { - CacheListeners cacheDesc = getCacheListeners( item.getCacheName() ); - /* Object val = */item.getVal(); - - boolean fromCluster = isRequestFromCluster( requesterId ); - - if ( log.isDebugEnabled() ) - { - log.debug( "In update, requesterId = [" + requesterId + "] fromCluster = " + fromCluster ); - } - - // ordered cache item update and notification. - synchronized ( cacheDesc ) - { - try - { - CompositeCache c = (CompositeCache) cacheDesc.cache; - - // If the source of this request was not from a cluster, - // then consider it a local update. The cache manager will - // try to - // update all auxiliaries. - // - // This requires that two local caches not be connected to - // two clustered remote caches. The failover runner will - // have to make sure of this. ALos, the local cache needs - // avoid updating this source. Will need to pass the source - // id somehow. The remote cache should update all local - // caches - // but not update the cluster source. Cluster remote caches - // should only be updated by the server and not the - // RemoteCache. - if ( fromCluster ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Put FROM cluster, NOT updating other auxiliaries for region. " - + " requesterId [" + requesterId + "]" ); - } - c.localUpdate( item ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Put NOT from cluster, updating other auxiliaries for region. " - + " requesterId [" + requesterId + "]" ); - } - c.update( item ); - } - } - catch ( Exception ce ) - { - // swallow - if ( log.isInfoEnabled() ) - { - log.info( "Exception caught updating item. requesterId [" + requesterId + "] " - + ce.getMessage() ); - } - } - - // UPDATE LOCALS IF A REQUEST COMES FROM A CLUSTER - // IF LOCAL CLUSTER CONSISTENCY IS CONFIGURED - if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) ) - { - ICacheEventQueue[] qlist = getEventQList( cacheDesc, requesterId ); - if ( log.isDebugEnabled() ) - { - log.debug( "qlist.length = " + qlist.length ); - } - for ( int i = 0; i < qlist.length; i++ ) - { - qlist[i].addPutEvent( item ); - } - } - } - } - catch ( IOException e ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logError( "RemoteCacheServer", ICacheEventLogger.UPDATE_EVENT, e.getMessage() - + " REGION: " + item.getCacheName() + " ITEM: " + item ); - } - - log.error( "Trouble in Update. requesterId [" + requesterId + "]", e ); - } - - // TODO use JAMON for timing - if ( timing ) - { - long end = System.currentTimeMillis(); - if ( log.isDebugEnabled() ) - { - log.debug( "put took " + String.valueOf( end - start ) + " ms." ); - } - } - } - - /** - * Log some details. - *

- * @param item - */ - private void logUpdateInfo( ICacheElement item ) - { - // not thread safe, but it doesn't have to be 100% accurate - puts++; - - if ( log.isInfoEnabled() ) - { - if ( puts % logInterval == 0 ) - { - log.info( "puts = " + puts ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "In update, put [" + item.getKey() + "] in [" + item.getCacheName() + "]" ); - } - } - - /** - * Returns a cache value from the specified remote cache; or null if the cache or key does not - * exist. - *

- * @param cacheName - * @param key - * @return ICacheElement - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key ) - throws IOException - { - return this.get( cacheName, key, 0 ); - } - - /** - * Returns a cache bean from the specified cache; or null if the key does not exist. - *

- * Adding the requestor id, allows the cache to determine the source of the get. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key, long requesterId ) - throws IOException - { - ICacheElement element = null; - ICacheEvent cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT ); - try - { - element = processGet( cacheName, key, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - return element; - } - - /** - * Returns a cache bean from the specified cache; or null if the key does not exist. - *

- * Adding the requester id, allows the cache to determine the source of the get. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement - */ - private ICacheElement processGet( String cacheName, K key, long requesterId ) - { - boolean fromCluster = isRequestFromCluster( requesterId ); - - if ( log.isDebugEnabled() ) - { - log.debug( "get [" + key + "] from cache [" + cacheName + "] requesterId = [" + requesterId - + "] fromCluster = " + fromCluster ); - } - - CacheListeners cacheDesc = null; - try - { - cacheDesc = getCacheListeners( cacheName ); - } - catch ( Exception e ) - { - log.error( "Problem getting listeners.", e ); - - if ( cacheEventLogger != null ) - { - cacheEventLogger.logError( "RemoteCacheServer", ICacheEventLogger.GET_EVENT, e.getMessage() + cacheName - + " KEY: " + key ); - } - } - - ICacheElement element = getFromCacheListeners( key, fromCluster, cacheDesc, null ); - return element; - } - - /** - * Gets the item from the associated cache listeners. - *

- * @param key - * @param fromCluster - * @param cacheDesc - * @param element - * @return ICacheElement - */ - private ICacheElement getFromCacheListeners( K key, boolean fromCluster, CacheListeners cacheDesc, - ICacheElement element ) - { - ICacheElement returnElement = element; - - if ( cacheDesc != null ) - { - CompositeCache c = (CompositeCache) cacheDesc.cache; - - // If we have a get come in from a client and we don't have the item - // locally, we will allow the cache to look in other non local sources, - // such as a remote cache or a lateral. - // - // Since remote servers never get from clients and clients never go - // remote from a remote call, this - // will not result in any loops. - // - // This is the only instance I can think of where we allow a remote get - // from a remote call. The purpose is to allow remote cache servers to - // talk to each other. If one goes down, you want it to be able to get - // data from those that were up when the failed server comes back o - // line. - - if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "NonLocalGet. fromCluster [" + fromCluster + "] AllowClusterGet [" - + this.remoteCacheServerAttributes.isAllowClusterGet() + "]" ); - } - returnElement = c.get( key ); - } - else - { - // Gets from cluster type remote will end up here. - // Gets from all clients will end up here if allow cluster get is - // false. - - if ( log.isDebugEnabled() ) - { - log.debug( "LocalGet. fromCluster [" + fromCluster + "] AllowClusterGet [" - + this.remoteCacheServerAttributes.isAllowClusterGet() + "]" ); - } - returnElement = c.localGet( key ); - } - } - - return returnElement; - } - - /** - * Gets all matching items. - *

- * @param cacheName - * @param pattern - * @return Map of keys and wrapped objects - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern ) - throws IOException - { - return getMatching( cacheName, pattern, 0 ); - } - - /** - * Retrieves all matching keys. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return Map of keys and wrapped objects - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, pattern, requesterId, - ICacheEventLogger.GETMATCHING_EVENT ); - try - { - return processGetMatching( cacheName, pattern, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Retrieves all matching keys. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return Map of keys and wrapped objects - */ - protected Map> processGetMatching( String cacheName, String pattern, long requesterId ) - { - boolean fromCluster = isRequestFromCluster( requesterId ); - - if ( log.isDebugEnabled() ) - { - log.debug( "getMatching [" + pattern + "] from cache [" + cacheName + "] requesterId = [" + requesterId - + "] fromCluster = " + fromCluster ); - } - - CacheListeners cacheDesc = null; - try - { - cacheDesc = getCacheListeners( cacheName ); - } - catch ( Exception e ) - { - log.error( "Problem getting listeners.", e ); - - if ( cacheEventLogger != null ) - { - cacheEventLogger.logError( "RemoteCacheServer", ICacheEventLogger.GETMATCHING_EVENT, e.getMessage() - + cacheName + " pattern: " + pattern ); - } - } - - return getMatchingFromCacheListeners( pattern, fromCluster, cacheDesc ); - } - - /** - * Gets the item from the associated cache listeners. - *

- * @param pattern - * @param fromCluster - * @param cacheDesc - * @return Map of keys to results - */ - private Map> getMatchingFromCacheListeners( String pattern, boolean fromCluster, CacheListeners cacheDesc ) - { - Map> elements = null; - if ( cacheDesc != null ) - { - CompositeCache c = (CompositeCache) cacheDesc.cache; - - // We always want to go remote and then merge the items. But this can lead to inconsistencies after - // failover recovery. Removed items may show up. There is no good way to prevent this. - // We should make it configurable. - - if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "NonLocalGetMatching. fromCluster [" + fromCluster + "] AllowClusterGet [" - + this.remoteCacheServerAttributes.isAllowClusterGet() + "]" ); - } - elements = c.getMatching( pattern ); - } - else - { - // Gets from cluster type remote will end up here. - // Gets from all clients will end up here if allow cluster get is - // false. - - if ( log.isDebugEnabled() ) - { - log.debug( "LocalGetMatching. fromCluster [" + fromCluster + "] AllowClusterGet [" - + this.remoteCacheServerAttributes.isAllowClusterGet() + "]" ); - } - elements = c.localGetMatching( pattern ); - } - } - return elements; - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys ) - throws IOException - { - return this.getMultiple( cacheName, keys, 0 ); - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( String cacheName, Set keys, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId, - ICacheEventLogger.GETMULTIPLE_EVENT ); - try - { - return processGetMultiple( cacheName, keys, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - */ - private Map> processGetMultiple( String cacheName, Set keys, long requesterId ) - { - boolean fromCluster = isRequestFromCluster( requesterId ); - - if ( log.isDebugEnabled() ) - { - log.debug( "getMultiple [" + keys + "] from cache [" + cacheName + "] requesterId = [" + requesterId - + "] fromCluster = " + fromCluster ); - } - - CacheListeners cacheDesc = getCacheListeners( cacheName ); - Map> elements = getMultipleFromCacheListeners( keys, null, fromCluster, cacheDesc ); - return elements; - } - - /** - * Since a non-receiving remote cache client will not register a listener, it will not have a - * listener id assigned from the server. As such the remote server cannot determine if it is a - * cluster or a normal client. It will assume that it is a normal client. - *

- * @param requesterId - * @return true is from a cluster. - */ - private boolean isRequestFromCluster( long requesterId ) - { - RemoteType remoteTypeL = idTypeMap.get( Long.valueOf( requesterId ) ); - return remoteTypeL == RemoteType.CLUSTER; - } - - /** - * Gets the items from the associated cache listeners. - *

- * @param keys - * @param elements - * @param fromCluster - * @param cacheDesc - * @return Map - */ - private Map> getMultipleFromCacheListeners( Set keys, Map> elements, boolean fromCluster, CacheListeners cacheDesc ) - { - Map> returnElements = elements; - - if ( cacheDesc != null ) - { - CompositeCache c = (CompositeCache) cacheDesc.cache; - - // If we have a getMultiple come in from a client and we don't have the item - // locally, we will allow the cache to look in other non local sources, - // such as a remote cache or a lateral. - // - // Since remote servers never get from clients and clients never go - // remote from a remote call, this - // will not result in any loops. - // - // This is the only instance I can think of where we allow a remote get - // from a remote call. The purpose is to allow remote cache servers to - // talk to each other. If one goes down, you want it to be able to get - // data from those that were up when the failed server comes back on - // line. - - if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "NonLocalGetMultiple. fromCluster [" + fromCluster + "] AllowClusterGet [" - + this.remoteCacheServerAttributes.isAllowClusterGet() + "]" ); - } - - returnElements = c.getMultiple( keys ); - } - else - { - // Gets from cluster type remote will end up here. - // Gets from all clients will end up here if allow cluster get is - // false. - - if ( log.isDebugEnabled() ) - { - log.debug( "LocalGetMultiple. fromCluster [" + fromCluster + "] AllowClusterGet [" - + this.remoteCacheServerAttributes.isAllowClusterGet() + "]" ); - } - - returnElements = c.localGetMultiple( keys ); - } - } - - return returnElements; - } - - /** - * Return the keys in the cache. - *

- * @param cacheName the name of the cache region - * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() - */ - @Override - public Set getKeySet(String cacheName) throws IOException - { - return processGetKeySet( cacheName ); - } - - /** - * Gets the set of keys of objects currently in the cache. - *

- * @param cacheName - * @return Set - */ - protected Set processGetKeySet( String cacheName ) - { - CacheListeners cacheDesc = null; - try - { - cacheDesc = getCacheListeners( cacheName ); - } - catch ( Exception e ) - { - log.error( "Problem getting listeners.", e ); - } - - if ( cacheDesc == null ) - { - return Collections.emptySet(); - } - - CompositeCache c = (CompositeCache) cacheDesc.cache; - return c.getKeySet(); - } - - /** - * Removes the given key from the specified remote cache. Defaults the listener id to 0. - *

- * @param cacheName - * @param key - * @throws IOException - */ - @Override - public void remove( String cacheName, K key ) - throws IOException - { - remove( cacheName, key, 0 ); - } - - /** - * Remove the key from the cache region and don't tell the source listener about it. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param key - * @param requesterId - * @throws IOException - */ - @Override - public void remove( String cacheName, K key, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT ); - try - { - processRemove( cacheName, key, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Remove the key from the cache region and don't tell the source listener about it. - *

- * @param cacheName - * @param key - * @param requesterId - * @throws IOException - */ - private void processRemove( String cacheName, K key, long requesterId ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "remove [" + key + "] from cache [" + cacheName + "]" ); - } - - CacheListeners cacheDesc = cacheListenersMap.get( cacheName ); - - boolean fromCluster = isRequestFromCluster( requesterId ); - - if ( cacheDesc != null ) - { - // best attempt to achieve ordered cache item removal and - // notification. - synchronized ( cacheDesc ) - { - boolean removeSuccess = false; - - // No need to notify if it was not cached. - CompositeCache c = (CompositeCache) cacheDesc.cache; - - if ( fromCluster ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Remove FROM cluster, NOT updating other auxiliaries for region" ); - } - removeSuccess = c.localRemove( key ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Remove NOT from cluster, updating other auxiliaries for region" ); - } - removeSuccess = c.remove( key ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "remove [" + key + "] from cache [" + cacheName + "] success (was it found) = " - + removeSuccess ); - } - - // UPDATE LOCALS IF A REQUEST COMES FROM A CLUSTER - // IF LOCAL CLUSTER CONSISTENCY IS CONFIGURED - if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) ) - { - ICacheEventQueue[] qlist = getEventQList( cacheDesc, requesterId ); - - for ( int i = 0; i < qlist.length; i++ ) - { - qlist[i].addRemoveEvent( key ); - } - } - } - } - } - - /** - * Remove all keys from the specified remote cache. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void removeAll( String cacheName ) - throws IOException - { - removeAll( cacheName, 0 ); - } - - /** - * Remove all keys from the specified remote cache. - *

- * The internal processing is wrapped in event logging calls. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - @Override - public void removeAll( String cacheName, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT ); - try - { - processRemoveAll( cacheName, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * Remove all keys from the specified remote cache. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - private void processRemoveAll( String cacheName, long requesterId ) - throws IOException - { - CacheListeners cacheDesc = cacheListenersMap.get( cacheName ); - - boolean fromCluster = isRequestFromCluster( requesterId ); - - if ( cacheDesc != null ) - { - // best attempt to achieve ordered cache item removal and - // notification. - synchronized ( cacheDesc ) - { - // No need to broadcast, or notify if it was not cached. - CompositeCache c = (CompositeCache) cacheDesc.cache; - - if ( fromCluster ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "RemoveALL FROM cluster, NOT updating other auxiliaries for region" ); - } - c.localRemoveAll(); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "RemoveALL NOT from cluster, updating other auxiliaries for region" ); - } - c.removeAll(); - } - - // update registered listeners - if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) ) - { - ICacheEventQueue[] qlist = getEventQList( cacheDesc, requesterId ); - - for ( int i = 0; i < qlist.length; i++ ) - { - qlist[i].addRemoveAllEvent(); - } - } - } - } - } - - /** - * How many put events have we received. - *

- * @return puts - */ - // Currently only intended for use by unit tests - int getPutCount() - { - return puts; - } - - /** - * Frees the specified remote cache. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void dispose( String cacheName ) - throws IOException - { - dispose( cacheName, 0 ); - } - - /** - * Frees the specified remote cache. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - public void dispose( String cacheName, long requesterId ) - throws IOException - { - ICacheEvent cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT ); - try - { - processDispose( cacheName, requesterId ); - } - finally - { - logICacheEvent( cacheEvent ); - } - } - - /** - * @param cacheName - * @param requesterId - * @throws IOException - */ - private void processDispose( String cacheName, long requesterId ) - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "Dispose request received from listener [" + requesterId + "]" ); - } - - CacheListeners cacheDesc = cacheListenersMap.get( cacheName ); - - // this is dangerous - if ( cacheDesc != null ) - { - // best attempt to achieve ordered free-cache-op and notification. - synchronized ( cacheDesc ) - { - ICacheEventQueue[] qlist = getEventQList( cacheDesc, requesterId ); - - for ( int i = 0; i < qlist.length; i++ ) - { - qlist[i].addDisposeEvent(); - } - cacheManager.freeCache( cacheName ); - } - } - } - - /** - * Frees all remote caches. - *

- * @throws IOException - */ - @Override - public void release() - throws IOException - { - for (CacheListeners cacheDesc : cacheListenersMap.values()) - { - ICacheEventQueue[] qlist = getEventQList( cacheDesc, 0 ); - - for ( int i = 0; i < qlist.length; i++ ) - { - qlist[i].addDisposeEvent(); - } - } - cacheManager.release(); - } - - /** - * Returns the cache listener for the specified cache. Creates the cache and the cache - * descriptor if they do not already exist. - *

- * @param cacheName - * @return The cacheListeners value - */ - protected CacheListeners getCacheListeners( String cacheName ) - { - CacheListeners cacheListeners = cacheListenersMap.get( cacheName ); - - if ( cacheListeners == null ) - { - cacheListenersLock.lock(); - - try - { - // double check - cacheListeners = cacheListenersMap.get( cacheName ); - if ( cacheListeners == null ) - { - CompositeCache cache = cacheManager.getCache( cacheName ); - cacheListeners = new CacheListeners( cache ); - cacheListenersMap.put( cacheName, cacheListeners ); - } - } - finally - { - cacheListenersLock.unlock(); - } - } - - return cacheListeners; - } - - /** - * Gets the clusterListeners attribute of the RemoteCacheServer object. - *

- * TODO may be able to remove this - * @param cacheName - * @return The clusterListeners value - */ - protected CacheListeners getClusterListeners( String cacheName ) - { - CacheListeners cacheListeners = clusterListenersMap.get( cacheName ); - - if ( cacheListeners == null ) - { - clusterListenersLock.lock(); - - try - { - cacheListeners = clusterListenersMap.get( cacheName ); - if ( cacheListeners == null ) - { - CompositeCache cache = cacheManager.getCache( cacheName ); - cacheListeners = new CacheListeners( cache ); - clusterListenersMap.put( cacheName, cacheListeners ); - } - } - finally - { - clusterListenersLock.unlock(); - } - } - - return cacheListeners; - } - - /** - * Gets the eventQList attribute of the RemoteCacheServer object. This returns the event queues - * stored in the cacheListeners object for a particular region, if the queue is not for this - * requester. - *

- * Basically, this makes sure that a request from a particular local cache, identified by its - * listener id, does not result in a call to that same listener. - *

- * @param cacheListeners - * @param requesterId - * @return The eventQList value - */ - @SuppressWarnings("unchecked") // No generic arrays in java - private ICacheEventQueue[] getEventQList( CacheListeners cacheListeners, long requesterId ) - { - ICacheEventQueue[] list = cacheListeners.eventQMap.values().toArray( new ICacheEventQueue[0] ); - int count = 0; - // Set those not qualified to null; Count those qualified. - for ( int i = 0; i < list.length; i++ ) - { - ICacheEventQueue q = list[i]; - if ( q.isWorking() && q.getListenerId() != requesterId ) - { - count++; - } - else - { - list[i] = null; - } - } - if ( count == list.length ) - { - // All qualified. - return list; - } - - // Returns only the qualified. - ICacheEventQueue[] qq = new ICacheEventQueue[count]; - count = 0; - for ( int i = 0; i < list.length; i++ ) - { - if ( list[i] != null ) - { - qq[count++] = list[i]; - } - } - return qq; - } - - /** - * Removes dead event queues. Should clean out deregistered listeners. - *

- * @param eventQMap - */ - private static void cleanupEventQMap( Map> eventQMap ) - { - synchronized ( eventQMap ) - { - for (Iterator>> itr = eventQMap.entrySet().iterator(); itr.hasNext(); ) - { - Map.Entry> e = itr.next(); - ICacheEventQueue q = e.getValue(); - - // this does not care if the q is alive (i.e. if - // there are active threads; it cares if the queue - // is working -- if it has not encountered errors - // above the failure threshold - if ( !q.isWorking() ) - { - itr.remove(); - log.warn( "Cache event queue " + q + " is not working and removed from cache server." ); - } - } - } - } - - /** - * Subscribes to the specified remote cache. - *

- * If the client id is 0, then the remote cache server will increment it's local count and - * assign an id to the client. - *

- * @param cacheName the specified remote cache. - * @param listener object to notify for cache changes. must be synchronized since there are - * remote calls involved. - * @throws IOException - */ - @Override - @SuppressWarnings("unchecked") // Need to cast to specific return type from getClusterListeners() - public void addCacheListener( String cacheName, ICacheListener listener ) - throws IOException - { - if ( cacheName == null || listener == null ) - { - throw new IllegalArgumentException( "cacheName and listener must not be null" ); - } - CacheListeners cacheListeners; - - IRemoteCacheListener ircl = (IRemoteCacheListener) listener; - - String listenerAddress = ircl.getLocalHostAddress(); - - RemoteType remoteType = ircl.getRemoteType(); - if ( remoteType == RemoteType.CLUSTER ) - { - log.debug( "adding cluster listener, listenerAddress [" + listenerAddress + "]" ); - cacheListeners = (CacheListeners)getClusterListeners( cacheName ); - } - else - { - log.debug( "adding normal listener, listenerAddress [" + listenerAddress + "]" ); - cacheListeners = (CacheListeners)getCacheListeners( cacheName ); - } - Map> eventQMap = cacheListeners.eventQMap; - cleanupEventQMap( eventQMap ); - - // synchronized ( listenerId ) - synchronized ( ICacheListener.class ) - { - long id = 0; - try - { - id = listener.getListenerId(); - // clients probably shouldn't do this. - if ( id == 0 ) - { - // must start at one so the next gets recognized - long listenerIdB = nextListenerId(); - if ( log.isDebugEnabled() ) - { - log.debug( "listener id=" + ( listenerIdB & 0xff ) + " addded for cache [" + cacheName - + "], listenerAddress [" + listenerAddress + "]" ); - } - listener.setListenerId( listenerIdB ); - id = listenerIdB; - - // in case it needs synchronization - String message = "Adding vm listener under new id = [" + listenerIdB + "], listenerAddress [" - + listenerAddress + "]"; - logApplicationEvent( "RemoteCacheServer", "addCacheListener", message ); - if ( log.isInfoEnabled() ) - { - log.info( message ); - } - } - else - { - String message = "Adding listener under existing id = [" + id + "], listenerAddress [" - + listenerAddress + "]"; - logApplicationEvent( "RemoteCacheServer", "addCacheListener", message ); - if ( log.isInfoEnabled() ) - { - log.info( message ); - } - // should confirm the the host is the same as we have on - // record, just in case a client has made a mistake. - } - - // relate the type to an id - this.idTypeMap.put( Long.valueOf( id ), remoteType); - if ( listenerAddress != null ) - { - this.idIPMap.put( Long.valueOf( id ), listenerAddress ); - } - } - catch ( IOException ioe ) - { - String message = "Problem setting listener id, listenerAddress [" + listenerAddress + "]"; - log.error( message, ioe ); - - if ( cacheEventLogger != null ) - { - cacheEventLogger.logError( "RemoteCacheServer", "addCacheListener", message + " - " - + ioe.getMessage() ); - } - } - - CacheEventQueueFactory fact = new CacheEventQueueFactory(); - ICacheEventQueue q = fact.createCacheEventQueue( listener, id, cacheName, remoteCacheServerAttributes - .getEventQueuePoolName(), remoteCacheServerAttributes.getEventQueueType() ); - - eventQMap.put(Long.valueOf(listener.getListenerId()), q); - - if ( log.isInfoEnabled() ) - { - log.info( cacheListeners ); - } - } - } - - /** - * Subscribes to all remote caches. - *

- * @param listener The feature to be added to the CacheListener attribute - * @throws IOException - */ - @Override - public void addCacheListener( ICacheListener listener ) - throws IOException - { - for (String cacheName : cacheListenersMap.keySet()) - { - addCacheListener( cacheName, listener ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Adding listener for cache [" + cacheName + "]" ); - } - } - } - - /** - * Unsubscribe this listener from this region. If the listener is registered, it will be removed - * from the event queue map list. - *

- * @param cacheName - * @param listener - * @throws IOException - */ - @Override - public void removeCacheListener( String cacheName, ICacheListener listener ) - throws IOException - { - removeCacheListener( cacheName, listener.getListenerId() ); - } - - /** - * Unsubscribe this listener from this region. If the listener is registered, it will be removed - * from the event queue map list. - *

- * @param cacheName - * @param listenerId - */ - public void removeCacheListener( String cacheName, long listenerId ) - { - String message = "Removing listener for cache region = [" + cacheName + "] and listenerId [" + listenerId + "]"; - logApplicationEvent( "RemoteCacheServer", "removeCacheListener", message ); - if ( log.isInfoEnabled() ) - { - log.info( message ); - } - - boolean isClusterListener = isRequestFromCluster( listenerId ); - - CacheListeners cacheDesc = null; - - if ( isClusterListener ) - { - cacheDesc = getClusterListeners( cacheName ); - } - else - { - cacheDesc = getCacheListeners( cacheName ); - } - Map> eventQMap = cacheDesc.eventQMap; - cleanupEventQMap( eventQMap ); - ICacheEventQueue q = eventQMap.remove( Long.valueOf( listenerId ) ); - - if ( q != null ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Found queue for cache region = [" + cacheName + "] and listenerId [" + listenerId + "]" ); - } - q.destroy(); - cleanupEventQMap( eventQMap ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Did not find queue for cache region = [" + cacheName + "] and listenerId [" + listenerId - + "]" ); - } - } - - // cleanup - idTypeMap.remove( Long.valueOf( listenerId ) ); - idIPMap.remove( Long.valueOf( listenerId ) ); - - if ( log.isInfoEnabled() ) - { - log.info( "After removing listener [" + listenerId + "] cache region " + cacheName + "'s listener size [" - + cacheDesc.eventQMap.size() + "]" ); - } - } - - /** - * Unsubscribes from all remote caches. - *

- * @param listener - * @throws IOException - */ - @Override - public void removeCacheListener( ICacheListener listener ) - throws IOException - { - for (String cacheName : cacheListenersMap.keySet()) - { - removeCacheListener( cacheName, listener ); - - if ( log.isInfoEnabled() ) - { - log.info( "Removing listener for cache [" + cacheName + "]" ); - } - } - } - - /** - * Shuts down the remote server. - *

- * @throws IOException - */ - @Override - public void shutdown() - throws IOException - { - shutdown("", Registry.REGISTRY_PORT); - } - - /** - * Shuts down a server at a particular host and port. Then it calls shutdown on the cache - * itself. - *

- * @param host - * @param port - * @throws IOException - */ - @Override - public void shutdown( String host, int port ) - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "Received shutdown request. Shutting down server." ); - } - - synchronized (listenerId) - { - for (String cacheName : cacheListenersMap.keySet()) - { - for (int i = 0; i <= listenerId[0]; i++) - { - removeCacheListener( cacheName, i ); - } - - if ( log.isInfoEnabled() ) - { - log.info( "Removing listener for cache [" + cacheName + "]" ); - } - } - - cacheListenersMap.clear(); - clusterListenersMap.clear(); - } - RemoteCacheServerFactory.shutdownImpl( host, port ); - this.cacheManager.shutDown(); - } - - /** - * Called by the RMI runtime sometime after the runtime determines that the reference list, the - * list of clients referencing the remote object, becomes empty. - */ - // TODO: test out the DGC. - @Override - public void unreferenced() - { - if ( log.isInfoEnabled() ) - { - log.info( "*** Server now unreferenced and subject to GC. ***" ); - } - } - - /** - * Returns the next generated listener id [0,255]. - *

- * @return the listener id of a client. This should be unique for this server. - */ - private long nextListenerId() - { - long id = 0; - if ( listenerId[0] == Integer.MAX_VALUE ) - { - synchronized ( listenerId ) - { - id = listenerId[0]; - listenerId[0] = 0; - // TODO: record & check if the generated id is currently being - // used by a valid listener. Currently if the id wraps after - // Long.MAX_VALUE, - // we just assume it won't collide with an existing listener who - // is live. - } - } - else - { - synchronized ( listenerId ) - { - id = ++listenerId[0]; - } - } - return id; - } - - /** - * Gets the stats attribute of the RemoteCacheServer object. - *

- * @return The stats value - * @throws IOException - */ - @Override - public String getStats() - throws IOException - { - return cacheManager.getStats(); - } - - /** - * Logs an event if an event logger is configured. - *

- * @param item - * @param requesterId - * @param eventName - * @return ICacheEvent - */ - private ICacheEvent> createICacheEvent( ICacheElement item, long requesterId, String eventName ) - { - if ( cacheEventLogger == null ) - { - return new CacheEvent>(); - } - String ipAddress = getExtraInfoForRequesterId( requesterId ); - return cacheEventLogger - .createICacheEvent( "RemoteCacheServer", item.getCacheName(), eventName, ipAddress, item ); - } - - /** - * Logs an event if an event logger is configured. - *

- * @param cacheName - * @param key - * @param requesterId - * @param eventName - * @return ICacheEvent - */ - private ICacheEvent createICacheEvent( String cacheName, T key, long requesterId, String eventName ) - { - if ( cacheEventLogger == null ) - { - return new CacheEvent(); - } - String ipAddress = getExtraInfoForRequesterId( requesterId ); - return cacheEventLogger.createICacheEvent( "RemoteCacheServer", cacheName, eventName, ipAddress, key ); - } - - /** - * Logs an event if an event logger is configured. - *

- * @param source - * @param eventName - * @param optionalDetails - */ - protected void logApplicationEvent( String source, String eventName, String optionalDetails ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails ); - } - } - - /** - * Logs an event if an event logger is configured. - *

- * @param cacheEvent - */ - protected void logICacheEvent( ICacheEvent cacheEvent ) - { - if ( cacheEventLogger != null ) - { - cacheEventLogger.logICacheEvent( cacheEvent ); - } - } - - /** - * Ip address for the client, if one is stored. - *

- * Protected for testing. - *

- * @param requesterId - * @return String - */ - protected String getExtraInfoForRequesterId( long requesterId ) - { - String ipAddress = idIPMap.get( Long.valueOf( requesterId ) ); - return ipAddress; - } - - /** - * Allows it to be injected. - *

- * @param cacheEventLogger - */ - public void setCacheEventLogger( ICacheEventLogger cacheEventLogger ) - { - this.cacheEventLogger = cacheEventLogger; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java deleted file mode 100644 index 351f5ac3113..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java +++ /dev/null @@ -1,211 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.CommonRemoteCacheAttributes; -import org.apache.commons.jcs.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes; - -/** - * These attributes are used to configure the remote cache server. - */ -public class RemoteCacheServerAttributes - extends CommonRemoteCacheAttributes - implements IRemoteCacheServerAttributes -{ - /** Don't change */ - private static final long serialVersionUID = -2741662082869155365L; - - /** port the server will listen to */ - private int servicePort = 0; - - /** Can a cluster remote get from other remotes */ - private boolean allowClusterGet = true; - - /** The config file, the initialization is multistage. Remote cache then composite cache. */ - private String configFileName = ""; - - /** Should we start the registry */ - private boolean DEFAULT_START_REGISTRY = true; - - /** Should we start the registry */ - private boolean startRegistry = DEFAULT_START_REGISTRY; - - /** Should we try to keep the registry alive */ - private boolean DEFAULT_USE_REGISTRY_KEEP_ALIVE = true; - - /** Should we try to keep the registry alive */ - private boolean useRegistryKeepAlive = DEFAULT_USE_REGISTRY_KEEP_ALIVE; - - /** The delay between runs */ - private long registryKeepAliveDelayMillis = 15 * 1000; - - /** Default constructor for the RemoteCacheAttributes object */ - public RemoteCacheServerAttributes() - { - super(); - } - - /** - * Gets the localPort attribute of the RemoteCacheAttributes object - *

- * @return The localPort value - */ - @Override - public int getServicePort() - { - return this.servicePort; - } - - /** - * Sets the localPort attribute of the RemoteCacheAttributes object - *

- * @param p The new localPort value - */ - @Override - public void setServicePort( int p ) - { - this.servicePort = p; - } - - /** - * Should gets from non-cluster clients be allowed to get from other remote auxiliaries. - *

- * @return The localClusterConsistency value - */ - @Override - public boolean isAllowClusterGet() - { - return allowClusterGet; - } - - /** - * Should we try to get from other cluster servers if we don't find the items locally. - *

- * @param r The new localClusterConsistency value - */ - @Override - public void setAllowClusterGet( boolean r ) - { - allowClusterGet = r; - } - - /** - * Gets the ConfigFileName attribute of the IRemoteCacheAttributes object - *

- * @return The clusterServers value - */ - @Override - public String getConfigFileName() - { - return configFileName; - } - - /** - * Sets the ConfigFileName attribute of the IRemoteCacheAttributes object - *

- * @param s The new clusterServers value - */ - @Override - public void setConfigFileName( String s ) - { - configFileName = s; - } - - /** - * Should we try to keep the registry alive - *

- * @param useRegistryKeepAlive the useRegistryKeepAlive to set - */ - @Override - public void setUseRegistryKeepAlive( boolean useRegistryKeepAlive ) - { - this.useRegistryKeepAlive = useRegistryKeepAlive; - } - - /** - * Should we start the registry - *

- * @param startRegistry the startRegistry to set - */ - @Override - public void setStartRegistry( boolean startRegistry ) - { - this.startRegistry = startRegistry; - } - - /** - * Should we start the registry - *

- * @return the startRegistry - */ - @Override - public boolean isStartRegistry() - { - return startRegistry; - } - - /** - * Should we try to keep the registry alive - *

- * @return the useRegistryKeepAlive - */ - @Override - public boolean isUseRegistryKeepAlive() - { - return useRegistryKeepAlive; - } - - /** - * @param registryKeepAliveDelayMillis the registryKeepAliveDelayMillis to set - */ - @Override - public void setRegistryKeepAliveDelayMillis( long registryKeepAliveDelayMillis ) - { - this.registryKeepAliveDelayMillis = registryKeepAliveDelayMillis; - } - - /** - * @return the registryKeepAliveDelayMillis - */ - @Override - public long getRegistryKeepAliveDelayMillis() - { - return registryKeepAliveDelayMillis; - } - - /** - * @return String details - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(super.toString()); - buf.append( "\n servicePort = [" + this.getServicePort() + "]" ); - buf.append( "\n allowClusterGet = [" + this.isAllowClusterGet() + "]" ); - buf.append( "\n configFileName = [" + this.getConfigFileName() + "]" ); - buf.append( "\n rmiSocketFactoryTimeoutMillis = [" + this.getRmiSocketFactoryTimeoutMillis() + "]" ); - buf.append( "\n startRegistry = [" + this.isStartRegistry() + "]" ); - buf.append( "\n useRegistryKeepAlive = [" + this.isUseRegistryKeepAlive() + "]" ); - buf.append( "\n registryKeepAliveDelayMillis = [" + this.getRegistryKeepAliveDelayMillis() + "]" ); - buf.append( "\n eventQueueType = [" + this.getEventQueueType() + "]" ); - buf.append( "\n eventQueuePoolName = [" + this.getEventQueuePoolName() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java b/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java deleted file mode 100644 index e0c616e53ba..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java +++ /dev/null @@ -1,509 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.Serializable; -import java.net.MalformedURLException; -import java.rmi.Naming; -import java.rmi.NotBoundException; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.rmi.server.RMISocketFactory; -import java.rmi.server.UnicastRemoteObject; -import java.util.Properties; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator; -import org.apache.commons.jcs.auxiliary.remote.RemoteUtils; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants; -import org.apache.commons.jcs.engine.behavior.ICacheServiceAdmin; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.utils.config.OptionConverter; -import org.apache.commons.jcs.utils.config.PropertySetter; -import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Provides remote cache services. This creates remote cache servers and can proxy command line - * requests to a running server. - */ -public class RemoteCacheServerFactory - implements IRemoteCacheConstants -{ - /** The logger */ - private static final Log log = LogFactory.getLog( RemoteCacheServerFactory.class ); - - /** The single instance of the RemoteCacheServer object. */ - private static RemoteCacheServer remoteCacheServer; - - /** The name of the service. */ - private static String serviceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL; - - /** Executes the registry keep alive. */ - private static ScheduledExecutorService keepAliveDaemon; - - /** A reference to the registry. */ - private static Registry registry = null; - - /** Constructor for the RemoteCacheServerFactory object. */ - private RemoteCacheServerFactory() - { - super(); - } - - /** - * This will allow you to get stats from the server, etc. Perhaps we should provide methods on - * the factory to do this instead. - *

- * A remote cache is either a local cache or a cluster cache. - *

- * @return Returns the remoteCacheServer. - */ - @SuppressWarnings("unchecked") // Need cast to specific RemoteCacheServer - public static RemoteCacheServer getRemoteCacheServer() - { - return (RemoteCacheServer)remoteCacheServer; - } - - // ///////////////////// Startup/shutdown methods. ////////////////// - /** - * Starts up the remote cache server on this JVM, and binds it to the registry on the given host - * and port. - *

- * A remote cache is either a local cache or a cluster cache. - *

- * @param host - * @param port - * @param props - * @throws IOException - */ - public static void startup( String host, int port, Properties props) - throws IOException - { - if ( remoteCacheServer != null ) - { - throw new IllegalArgumentException( "Server already started." ); - } - - synchronized ( RemoteCacheServer.class ) - { - if ( remoteCacheServer != null ) - { - return; - } - if ( host == null ) - { - host = ""; - } - - RemoteCacheServerAttributes rcsa = configureRemoteCacheServerAttributes(props); - - // These should come from the file! - rcsa.setRemoteLocation( host, port ); - if ( log.isInfoEnabled() ) - { - log.info( "Creating server with these attributes: " + rcsa ); - } - - setServiceName( rcsa.getRemoteServiceName() ); - - RMISocketFactory customRMISocketFactory = configureObjectSpecificCustomFactory( props ); - - RemoteUtils.configureGlobalCustomSocketFactory( rcsa.getRmiSocketFactoryTimeoutMillis() ); - - // CONFIGURE THE EVENT LOGGER - ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props ); - - // CREATE SERVER - if ( customRMISocketFactory != null ) - { - remoteCacheServer = new RemoteCacheServer( rcsa, props, customRMISocketFactory ); - } - else - { - remoteCacheServer = new RemoteCacheServer( rcsa, props ); - } - - remoteCacheServer.setCacheEventLogger( cacheEventLogger ); - - // START THE REGISTRY - if (rcsa.isStartRegistry()) - { - registry = RemoteUtils.createRegistry(port); - } - - // REGISTER THE SERVER - registerServer( RemoteUtils.getNamingURL(host, port, serviceName), remoteCacheServer ); - - // KEEP THE REGISTRY ALIVE - if ( rcsa.isUseRegistryKeepAlive() ) - { - if ( keepAliveDaemon == null ) - { - keepAliveDaemon = Executors.newScheduledThreadPool(1, - new DaemonThreadFactory("JCS-RemoteCacheServerFactory-")); - } - RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, serviceName ); - runner.setCacheEventLogger( cacheEventLogger ); - keepAliveDaemon.scheduleAtFixedRate(runner, 0, rcsa.getRegistryKeepAliveDelayMillis(), TimeUnit.MILLISECONDS); - } - } - } - - /** - * Tries to get the event logger by new and old config styles. - *

- * @param props - * @return ICacheEventLogger - */ - protected static ICacheEventLogger configureCacheEventLogger( Properties props ) - { - ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator - .parseCacheEventLogger( props, IRemoteCacheConstants.CACHE_SERVER_PREFIX ); - - // try the old way - if ( cacheEventLogger == null ) - { - cacheEventLogger = AuxiliaryCacheConfigurator.parseCacheEventLogger( props, - IRemoteCacheConstants.PROPERTY_PREFIX ); - } - return cacheEventLogger; - } - - /** - * This configures an object specific custom factory. This will be configured for just this - * object in the registry. This can be null. - *

- * @param props - * @return RMISocketFactory - */ - protected static RMISocketFactory configureObjectSpecificCustomFactory( Properties props ) - { - RMISocketFactory customRMISocketFactory = - OptionConverter.instantiateByKey( props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, null ); - - if ( customRMISocketFactory != null ) - { - PropertySetter.setProperties( customRMISocketFactory, props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX - + "." ); - if ( log.isInfoEnabled() ) - { - log.info( "Will use server specific custom socket factory. " + customRMISocketFactory ); - } - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "No server specific custom socket factory defined." ); - } - } - return customRMISocketFactory; - } - - /** - * Registers the server with the registry. I broke this off because we might want to have code - * that will restart a dead registry. It will need to rebind the server. - *

- * @param namingURL - * @param server - * @throws RemoteException - */ - protected static void registerServer( String namingURL, Remote server ) - throws RemoteException - { - if ( server == null ) - { - throw new RemoteException( "Cannot register the server until it is created." ); - } - - if ( log.isInfoEnabled() ) - { - log.info( "Binding server to " + namingURL ); - } - - try - { - Naming.rebind( namingURL, server ); - } - catch ( MalformedURLException ex ) - { - // impossible case. - throw new IllegalArgumentException( ex.getMessage() + "; url=" + namingURL ); - } - } - - /** - * Configure. - *

- * jcs.remotecache.serverattributes.ATTRIBUTENAME=ATTRIBUTEVALUE - *

- * @param prop - * @return RemoteCacheServerAttributesconfigureRemoteCacheServerAttributes - */ - protected static RemoteCacheServerAttributes configureRemoteCacheServerAttributes( Properties prop ) - { - RemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes(); - - // configure automatically - PropertySetter.setProperties( rcsa, prop, CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." ); - - configureManuallyIfValuesArePresent( prop, rcsa ); - - return rcsa; - } - - /** - * This looks for the old config values. - *

- * @param prop - * @param rcsa - */ - private static void configureManuallyIfValuesArePresent( Properties prop, RemoteCacheServerAttributes rcsa ) - { - // DEPRECATED CONFIG - String servicePortStr = prop.getProperty( REMOTE_CACHE_SERVICE_PORT ); - if ( servicePortStr != null ) - { - try - { - int servicePort = Integer.parseInt( servicePortStr ); - rcsa.setServicePort( servicePort ); - log.debug( "Remote cache service uses port number " + servicePort + "." ); - } - catch ( NumberFormatException ignore ) - { - log.debug( "Remote cache service port property " + REMOTE_CACHE_SERVICE_PORT - + " not specified. An anonymous port will be used." ); - } - } - - String socketTimeoutMillisStr = prop.getProperty( SOCKET_TIMEOUT_MILLIS ); - if ( socketTimeoutMillisStr != null ) - { - try - { - int rmiSocketFactoryTimeoutMillis = Integer.parseInt( socketTimeoutMillisStr ); - rcsa.setRmiSocketFactoryTimeoutMillis( rmiSocketFactoryTimeoutMillis ); - log.debug( "Remote cache socket timeout " + rmiSocketFactoryTimeoutMillis + "ms." ); - } - catch ( NumberFormatException ignore ) - { - log.debug( "Remote cache socket timeout property " + SOCKET_TIMEOUT_MILLIS - + " not specified. The default will be used." ); - } - } - - String lccStr = prop.getProperty( REMOTE_LOCAL_CLUSTER_CONSISTENCY ); - if ( lccStr != null ) - { - boolean lcc = Boolean.parseBoolean( lccStr ); - rcsa.setLocalClusterConsistency( lcc ); - } - - String acgStr = prop.getProperty( REMOTE_ALLOW_CLUSTER_GET ); - if ( acgStr != null ) - { - boolean acg = Boolean.parseBoolean( lccStr ); - rcsa.setAllowClusterGet( acg ); - } - - // Register the RemoteCacheServer remote object in the registry. - rcsa.setRemoteServiceName( prop.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim() ); - } - - /** - * Unbinds the remote server. - *

- * @param host - * @param port - * @throws IOException - */ - static void shutdownImpl( String host, int port ) - throws IOException - { - synchronized ( RemoteCacheServer.class ) - { - if ( remoteCacheServer == null ) - { - return; - } - log.info( "Unbinding host=" + host + ", port=" + port + ", serviceName=" + getServiceName() ); - try - { - Naming.unbind( RemoteUtils.getNamingURL(host, port, getServiceName()) ); - } - catch ( MalformedURLException ex ) - { - // impossible case. - throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port - + ", serviceName=" + getServiceName() ); - } - catch ( NotBoundException ex ) - { - // ignore. - } - remoteCacheServer.release(); - remoteCacheServer = null; - - // Shut down keepalive scheduler - if ( keepAliveDaemon != null ) - { - keepAliveDaemon.shutdownNow(); - keepAliveDaemon = null; - } - - // Try to release registry - if (registry != null) - { - UnicastRemoteObject.unexportObject(registry, true); - registry = null; - } - } - } - - /** - * Creates an local RMI registry on the default port, starts up the remote cache server, and - * binds it to the registry. - *

- * A remote cache is either a local cache or a cluster cache. - *

- * @param args The command line arguments - * @throws Exception - */ - public static void main( String[] args ) - throws Exception - { - Properties prop = args.length > 0 ? RemoteUtils.loadProps( args[args.length - 1] ) : new Properties(); - - int port; - try - { - port = Integer.parseInt( prop.getProperty( "registry.port" ) ); - } - catch ( NumberFormatException ex ) - { - port = Registry.REGISTRY_PORT; - } - - // shutdown - if ( args.length > 0 && args[0].toLowerCase().indexOf( "-shutdown" ) != -1 ) - { - try - { - ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port); - admin.shutdown(); - } - catch ( Exception ex ) - { - log.error( "Problem calling shutdown.", ex ); - } - log.debug( "done." ); - System.exit( 0 ); - } - - // STATS - if ( args.length > 0 && args[0].toLowerCase().indexOf( "-stats" ) != -1 ) - { - log.debug( "getting cache stats" ); - - try - { - ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port); - - try - { -// System.out.println( admin.getStats().toString() ); - log.debug( admin.getStats() ); - } - catch ( IOException es ) - { - log.error( es ); - } - } - catch ( Exception ex ) - { - log.error( "Problem getting stats.", ex ); - } - log.debug( "done." ); - System.exit( 0 ); - } - - // startup. - String host = prop.getProperty( "registry.host" ); - - if ( host == null || host.trim().equals( "" ) || host.trim().equals( "localhost" ) ) - { - log.debug( "main> creating registry on the localhost" ); - RemoteUtils.createRegistry( port ); - } - log.debug( "main> starting up RemoteCacheServer" ); - startup( host, port, prop); - log.debug( "main> done" ); - } - - /** - * Look up the remote cache service admin instance - * - * @param config the configuration properties - * @param port the local port - * @return the admin object instance - * - * @throws Exception if lookup fails - */ - private static ICacheServiceAdmin lookupCacheServiceAdmin(Properties config, int port) throws Exception - { - String remoteServiceName = config.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim(); - String registry = RemoteUtils.getNamingURL("", port, remoteServiceName); - - if ( log.isDebugEnabled() ) - { - log.debug( "looking up server " + registry ); - } - Object obj = Naming.lookup( registry ); - if ( log.isDebugEnabled() ) - { - log.debug( "server found" ); - } - - return (ICacheServiceAdmin) obj; - } - - /** - * @param serviceName the serviceName to set - */ - protected static void setServiceName( String serviceName ) - { - RemoteCacheServerFactory.serviceName = serviceName; - } - - /** - * @return the serviceName - */ - protected static String getServiceName() - { - return serviceName; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java b/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java deleted file mode 100644 index 59241f69e7f..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java +++ /dev/null @@ -1,291 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.OutputStream; -import java.net.UnknownHostException; -import java.util.Properties; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.auxiliary.remote.RemoteUtils; -import org.apache.commons.jcs.engine.control.CompositeCacheManager; -import org.apache.commons.jcs.utils.net.HostNameUtil; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This servlet can be used to startup the JCS remote cache. It is easy to - * deploy the remote server in a tomcat base. This give you an easy way to - * monitor its activity. - *

- * - * servlet> - <servlet-name>JCSRemoteCacheStartupServlet</servlet-name> - <servlet-class> - org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheStartupServlet - </servlet-class> - <load-on-startup>1</load-on-startup> - </servlet> - - - <servlet-mapping> - <servlet-name>JCSRemoteCacheStartupServlet</servlet-name> - <url-pattern>/jcs</url-pattern> - </servlet-mapping> - * - * - * @author Aaron Smuts - */ -public class RemoteCacheStartupServlet - extends HttpServlet -{ - /** Don't change */ - private static final long serialVersionUID = 1L; - - /** The logger */ - private static final Log log = LogFactory.getLog(RemoteCacheStartupServlet.class); - - /** The default port to start the registry on. */ - private static final int DEFAULT_REGISTRY_PORT = 1101; - - /** properties file name */ - private static final String DEFAULT_PROPS_FILE_NAME = "/cache.ccf"; - - /** properties file name, must set prior to calling get instance */ - private String propsFileName = DEFAULT_PROPS_FILE_NAME; - - /** Configuration properties */ - private int registryPort = DEFAULT_REGISTRY_PORT; - - /** Configuration properties */ - private String registryHost = null; - - /** - * Starts the registry and then tries to bind to it. - *

- * Gets the port from a props file. Uses the local host name for the - * registry host. Tries to start the registry, ignoring failure. Starts the - * server. - *

- * - * @throws ServletException - */ - @Override - public void init() - throws ServletException - { - super.init(); - - loadInitParams(); - Properties props = loadPropertiesFromFile(); - - if (registryHost == null) - { - // we will always use the local machine for the registry - try - { - registryHost = HostNameUtil.getLocalHostAddress(); - } - catch (UnknownHostException e) - { - log.error("Could not get local address to use for the registry!", e); - } - } - - if (log.isDebugEnabled()) - { - log.debug("registryHost = [" + registryHost + "]"); - } - - if ("localhost".equals(registryHost) || "127.0.0.1".equals(registryHost)) - { - log.warn("The local address [" + registryHost - + "] is INVALID. Other machines must be able to use the address to reach this server."); - } - - try - { - if (props == null) - { - throw new ServletException("Could not load configuration from " + propsFileName); - } - - RemoteCacheServerFactory.startup(registryHost, registryPort, props); - if (log.isInfoEnabled()) - { - log.info("Remote JCS Server started with properties from " + propsFileName); - } - } - catch (IOException e) - { - throw new ServletException("Problem starting remote cache server.", e); - } - } - - /** - * It just dumps the stats. - *

- * - * @param request - * @param response - * @throws ServletException - * @throws IOException - */ - @Override - protected void service(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException - { - String stats = ""; - - try - { - stats = CompositeCacheManager.getInstance().getStats(); - } - catch (CacheException e) - { - throw new ServletException(e); - } - - if (log.isInfoEnabled()) - { - log.info(stats); - } - - try - { - String characterEncoding = response.getCharacterEncoding(); - if (characterEncoding == null) - { - characterEncoding = "UTF-8"; - response.setCharacterEncoding(characterEncoding); - } - OutputStream os = response.getOutputStream(); - os.write(stats.getBytes(characterEncoding)); - os.close(); - } - catch (IOException e) - { - log.error("Problem writing response.", e); - } - } - - /** - * shuts the cache down. - */ - @Override - public void destroy() - { - super.destroy(); - - log.info("Shutting down remote cache "); - - try - { - RemoteCacheServerFactory.shutdownImpl(registryHost, registryPort); - } - catch (IOException e) - { - log.error("Problem shutting down.", e); - } - - try - { - CompositeCacheManager.getInstance().shutDown(); - } - catch (CacheException e) - { - log.error("Could not retrieve cache manager instance", e); - } - } - - /** - * Load configuration values from config file if possible - */ - private Properties loadPropertiesFromFile() - { - Properties props = null; - - try - { - props = RemoteUtils.loadProps(propsFileName); - if (props != null) - { - registryHost = props.getProperty("registry.host", registryHost); - String portS = props.getProperty("registry.port", String.valueOf(registryPort)); - setRegistryPort(portS); - } - } - catch (IOException e) - { - log.error("Problem loading props.", e); - } - - return props; - } - - /** - * Load configuration values from init params if possible - */ - private void loadInitParams() - { - ServletConfig config = getServletConfig(); - String _propsFileName = config.getInitParameter("propsFileName"); - if (null != _propsFileName) - { - this.propsFileName = _propsFileName; - } - String _registryHost = config.getInitParameter("registryHost"); - if (null != _registryHost) - { - this.registryHost = _registryHost; - } - String regPortString = config.getInitParameter("registryPort"); - if (null != regPortString) - { - setRegistryPort(regPortString); - } - } - - /** - * Set registry port from string If the string cannot be parsed, the default - * value is used - * - * @param portS - */ - private void setRegistryPort(String portS) - { - try - { - this.registryPort = Integer.parseInt(portS); - } - catch (NumberFormatException e) - { - log.error("Problem converting port to an int.", e); - this.registryPort = DEFAULT_REGISTRY_PORT; - } - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java b/src/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java deleted file mode 100644 index 7d1f31a0348..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.Serializable; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.rmi.server.RMISocketFactory; - -/** - * This can be injected into the the remote cache server as follows: - * - *

- * jcs.remotecache.customrmisocketfactory=org.apache.commons.jcs.auxiliary.remote.server.TimeoutConfigurableRMISocketFactory
- * jcs.remotecache.customrmisocketfactory.readTimeout=5000
- * jcs.remotecache.customrmisocketfactory.openTimeout=5000
- * 
- */ -public class TimeoutConfigurableRMISocketFactory - extends RMISocketFactory - implements Serializable -{ - /** Don't change. */ - private static final long serialVersionUID = 1489909775271203334L; - - /** The socket read timeout */ - private int readTimeout = 5000; - - /** The socket open timeout */ - private int openTimeout = 5000; - - /** - * @param port - * @return ServerSocket - * @throws IOException - */ - @Override - public ServerSocket createServerSocket( int port ) - throws IOException - { - return new ServerSocket( port ); - } - - /** - * @param host - * @param port - * @return Socket - * @throws IOException - */ - @Override - public Socket createSocket( String host, int port ) - throws IOException - { - Socket socket = new Socket(); - socket.setSoTimeout( readTimeout ); - socket.setSoLinger( false, 0 ); - socket.connect( new InetSocketAddress( host, port ), openTimeout ); - return socket; - } - - /** - * @param readTimeout the readTimeout to set - */ - public void setReadTimeout( int readTimeout ) - { - this.readTimeout = readTimeout; - } - - /** - * @return the readTimeout - */ - public int getReadTimeout() - { - return readTimeout; - } - - /** - * @param openTimeout the openTimeout to set - */ - public void setOpenTimeout( int openTimeout ) - { - this.openTimeout = openTimeout; - } - - /** - * @return the openTimeout - */ - public int getOpenTimeout() - { - return openTimeout; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServer.java b/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServer.java deleted file mode 100644 index 8799b5a7c4c..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServer.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server.behavior; - -import java.rmi.Remote; -import org.apache.commons.jcs.engine.behavior.ICacheObserver; -import org.apache.commons.jcs.engine.behavior.ICacheServiceAdmin; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Interface for managing Remote objects - * - * @author Thomas Vandahl - * - */ -public interface IRemoteCacheServer - extends ICacheServiceNonLocal, ICacheObserver, ICacheServiceAdmin, Remote -{ - // empty -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java b/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java deleted file mode 100644 index 1c8500df97e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.remote.behavior.ICommonRemoteCacheAttributes; - -/** - * This defines the minimal behavior for the objects that are used to configure - * the remote cache server. - */ -public interface IRemoteCacheServerAttributes - extends ICommonRemoteCacheAttributes -{ - /** - * Gets the localPort attribute of the IRemoteCacheAttributes object. - *

- * @return The localPort value - */ - int getServicePort(); - - /** - * Sets the localPort attribute of the IRemoteCacheAttributes object. - *

- * @param p - * The new localPort value - */ - void setServicePort( int p ); - - /** - * Should we try to get remotely when the request does not come in from a - * cluster. If local L1 asks remote server R1 for element A and R1 doesn't - * have it, should R1 look remotely? The difference is between a local and a - * remote update. The local update stays local. Normal updates, removes, - * etc, stay local when they come from a client. If this is set to true, - * then they can go remote. - *

- * @return The localClusterConsistency value - */ - boolean isAllowClusterGet(); - - /** - * Should cluster updates be propagated to the locals. - *

- * @param r - * The new localClusterConsistency value - */ - void setAllowClusterGet( boolean r ); - - /** - * Gets the ConfigFileName attribute of the IRemoteCacheAttributes object. - *

- * @return The configuration file name - */ - String getConfigFileName(); - - /** - * Sets the ConfigFileName attribute of the IRemoteCacheAttributes object. - *

- * @param s - * The new configuration file name - */ - void setConfigFileName( String s ); - - /** - * Should we try to keep the registry alive - *

- * @param useRegistryKeepAlive the useRegistryKeepAlive to set - */ - void setUseRegistryKeepAlive( boolean useRegistryKeepAlive ); - - /** - * Should we start the registry - *

- * @param startRegistry the startRegistry to set - */ - void setStartRegistry( boolean startRegistry ); - - /** - * Should we start the registry - *

- * @return the startRegistry - */ - boolean isStartRegistry(); - - /** - * Should we try to keep the registry alive - *

- * @return the useRegistryKeepAlive - */ - boolean isUseRegistryKeepAlive(); - - /** - * @param registryKeepAliveDelayMillis the registryKeepAliveDelayMillis to set - */ - void setRegistryKeepAliveDelayMillis( long registryKeepAliveDelayMillis ); - - /** - * @return the registryKeepAliveDelayMillis - */ - long getRegistryKeepAliveDelayMillis(); -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/RemoteType.java b/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/RemoteType.java deleted file mode 100644 index 31c7cbf3496..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/server/behavior/RemoteType.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.server.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Enum to describe the mode of the remote cache - */ -public enum RemoteType -{ - /** A remote cache is either a local cache or a cluster cache */ - LOCAL, - - /** A remote cache is either a local cache or a cluster cache */ - CLUSTER -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactory.java b/src/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactory.java deleted file mode 100644 index fc90ca9995e..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactory.java +++ /dev/null @@ -1,204 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.util; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Set; - -import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest; -import org.apache.commons.jcs.auxiliary.remote.value.RemoteRequestType; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This creates request objects. You could write your own client and use the objects from this - * factory. - */ -public class RemoteCacheRequestFactory -{ - /** The Logger. */ - private static final Log log = LogFactory.getLog( RemoteCacheRequestFactory.class ); - - /** - * Create generic request - * @param cacheName cache name - * @param requestType type of request - * @param requesterId id of requester - * @return the request - */ - private static RemoteCacheRequest createRequest(String cacheName, RemoteRequestType requestType, long requesterId) - { - RemoteCacheRequest request = new RemoteCacheRequest(); - request.setCacheName( cacheName ); - request.setRequestType( requestType ); - request.setRequesterId( requesterId ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Created: " + request ); - } - - return request; - } - - /** - * Creates a get Request. - *

- * @param cacheName - * @param key - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createGetRequest( String cacheName, K key, long requesterId ) - { - RemoteCacheRequest request = createRequest(cacheName, RemoteRequestType.GET, requesterId); - request.setKey( key ); - - return request; - } - - /** - * Creates a getMatching Request. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createGetMatchingRequest( String cacheName, String pattern, long requesterId ) - { - RemoteCacheRequest request = createRequest(cacheName, RemoteRequestType.GET_MATCHING, requesterId); - request.setPattern( pattern ); - - return request; - } - - /** - * Creates a getMultiple Request. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createGetMultipleRequest( String cacheName, Set keys, long requesterId ) - { - RemoteCacheRequest request = createRequest(cacheName, RemoteRequestType.GET_MULTIPLE, requesterId); - request.setKeySet(keys); - - return request; - } - - /** - * Creates a remove Request. - *

- * @param cacheName - * @param key - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createRemoveRequest( String cacheName, K key, long requesterId ) - { - RemoteCacheRequest request = createRequest(cacheName, RemoteRequestType.REMOVE, requesterId); - request.setKey( key ); - - return request; - } - - /** - * Creates a GetKeySet Request. - *

- * @param cacheName - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createGetKeySetRequest( String cacheName, long requesterId ) - { - RemoteCacheRequest request = createRequest(cacheName, RemoteRequestType.GET_KEYSET, requesterId); - request.setKey( cacheName ); - - return request; - } - - /** - * Creates a removeAll Request. - *

- * @param cacheName - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createRemoveAllRequest( String cacheName, long requesterId ) - { - RemoteCacheRequest request = createRequest(cacheName, RemoteRequestType.REMOVE_ALL, requesterId); - - return request; - } - - /** - * Creates a dispose Request. - *

- * @param cacheName - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createDisposeRequest( String cacheName, long requesterId ) - { - RemoteCacheRequest request = createRequest(cacheName, RemoteRequestType.DISPOSE, requesterId); - - return request; - } - - /** - * Creates an Update Request. - *

- * @param cacheElement - * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createUpdateRequest( ICacheElement cacheElement, long requesterId ) - { - RemoteCacheRequest request = createRequest(null, RemoteRequestType.UPDATE, requesterId); - if ( cacheElement != null ) - { - request.setCacheName( cacheElement.getCacheName() ); - request.setCacheElement( cacheElement ); - request.setKey( cacheElement.getKey() ); - } - else - { - log.error( "Can't create a proper update request for a null cache element." ); - } - - return request; - } - - /** - * Creates an alive check Request. - *

- * @param requesterId - * @return RemoteHttpCacheRequest - */ - public static RemoteCacheRequest createAliveCheckRequest( long requesterId ) - { - RemoteCacheRequest request = createRequest(null, RemoteRequestType.ALIVE_CHECK, requesterId); - - return request; - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheRequest.java b/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheRequest.java deleted file mode 100644 index b99ef2da194..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheRequest.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.value; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; - -import java.io.Serializable; -import java.util.Set; - -/** - * The basic request wrapper. The different types of requests are differentiated by their types. - *

- * Rather than creating sub object types, I created on object that has values for all types of - * requests. - */ -public class RemoteCacheRequest - implements Serializable -{ - /** Don't change. */ - private static final long serialVersionUID = -8858447417390442569L; - - /** The request type specifies the type of request: get, put, remove, . . */ - private RemoteRequestType requestType = null; - - /** Used to identify the source. Same as listener id on the client side. */ - private long requesterId = 0; - - /** The name of the region */ - private String cacheName; - - /** The key, if this request has a key. */ - private K key; - - /** The keySet, if this request has a keySet. Only getMultiple requests. */ - private Set keySet; - - /** The pattern, if this request uses a pattern. Only getMatching requests. */ - private String pattern; - - /** The ICacheEleemnt, if this request contains a value. Only update requests will have this. */ - private ICacheElement cacheElement; - - /** - * @param requestType the requestType to set - */ - public void setRequestType( RemoteRequestType requestType ) - { - this.requestType = requestType; - } - - /** - * @return the requestType - */ - public RemoteRequestType getRequestType() - { - return requestType; - } - - /** - * @param cacheName the cacheName to set - */ - public void setCacheName( String cacheName ) - { - this.cacheName = cacheName; - } - - /** - * @return the cacheName - */ - public String getCacheName() - { - return cacheName; - } - - /** - * @param key the key to set - */ - public void setKey( K key ) - { - this.key = key; - } - - /** - * @return the key - */ - public K getKey() - { - return key; - } - - /** - * @param pattern the pattern to set - */ - public void setPattern( String pattern ) - { - this.pattern = pattern; - } - - /** - * @return the pattern - */ - public String getPattern() - { - return pattern; - } - - /** - * @param cacheElement the cacheElement to set - */ - public void setCacheElement( ICacheElement cacheElement ) - { - this.cacheElement = cacheElement; - } - - /** - * @return the cacheElement - */ - public ICacheElement getCacheElement() - { - return cacheElement; - } - - /** - * @param requesterId the requesterId to set - */ - public void setRequesterId( long requesterId ) - { - this.requesterId = requesterId; - } - - /** - * @return the requesterId - */ - public long getRequesterId() - { - return requesterId; - } - - /** - * @param keySet the keySet to set - */ - public void setKeySet( Set keySet ) - { - this.keySet = keySet; - } - - /** - * @return the keySet - */ - public Set getKeySet() - { - return keySet; - } - - /** @return string */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nRemoteHttpCacheRequest" ); - buf.append( "\n requesterId [" + getRequesterId() + "]" ); - buf.append( "\n requestType [" + getRequestType() + "]" ); - buf.append( "\n cacheName [" + getCacheName() + "]" ); - buf.append( "\n key [" + getKey() + "]" ); - buf.append( "\n keySet [" + getKeySet() + "]" ); - buf.append( "\n pattern [" + getPattern() + "]" ); - buf.append( "\n cacheElement [" + getCacheElement() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheResponse.java b/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheResponse.java deleted file mode 100644 index 8292a6ae964..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheResponse.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.value; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * This is the response wrapper. The servlet wraps all different type of responses in one of these - * objects. - */ -public class RemoteCacheResponse - implements Serializable -{ - /** Don't change. */ - private static final long serialVersionUID = -8858447417390442568L; - - /** Was the event processed without error */ - private boolean success = true; - - /** Simple error messaging */ - private String errorMessage; - - /** - * The payload. Typically a key / ICacheElement<K, V> map. A normal get will return a map with one - * record. - */ - private T payload; - - /** - * @param success the success to set - */ - public void setSuccess( boolean success ) - { - this.success = success; - } - - /** - * @return the success - */ - public boolean isSuccess() - { - return success; - } - - /** - * @param errorMessage the errorMessage to set - */ - public void setErrorMessage( String errorMessage ) - { - this.errorMessage = errorMessage; - } - - /** - * @return the errorMessage - */ - public String getErrorMessage() - { - return errorMessage; - } - - /** - * @param payload the payload to set - */ - public void setPayload( T payload ) - { - this.payload = payload; - } - - /** - * @return the payload - */ - public T getPayload() - { - return payload; - } - - /** @return string */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\nRemoteHttpCacheResponse" ); - buf.append( "\n success [" + isSuccess() + "]" ); - buf.append( "\n payload [" + getPayload() + "]" ); - buf.append( "\n errorMessage [" + getErrorMessage() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteRequestType.java b/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteRequestType.java deleted file mode 100644 index ea6d4e1f8dc..00000000000 --- a/src/org/apache/commons/jcs/auxiliary/remote/value/RemoteRequestType.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.apache.commons.jcs.auxiliary.remote.value; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * The different types of requests - */ -public enum RemoteRequestType -{ - /** Alive check request type. */ - ALIVE_CHECK, - - /** Get request type. */ - GET, - - /** Get Multiple request type. */ - GET_MULTIPLE, - - /** Get Matching request type. */ - GET_MATCHING, - - /** Update request type. */ - UPDATE, - - /** Remove request type. */ - REMOVE, - - /** Remove All request type. */ - REMOVE_ALL, - - /** Get keys request type. */ - GET_KEYSET, - - /** Dispose request type. */ - DISPOSE, -} diff --git a/src/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java b/src/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java deleted file mode 100644 index 55b0af810b0..00000000000 --- a/src/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java +++ /dev/null @@ -1,444 +0,0 @@ -package org.apache.commons.jcs.engine; - -import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * An abstract base class to the different implementations - */ -public abstract class AbstractCacheEventQueue - implements ICacheEventQueue -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( AbstractCacheEventQueue.class ); - - /** default */ - protected static final int DEFAULT_WAIT_TO_DIE_MILLIS = 10000; - - /** - * time to wait for an event before snuffing the background thread if the queue is empty. make - * configurable later - */ - private int waitToDieMillis = DEFAULT_WAIT_TO_DIE_MILLIS; - - /** - * When the events are pulled off the queue, then tell the listener to handle the specific event - * type. The work is done by the listener. - */ - private ICacheListener listener; - - /** Id of the listener registered with this queue */ - private long listenerId; - - /** The cache region name, if applicable. */ - private String cacheName; - - /** Maximum number of failures before we buy the farm. */ - private int maxFailure; - - /** in milliseconds */ - private int waitBeforeRetry; - - /** - * This means that the queue is functional. If we reached the max number of failures, the queue - * is marked as non functional and will never work again. - */ - private final AtomicBoolean working = new AtomicBoolean(true); - - /** - * Returns the time to wait for events before killing the background thread. - *

- * @return int - */ - public int getWaitToDieMillis() - { - return waitToDieMillis; - } - - /** - * Sets the time to wait for events before killing the background thread. - *

- * @param wtdm the ms for the q to sit idle. - */ - public void setWaitToDieMillis( int wtdm ) - { - waitToDieMillis = wtdm; - } - - /** - * Creates a brief string identifying the listener and the region. - *

- * @return String debugging info. - */ - @Override - public String toString() - { - return "CacheEventQueue [listenerId=" + listenerId + ", cacheName=" + cacheName + "]"; - } - - /** - * @return The listenerId value - */ - @Override - public long getListenerId() - { - return listenerId; - } - - /** - * @return the cacheName - */ - protected String getCacheName() - { - return cacheName; - } - - /** - * Initializes the queue. - *

- * @param listener - * @param listenerId - * @param cacheName - * @param maxFailure - * @param waitBeforeRetry - */ - protected void initialize( ICacheListener listener, long listenerId, String cacheName, int maxFailure, - int waitBeforeRetry) - { - if ( listener == null ) - { - throw new IllegalArgumentException( "listener must not be null" ); - } - - this.listener = listener; - this.listenerId = listenerId; - this.cacheName = cacheName; - this.maxFailure = maxFailure <= 0 ? 3 : maxFailure; - this.waitBeforeRetry = waitBeforeRetry <= 0 ? 500 : waitBeforeRetry; - - if ( log.isDebugEnabled() ) - { - log.debug( "Constructed: " + this ); - } - } - - /** - * This adds a put event to the queue. When it is processed, the element will be put to the - * listener. - *

- * @param ce The feature to be added to the PutEvent attribute - * @throws IOException - */ - @Override - public void addPutEvent( ICacheElement ce ) - { - put( new PutEvent( ce ) ); - } - - /** - * This adds a remove event to the queue. When processed the listener's remove method will be - * called for the key. - *

- * @param key The feature to be added to the RemoveEvent attribute - * @throws IOException - */ - @Override - public void addRemoveEvent( K key ) - { - put( new RemoveEvent( key ) ); - } - - /** - * This adds a remove all event to the queue. When it is processed, all elements will be removed - * from the cache. - */ - @Override - public void addRemoveAllEvent() - { - put( new RemoveAllEvent() ); - } - - /** - * This adds a dispose event to the queue. When it is processed, the cache is shut down - */ - @Override - public void addDisposeEvent() - { - put( new DisposeEvent() ); - } - - /** - * Adds an event to the queue. - *

- * @param event - */ - protected abstract void put( AbstractCacheEvent event ); - - - // /////////////////////////// Inner classes ///////////////////////////// - /** - * Retries before declaring failure. - *

- * @author asmuts - */ - protected abstract class AbstractCacheEvent implements Runnable - { - /** Number of failures encountered processing this event. */ - int failures = 0; - - /** - * Main processing method for the AbstractCacheEvent object - */ - @Override - @SuppressWarnings("synthetic-access") - public void run() - { - try - { - doRun(); - } - catch ( IOException e ) - { - if ( log.isWarnEnabled() ) - { - log.warn( e ); - } - if ( ++failures >= maxFailure ) - { - if ( log.isWarnEnabled() ) - { - log.warn( "Error while running event from Queue: " + this - + ". Dropping Event and marking Event Queue as non-functional." ); - } - destroy(); - return; - } - if ( log.isInfoEnabled() ) - { - log.info( "Error while running event from Queue: " + this + ". Retrying..." ); - } - try - { - Thread.sleep( waitBeforeRetry ); - run(); - } - catch ( InterruptedException ie ) - { - if ( log.isErrorEnabled() ) - { - log.warn( "Interrupted while sleeping for retry on event " + this + "." ); - } - destroy(); - } - } - } - - /** - * @throws IOException - */ - protected abstract void doRun() - throws IOException; - } - - /** - * An element should be put in the cache. - *

- * @author asmuts - */ - protected class PutEvent - extends AbstractCacheEvent - { - /** The element to put to the listener */ - private final ICacheElement ice; - - /** - * Constructor for the PutEvent object. - *

- * @param ice - */ - PutEvent( ICacheElement ice ) - { - this.ice = ice; - } - - /** - * Call put on the listener. - *

- * @throws IOException - */ - @Override - protected void doRun() - throws IOException - { - listener.handlePut( ice ); - } - - /** - * For debugging. - *

- * @return Info on the key and value. - */ - @Override - public String toString() - { - return new StringBuilder( "PutEvent for key: " ).append( ice.getKey() ).append( " value: " ) - .append( ice.getVal() ).toString(); - } - - } - - /** - * An element should be removed from the cache. - *

- * @author asmuts - */ - protected class RemoveEvent - extends AbstractCacheEvent - { - /** The key to remove from the listener */ - private final K key; - - /** - * Constructor for the RemoveEvent object - *

- * @param key - */ - RemoveEvent( K key ) - { - this.key = key; - } - - /** - * Call remove on the listener. - *

- * @throws IOException - */ - @Override - protected void doRun() - throws IOException - { - listener.handleRemove( cacheName, key ); - } - - /** - * For debugging. - *

- * @return Info on the key to remove. - */ - @Override - public String toString() - { - return new StringBuilder( "RemoveEvent for " ).append( key ).toString(); - } - - } - - /** - * All elements should be removed from the cache when this event is processed. - *

- * @author asmuts - */ - protected class RemoveAllEvent - extends AbstractCacheEvent - { - /** - * Call removeAll on the listener. - *

- * @throws IOException - */ - @Override - protected void doRun() - throws IOException - { - listener.handleRemoveAll( cacheName ); - } - - /** - * For debugging. - *

- * @return The name of the event. - */ - @Override - public String toString() - { - return "RemoveAllEvent"; - } - } - - /** - * The cache should be disposed when this event is processed. - *

- * @author asmuts - */ - protected class DisposeEvent - extends AbstractCacheEvent - { - /** - * Called when gets to the end of the queue - *

- * @throws IOException - */ - @Override - protected void doRun() - throws IOException - { - listener.handleDispose( cacheName ); - } - - /** - * For debugging. - *

- * @return The name of the event. - */ - @Override - public String toString() - { - return "DisposeEvent"; - } - } - - /** - * @return whether the queue is functional. - */ - @Override - public boolean isWorking() - { - return working.get(); - } - - /** - * This means that the queue is functional. If we reached the max number of failures, the queue - * is marked as non functional and will never work again. - *

- * @param b - */ - public void setWorking( boolean b ) - { - working.set(b); - } -} diff --git a/src/org/apache/commons/jcs/engine/CacheAdaptor.java b/src/org/apache/commons/jcs/engine/CacheAdaptor.java deleted file mode 100644 index 7554a317093..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheAdaptor.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.IOException; - -/** - * Used for Cache-to-Cache messaging purposes. These are used in the balking - * facades in the lateral and remote caches. - */ -public class CacheAdaptor - implements ICacheListener -{ - /** The logger */ - private static final Log log = LogFactory.getLog( CacheAdaptor.class ); - - /** The cache we are adapting. */ - private final ICache cache; - - /** The unique id of this listener. */ - private long listenerId = 0; - - /** - * Sets the listenerId attribute of the CacheAdaptor object - *

- * @param id - * The new listenerId value - * @throws IOException - */ - @Override - public void setListenerId( long id ) - throws IOException - { - this.listenerId = id; - log.debug( "listenerId = " + id ); - } - - /** - * Gets the listenerId attribute of the CacheAdaptor object - *

- * @return The listenerId value - * @throws IOException - */ - @Override - public long getListenerId() - throws IOException - { - return this.listenerId; - } - - /** - * Constructor for the CacheAdaptor object - *

- * @param cache - */ - public CacheAdaptor( ICache cache ) - { - this.cache = cache; - } - - /** - * Puts an item into the cache. - *

- * @param item - * @throws IOException - */ - @Override - public void handlePut( ICacheElement item ) - throws IOException - { - try - { - cache.update( item ); - } - catch ( Exception e ) - { - // swallow - } - } - - /** - * Removes an item. - *

- * @param cacheName - * @param key - * @throws IOException - */ - @Override - public void handleRemove( String cacheName, K key ) - throws IOException - { - cache.remove( key ); - } - - /** - * Clears the region. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void handleRemoveAll( String cacheName ) - throws IOException - { - cache.removeAll(); - } - - /** - * Shutdown call. - *

- * @param cacheName - * @throws IOException - */ - @Override - public void handleDispose( String cacheName ) - throws IOException - { - cache.dispose(); - } -} diff --git a/src/org/apache/commons/jcs/engine/CacheConstants.java b/src/org/apache/commons/jcs/engine/CacheConstants.java deleted file mode 100644 index 18ff42c7f64..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheConstants.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Constants used throughout the JCS cache engine - *

- * @version $Id: CacheConstants.java 1590887 2014-04-29 07:07:32Z olamy $ - */ -public interface CacheConstants -{ - /** This is the name of the config file that we will look for by default. */ - String DEFAULT_CONFIG = "/cache.ccf"; - - /** Delimiter of a cache name component. This is used for hierarchical deletion */ - String NAME_COMPONENT_DELIMITER = ":"; -} diff --git a/src/org/apache/commons/jcs/engine/CacheElement.java b/src/org/apache/commons/jcs/engine/CacheElement.java deleted file mode 100644 index 224b34d8732..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheElement.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; - -/** - * Generic element wrapper. Often stuffed inside another. - */ -public class CacheElement - implements ICacheElement -{ - /** Don't change */ - private static final long serialVersionUID = -6062305728297627263L; - - /** The name of the cache region. This is a namespace. */ - private final String cacheName; - - /** This is the cache key by which the value can be referenced. */ - private final K key; - - /** This is the cached value, reference by the key. */ - private final V val; - - /** - * These attributes hold information about the element and what it is - * allowed to do. - */ - private IElementAttributes attr; - - /** - * Constructor for the CacheElement object - *

- * @param cacheName - * @param key - * @param val - */ - public CacheElement( String cacheName, K key, V val ) - { - this.cacheName = cacheName; - this.key = key; - this.val = val; - } - - /** - * Constructor for the CacheElement object - *

- * @param cacheName - * @param key - * @param val - * @param attrArg - */ - public CacheElement( String cacheName, K key, V val, IElementAttributes attrArg ) - { - this(cacheName, key, val); - this.attr = attrArg; - } - - /** - * Gets the cacheName attribute of the CacheElement object - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return this.cacheName; - } - - /** - * Gets the key attribute of the CacheElement object - *

- * @return The key value - */ - @Override - public K getKey() - { - return this.key; - } - - /** - * Gets the val attribute of the CacheElement object - *

- * @return The val value - */ - @Override - public V getVal() - { - return this.val; - } - - /** - * Sets the attributes attribute of the CacheElement object - *

- * @param attr - * The new IElementAttributes value - */ - @Override - public void setElementAttributes( IElementAttributes attr ) - { - this.attr = attr; - } - - /** - * Gets the IElementAttributes attribute of the CacheElement object - *

- * @return The IElementAttributes value, never null - */ - @Override - public IElementAttributes getElementAttributes() - { - // create default attributes if they are null - // this shouldn't happen, but could if a corrupt - // object was sent over the wire. - if ( this.attr == null ) - { - this.attr = new ElementAttributes(); - } - return this.attr; - } - - /** - * @return a hash of the key only - */ - @Override - public int hashCode() - { - return key.hashCode(); - } - - /** - * For debugging only. - *

- * @return String representation - */ - @Override - public String toString() - { - return "[CacheElement: cacheName [" + cacheName + "], key [" + key + "], val [" + val + "], attr [" + attr - + "]"; - } -} diff --git a/src/org/apache/commons/jcs/engine/CacheElementSerialized.java b/src/org/apache/commons/jcs/engine/CacheElementSerialized.java deleted file mode 100644 index 8a3d253d116..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheElementSerialized.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; - -import java.util.Arrays; - -/** Either serialized value or the value should be null; */ -public class CacheElementSerialized - extends CacheElement - implements ICacheElementSerialized -{ - /** Don't change. */ - private static final long serialVersionUID = -7265084818647601874L; - - /** The serialized value. */ - private final byte[] serializedValue; - - /** - * Constructs a usable wrapper. - *

- * @param cacheNameArg - * @param keyArg - * @param serializedValueArg - * @param elementAttributesArg - */ - public CacheElementSerialized( String cacheNameArg, K keyArg, byte[] serializedValueArg, - IElementAttributes elementAttributesArg ) - { - super(cacheNameArg, keyArg, null, elementAttributesArg); - this.serializedValue = serializedValueArg; - } - - /** @return byte[] */ - @Override - public byte[] getSerializedValue() - { - return this.serializedValue; - } - - /** - * For debugging only. - *

- * @return debugging string. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n CacheElementSerialized: " ); - buf.append( "\n CacheName = [" + getCacheName() + "]" ); - buf.append( "\n Key = [" + getKey() + "]" ); - buf.append( "\n SerializedValue = " + Arrays.toString(getSerializedValue()) ); - buf.append( "\n ElementAttributes = " + getElementAttributes() ); - return buf.toString(); - } - -} diff --git a/src/org/apache/commons/jcs/engine/CacheEventQueue.java b/src/org/apache/commons/jcs/engine/CacheEventQueue.java deleted file mode 100644 index bf2758f49cf..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheEventQueue.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.jcs.utils.threadpool.PoolConfiguration; -import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy; -import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager; - -/** - * An event queue is used to propagate ordered cache events to one and only one target listener. - */ -public class CacheEventQueue - extends PooledCacheEventQueue -{ - /** The type of queue -- there are pooled and single */ - private static final QueueType queueType = QueueType.SINGLE; - - /** - * Constructs with the specified listener and the cache name. - *

- * @param listener - * @param listenerId - * @param cacheName - */ - public CacheEventQueue( ICacheListener listener, long listenerId, String cacheName ) - { - this( listener, listenerId, cacheName, 10, 500 ); - } - - /** - * Constructor for the CacheEventQueue object - *

- * @param listener - * @param listenerId - * @param cacheName - * @param maxFailure - * @param waitBeforeRetry - */ - public CacheEventQueue( ICacheListener listener, long listenerId, String cacheName, int maxFailure, - int waitBeforeRetry ) - { - super( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, null ); - } - - /** - * Initializes the queue. - *

- * @param listener - * @param listenerId - * @param cacheName - * @param maxFailure - * @param waitBeforeRetry - * @param threadPoolName - */ - @Override - protected void initialize( ICacheListener listener, long listenerId, String cacheName, int maxFailure, - int waitBeforeRetry, String threadPoolName ) - { - super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry); - - // create a default pool with one worker thread to mimic the SINGLE queue behavior - pool = ThreadPoolManager.getInstance().createPool( - new PoolConfiguration(false, 0, 1, 0, getWaitToDieMillis(), WhenBlockedPolicy.RUN, 0), - "CacheEventQueue.QProcessor-" + getCacheName()); - } - - /** - * What type of queue is this. - *

- * @return queueType - */ - @Override - public QueueType getQueueType() - { - return queueType; - } -} diff --git a/src/org/apache/commons/jcs/engine/CacheEventQueueFactory.java b/src/org/apache/commons/jcs/engine/CacheEventQueueFactory.java deleted file mode 100644 index 24b5dc25b66..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheEventQueueFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class hands out event Queues. This allows us to change the implementation more easily. You - * can confugure the cache to use a custom type. - *

- * @author aaronsm - */ -public class CacheEventQueueFactory -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( CacheEventQueueFactory.class ); - - /** - * The most commonly used factory method. - *

- * @param listener - * @param listenerId - * @param cacheName - * @param threadPoolName - * @param poolType - SINGLE, POOLED - * @return ICacheEventQueue - */ - public ICacheEventQueue createCacheEventQueue( ICacheListener listener, long listenerId, String cacheName, - String threadPoolName, ICacheEventQueue.QueueType poolType ) - { - return createCacheEventQueue( listener, listenerId, cacheName, 10, 500, threadPoolName, poolType ); - } - - /** - * Fully configured event queue. - *

- * @param listener - * @param listenerId - * @param cacheName - * @param maxFailure - * @param waitBeforeRetry - * @param threadPoolName null is OK, if not a pooled event queue this is ignored - * @param poolType single or pooled - * @return ICacheEventQueue - */ - public ICacheEventQueue createCacheEventQueue( ICacheListener listener, long listenerId, String cacheName, - int maxFailure, int waitBeforeRetry, String threadPoolName, - ICacheEventQueue.QueueType poolType ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "threadPoolName = [" + threadPoolName + "] poolType = " + poolType + " " ); - } - - ICacheEventQueue eventQueue = null; - if ( poolType == null || ICacheEventQueue.QueueType.SINGLE == poolType ) - { - eventQueue = new CacheEventQueue( listener, listenerId, cacheName, maxFailure, waitBeforeRetry ); - } - else if ( ICacheEventQueue.QueueType.POOLED == poolType ) - { - eventQueue = new PooledCacheEventQueue( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, - threadPoolName ); - } - - return eventQueue; - } -} diff --git a/src/org/apache/commons/jcs/engine/CacheGroup.java b/src/org/apache/commons/jcs/engine/CacheGroup.java deleted file mode 100644 index 0da5a6d969d..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheGroup.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.IElementAttributes; - -/** - * Holder for attributes specific to a group. The grouping functionality is on - * the way out. - */ -public class CacheGroup -{ - /** Element configuration. */ - private IElementAttributes attr; - - /** Constructor for the CacheGroup object */ - public CacheGroup() - { - super(); - } - - /** - * Sets the attributes attribute of the CacheGroup object - *

- * @param attr - * The new attributes value - */ - public void setElementAttributes( IElementAttributes attr ) - { - this.attr = attr; - } - - /** - * Gets the attrributes attribute of the CacheGroup object - *

- * @return The attrributes value - */ - public IElementAttributes getElementAttrributes() - { - return attr; - } -} diff --git a/src/org/apache/commons/jcs/engine/CacheInfo.java b/src/org/apache/commons/jcs/engine/CacheInfo.java deleted file mode 100644 index 6256d0eef2b..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheInfo.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.rmi.dgc.VMID; - -/** - * This is a static variable holder for the distribution auxiliaries that need something like a vmid. - */ -public final class CacheInfo -{ - /** shouldn't be instantiated */ - private CacheInfo() - { - super(); - } - - /** - * Used to identify a client, so we can run multiple clients off one host. - * Need since there is no way to identify a client other than by host in - * rmi. - *

- * TODO: may have some trouble in failover mode if the cache keeps its old - * id. We may need to reset this when moving into failover. - */ - private static final VMID vmid = new VMID(); - - /** By default this is the hashcode of the VMID */ - public static final long listenerId = vmid.hashCode(); -} diff --git a/src/org/apache/commons/jcs/engine/CacheListeners.java b/src/org/apache/commons/jcs/engine/CacheListeners.java deleted file mode 100644 index 601529f25b9..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheListeners.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; - -/** - * Used to associates a set of [cache listener to cache event queue] for a - * cache. - */ -public class CacheListeners -{ - /** The cache using the queue. */ - public final ICache cache; - - /** Map ICacheListener to ICacheEventQueue */ - public final ConcurrentMap> eventQMap = - new ConcurrentHashMap>(); - - /** - * Constructs with the given cache. - *

- * @param cache - */ - public CacheListeners( ICache cache ) - { - if ( cache == null ) - { - throw new IllegalArgumentException( "cache must not be null" ); - } - this.cache = cache; - } - - /** @return info on the listeners */ - @Override - public String toString() - { - StringBuilder buffer = new StringBuilder(); - buffer.append( "\n CacheListeners" ); - if ( cache != null ) - { - buffer.append( "\n Region = " + cache.getCacheName() ); - } - if ( eventQMap != null ) - { - buffer.append( "\n Event Queue Map " ); - buffer.append( "\n size = " + eventQMap.size() ); - Iterator>> it = eventQMap.entrySet().iterator(); - while ( it.hasNext() ) - { - buffer.append( "\n Entry: " + it.next() ); - } - } - else - { - buffer.append( "\n No Listeners. " ); - } - return buffer.toString(); - } -} diff --git a/src/org/apache/commons/jcs/engine/CacheStatus.java b/src/org/apache/commons/jcs/engine/CacheStatus.java deleted file mode 100644 index ab79e08e5db..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheStatus.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Cache statuses - *

- * @version $Id: CacheStatus.java 1590887 2014-04-29 07:07:32Z olamy $ - */ -public enum CacheStatus -{ - /** Cache alive status. */ - ALIVE, - - /** Cache disposed status. */ - DISPOSED, - - /** Cache in error. */ - ERROR -} diff --git a/src/org/apache/commons/jcs/engine/CacheWatchRepairable.java b/src/org/apache/commons/jcs/engine/CacheWatchRepairable.java deleted file mode 100644 index 51c5987a56c..00000000000 --- a/src/org/apache/commons/jcs/engine/CacheWatchRepairable.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.apache.commons.jcs.engine; - -import java.io.IOException; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArraySet; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.jcs.engine.behavior.ICacheObserver; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Intercepts the requests to the underlying ICacheObserver object so that the listeners can be - * recorded locally for remote connection recovery purposes. (Durable subscription like those in JMS - * is not implemented at this stage for it can be too expensive.) - */ -public class CacheWatchRepairable - implements ICacheObserver -{ - /** The logger */ - private static final Log log = LogFactory.getLog( CacheWatchRepairable.class ); - - /** the underlying ICacheObserver. */ - private ICacheObserver cacheWatch; - - /** Map of cache regions. */ - private final ConcurrentMap>> cacheMap = - new ConcurrentHashMap>>(); - - /** - * Replaces the underlying cache watch service and re-attaches all existing listeners to the new - * cache watch. - *

- * @param cacheWatch The new cacheWatch value - */ - public void setCacheWatch( ICacheObserver cacheWatch ) - { - this.cacheWatch = cacheWatch; - for (Map.Entry>> entry : cacheMap.entrySet()) - { - String cacheName = entry.getKey(); - for (ICacheListener listener : entry.getValue()) - { - try - { - if ( log.isInfoEnabled() ) - { - log.info( "Adding listener to cache watch. ICacheListener = " + listener - + " | ICacheObserver = " + cacheWatch ); - } - cacheWatch.addCacheListener( cacheName, listener ); - } - catch ( IOException ex ) - { - log.error( "Problem adding listener. ICacheListener = " + listener + " | ICacheObserver = " - + cacheWatch, ex ); - } - } - } - } - - /** - * Adds a feature to the CacheListener attribute of the CacheWatchRepairable object - *

- * @param cacheName The feature to be added to the CacheListener attribute - * @param obj The feature to be added to the CacheListener attribute - * @throws IOException - */ - @Override - public void addCacheListener( String cacheName, ICacheListener obj ) - throws IOException - { - // Record the added cache listener locally, regardless of whether the - // remote add-listener operation succeeds or fails. - Set> listenerSet = cacheMap.get( cacheName ); - if ( listenerSet == null ) - { - Set> newListenerSet = new CopyOnWriteArraySet>(); - listenerSet = cacheMap.putIfAbsent( cacheName, newListenerSet ); - - if (listenerSet == null) - { - listenerSet = newListenerSet; - } - } - - listenerSet.add( obj ); - - if ( log.isInfoEnabled() ) - { - log.info( "Adding listener to cache watch. ICacheListener = " + obj - + " | ICacheObserver = " + cacheWatch + " | cacheName = " + cacheName ); - } - cacheWatch.addCacheListener( cacheName, obj ); - } - - /** - * Adds a feature to the CacheListener attribute of the CacheWatchRepairable object - *

- * @param obj The feature to be added to the CacheListener attribute - * @throws IOException - */ - @Override - public void addCacheListener( ICacheListener obj ) - throws IOException - { - // Record the added cache listener locally, regardless of whether the - // remote add-listener operation succeeds or fails. - for (Set> listenerSet : cacheMap.values()) - { - listenerSet.add( obj ); - } - - if ( log.isInfoEnabled() ) - { - log.info( "Adding listener to cache watch. ICacheListener = " + obj - + " | ICacheObserver = " + cacheWatch ); - } - cacheWatch.addCacheListener( obj ); - } - - /** - * Tell the server to release us. - *

- * @param cacheName - * @param obj - * @throws IOException - */ - @Override - public void removeCacheListener( String cacheName, ICacheListener obj ) - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "removeCacheListener, cacheName [" + cacheName + "]" ); - } - // Record the removal locally, regardless of whether the remote - // remove-listener operation succeeds or fails. - Set> listenerSet = cacheMap.get( cacheName ); - if ( listenerSet != null ) - { - listenerSet.remove( obj ); - } - cacheWatch.removeCacheListener( cacheName, obj ); - } - - /** - * @param obj - * @throws IOException - */ - @Override - public void removeCacheListener( ICacheListener obj ) - throws IOException - { - if ( log.isInfoEnabled() ) - { - log.info( "removeCacheListener, ICacheListener [" + obj + "]" ); - } - - // Record the removal locally, regardless of whether the remote - // remove-listener operation succeeds or fails. - for (Set> listenerSet : cacheMap.values()) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Before removing [" + obj + "] the listenerSet = " + listenerSet ); - } - listenerSet.remove( obj ); - } - cacheWatch.removeCacheListener( obj ); - } -} diff --git a/src/org/apache/commons/jcs/engine/CompositeCacheAttributes.java b/src/org/apache/commons/jcs/engine/CompositeCacheAttributes.java deleted file mode 100644 index 31da4be512b..00000000000 --- a/src/org/apache/commons/jcs/engine/CompositeCacheAttributes.java +++ /dev/null @@ -1,443 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; - -/** - * The CompositeCacheAttributes defines the general cache region settings. If a region is not - * explicitly defined in the cache.ccf then it inherits the cache default settings. - *

- * If all the default attributes are not defined in the default region definition in the cache.ccf, - * the hard coded defaults will be used. - */ -public class CompositeCacheAttributes - implements ICompositeCacheAttributes -{ - /** Don't change */ - private static final long serialVersionUID = 6754049978134196787L; - - /** default lateral switch */ - private static final boolean DEFAULT_USE_LATERAL = true; - - /** default remote switch */ - private static final boolean DEFAULT_USE_REMOTE = true; - - /** default disk switch */ - private static final boolean DEFAULT_USE_DISK = true; - - /** default shrinker setting */ - private static final boolean DEFAULT_USE_SHRINKER = false; - - /** default max objects value */ - private static final int DEFAULT_MAX_OBJECTS = 100; - - /** default */ - private static final int DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS = 60 * 120; - - /** default interval to run the shrinker */ - private static final int DEFAULT_SHRINKER_INTERVAL_SECONDS = 30; - - /** default */ - private static final int DEFAULT_MAX_SPOOL_PER_RUN = -1; - - /** default */ - private static final String DEFAULT_MEMORY_CACHE_NAME = "org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache"; - - /** Default number to send to disk at a time when memory fills. */ - private static final int DEFAULT_CHUNK_SIZE = 2; - - /** allow lateral caches */ - private boolean useLateral = DEFAULT_USE_LATERAL; - - /** allow remote caches */ - private boolean useRemote = DEFAULT_USE_REMOTE; - - /** Whether we should use a disk cache if it is configured. */ - private boolean useDisk = DEFAULT_USE_DISK; - - /** Whether or not we should run the memory shrinker thread. */ - private boolean useMemoryShrinker = DEFAULT_USE_SHRINKER; - - /** The maximum objects that the memory cache will be allowed to hold. */ - private int maxObjs = DEFAULT_MAX_OBJECTS; - - /** maxMemoryIdleTimeSeconds */ - private long maxMemoryIdleTimeSeconds = DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS; - - /** shrinkerIntervalSeconds */ - private long shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS; - - /** The maximum number the shrinker will spool to disk per run. */ - private int maxSpoolPerRun = DEFAULT_MAX_SPOOL_PER_RUN; - - /** The name of this cache region. */ - private String cacheName; - - /** The name of the memory cache implementation class. */ - private String memoryCacheName; - - /** Set via DISK_USAGE_PATTERN_NAME */ - private DiskUsagePattern diskUsagePattern = DiskUsagePattern.SWAP; - - /** How many to spool to disk at a time. */ - private int spoolChunkSize = DEFAULT_CHUNK_SIZE; - - /** - * Constructor for the CompositeCacheAttributes object - */ - public CompositeCacheAttributes() - { - super(); - // set this as the default so the configuration is a bit simpler - memoryCacheName = DEFAULT_MEMORY_CACHE_NAME; - } - - /** - * Sets the maxObjects attribute of the CompositeCacheAttributes object - *

- * @param maxObjs The new maxObjects value - */ - @Override - public void setMaxObjects( int maxObjs ) - { - this.maxObjs = maxObjs; - } - - /** - * Gets the maxObjects attribute of the CompositeCacheAttributes object - *

- * @return The maxObjects value - */ - @Override - public int getMaxObjects() - { - return this.maxObjs; - } - - /** - * Sets the useDisk attribute of the CompositeCacheAttributes object - *

- * @param useDisk The new useDisk value - */ - @Override - public void setUseDisk( boolean useDisk ) - { - this.useDisk = useDisk; - } - - /** - * Gets the useDisk attribute of the CompositeCacheAttributes object - *

- * @return The useDisk value - */ - @Override - public boolean isUseDisk() - { - return useDisk; - } - - /** - * Sets the useLateral attribute of the CompositeCacheAttributes object - *

- * @param b The new useLateral value - */ - @Override - public void setUseLateral( boolean b ) - { - this.useLateral = b; - } - - /** - * Gets the useLateral attribute of the CompositeCacheAttributes object - *

- * @return The useLateral value - */ - @Override - public boolean isUseLateral() - { - return this.useLateral; - } - - /** - * Sets the useRemote attribute of the CompositeCacheAttributes object - *

- * @param useRemote The new useRemote value - */ - @Override - public void setUseRemote( boolean useRemote ) - { - this.useRemote = useRemote; - } - - /** - * Gets the useRemote attribute of the CompositeCacheAttributes object - *

- * @return The useRemote value - */ - @Override - public boolean isUseRemote() - { - return this.useRemote; - } - - /** - * Sets the cacheName attribute of the CompositeCacheAttributes object - *

- * @param s The new cacheName value - */ - @Override - public void setCacheName( String s ) - { - this.cacheName = s; - } - - /** - * Gets the cacheName attribute of the CompositeCacheAttributes object - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return this.cacheName; - } - - /** - * Sets the memoryCacheName attribute of the CompositeCacheAttributes object - *

- * @param s The new memoryCacheName value - */ - @Override - public void setMemoryCacheName( String s ) - { - this.memoryCacheName = s; - } - - /** - * Gets the memoryCacheName attribute of the CompositeCacheAttributes object - *

- * @return The memoryCacheName value - */ - @Override - public String getMemoryCacheName() - { - return this.memoryCacheName; - } - - /** - * Whether the memory cache should perform background memory shrinkage. - *

- * @param useShrinker The new UseMemoryShrinker value - */ - @Override - public void setUseMemoryShrinker( boolean useShrinker ) - { - this.useMemoryShrinker = useShrinker; - } - - /** - * Whether the memory cache should perform background memory shrinkage. - *

- * @return The UseMemoryShrinker value - */ - @Override - public boolean isUseMemoryShrinker() - { - return this.useMemoryShrinker; - } - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space. - *

- * @param seconds The new MaxMemoryIdleTimeSeconds value - */ - @Override - public void setMaxMemoryIdleTimeSeconds( long seconds ) - { - this.maxMemoryIdleTimeSeconds = seconds; - } - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space. - *

- * @return The MaxMemoryIdleTimeSeconds value - */ - @Override - public long getMaxMemoryIdleTimeSeconds() - { - return this.maxMemoryIdleTimeSeconds; - } - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space. - * This sets the shrinker interval. - *

- * @param seconds The new ShrinkerIntervalSeconds value - */ - @Override - public void setShrinkerIntervalSeconds( long seconds ) - { - this.shrinkerIntervalSeconds = seconds; - } - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space. - * This gets the shrinker interval. - *

- * @return The ShrinkerIntervalSeconds value - */ - @Override - public long getShrinkerIntervalSeconds() - { - return this.shrinkerIntervalSeconds; - } - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space. - * This sets the maximum number of items to spool per run. - *

- * If the value is -1, then there is no limit to the number of items to be spooled. - *

- * @param maxSpoolPerRun The new maxSpoolPerRun value - */ - @Override - public void setMaxSpoolPerRun( int maxSpoolPerRun ) - { - this.maxSpoolPerRun = maxSpoolPerRun; - } - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space. - * This gets the maximum number of items to spool per run. - *

- * @return The maxSpoolPerRun value - */ - @Override - public int getMaxSpoolPerRun() - { - return this.maxSpoolPerRun; - } - - /** - * By default this is SWAP_ONLY. - *

- * @param diskUsagePattern The diskUsagePattern to set. - */ - @Override - public void setDiskUsagePattern( DiskUsagePattern diskUsagePattern ) - { - this.diskUsagePattern = diskUsagePattern; - } - - /** - * Translates the name to the disk usage pattern short value. - *

- * The allowed values are SWAP and UPDATE. - *

- * @param diskUsagePatternName The diskUsagePattern to set. - */ - @Override - public void setDiskUsagePatternName( String diskUsagePatternName ) - { - if ( diskUsagePatternName != null ) - { - String name = diskUsagePatternName.toUpperCase().trim(); - if ( name.startsWith( "SWAP" ) ) - { - this.setDiskUsagePattern( DiskUsagePattern.SWAP ); - } - else if ( name.startsWith( "UPDATE" ) ) - { - this.setDiskUsagePattern( DiskUsagePattern.UPDATE ); - } - } - } - - /** - * Number to send to disk at at time when memory is full. - *

- * @return int - */ - @Override - public int getSpoolChunkSize() - { - return spoolChunkSize; - } - - /** - * Number to send to disk at a time. - *

- * @param spoolChunkSize - */ - @Override - public void setSpoolChunkSize( int spoolChunkSize ) - { - this.spoolChunkSize = spoolChunkSize; - } - - /** - * @return Returns the diskUsagePattern. - */ - @Override - public DiskUsagePattern getDiskUsagePattern() - { - return diskUsagePattern; - } - - /** - * Dumps the core attributes. - *

- * @return For debugging. - */ - @Override - public String toString() - { - StringBuilder dump = new StringBuilder(); - - dump.append( "[ " ); - dump.append( "useLateral = " ).append( useLateral ); - dump.append( ", useRemote = " ).append( useRemote ); - dump.append( ", useDisk = " ).append( useDisk ); - dump.append( ", maxObjs = " ).append( maxObjs ); - dump.append( ", maxSpoolPerRun = " ).append( maxSpoolPerRun ); - dump.append( ", diskUsagePattern = " ).append( diskUsagePattern ); - dump.append( ", spoolChunkSize = " ).append( spoolChunkSize ); - dump.append( " ]" ); - - return dump.toString(); - } - - /** - * @see java.lang.Object#clone() - */ - @Override - public ICompositeCacheAttributes clone() - { - try - { - return (ICompositeCacheAttributes)super.clone(); - } - catch (CloneNotSupportedException e) - { - throw new RuntimeException("Clone not supported. This should never happen.", e); - } - } -} diff --git a/src/org/apache/commons/jcs/engine/ElementAttributes.java b/src/org/apache/commons/jcs/engine/ElementAttributes.java deleted file mode 100644 index 4fd0252bdb8..00000000000 --- a/src/org/apache/commons/jcs/engine/ElementAttributes.java +++ /dev/null @@ -1,458 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler; - -/** - * This it the element attribute descriptor class. Each element in the cache has an ElementAttribute - * object associated with it. An ElementAttributes object can be associated with an element in 3 - * ways: - *

    - *
  1. When the item is put into the cache, you can associate an element attributes object.
  2. - *
  3. If not attributes object is include when the element is put into the cache, then the default - * attributes for the region will be used.
  4. - *
  5. The element attributes can be reset. This effectively results in a retrieval followed by a - * put. Hence, this is the same as 1.
  6. - *
- */ -public class ElementAttributes - implements IElementAttributes -{ - /** Don't change. */ - private static final long serialVersionUID = 7814990748035017441L; - - /** Can this item be flushed to disk */ - private boolean IS_SPOOL = true; - - /** Is this item laterally distributable */ - private boolean IS_LATERAL = true; - - /** Can this item be sent to the remote cache */ - private boolean IS_REMOTE = true; - - /** - * You can turn off expiration by setting this to true. This causes the cache to bypass both max - * life and idle time expiration. - */ - private boolean IS_ETERNAL = true; - - /** Max life seconds */ - private long maxLife = -1; - - /** - * The maximum time an entry can be idle. Setting this to -1 causes the idle time check to be - * ignored. - */ - private long maxIdleTime = -1; - - /** The byte size of the field. Must be manually set. */ - private int size = 0; - - /** The creation time. This is used to enforce the max life. */ - private long createTime = 0; - - /** The last access time. This is used to enforce the max idel time. */ - private long lastAccessTime = 0; - - /** - * The list of Event handlers to use. This is transient, since the event handlers cannot usually - * be serialized. This means that you cannot attach a post serialization event to an item. - *

- * TODO we need to check that when an item is passed to a non-local cache that if the local - * cache had a copy with event handlers, that those handlers are used. - */ - private transient ArrayList eventHandlers; - - private long timeFactor = 1000; - - /** - * Constructor for the IElementAttributes object - */ - public ElementAttributes() - { - this.createTime = System.currentTimeMillis(); - this.lastAccessTime = this.createTime; - } - - /** - * Constructor for the IElementAttributes object - *

- * @param attr - */ - protected ElementAttributes( ElementAttributes attr ) - { - IS_ETERNAL = attr.IS_ETERNAL; - - // waterfall onto disk, for pure disk set memory to 0 - IS_SPOOL = attr.IS_SPOOL; - - // lateral - IS_LATERAL = attr.IS_LATERAL; - - // central rmi store - IS_REMOTE = attr.IS_REMOTE; - - maxLife = attr.maxLife; - // time-to-live - maxIdleTime = attr.maxIdleTime; - size = attr.size; - } - - /** - * Sets the maxLife attribute of the IAttributes object. - *

- * @param mls The new MaxLifeSeconds value - */ - @Override - public void setMaxLife(long mls) - { - this.maxLife = mls; - } - - /** - * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after - * creation. - *

- * If this is exceeded the element will not be returned, instead it will be removed. It will be - * removed on retrieval, or removed actively if the memory shrinker is turned on. - * @return The MaxLifeSeconds value - */ - @Override - public long getMaxLife() - { - return this.maxLife; - } - - /** - * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can - * be idle in the cache, that is not accessed. - *

- * If this is exceeded the element will not be returned, instead it will be removed. It will be - * removed on retrieval, or removed actively if the memory shrinker is turned on. - * @param idle The new idleTime value - */ - @Override - public void setIdleTime( long idle ) - { - this.maxIdleTime = idle; - } - - /** - * Size in bytes. This is not used except in the admin pages. It will be -1 by default. - *

- * @param size The new size value - */ - @Override - public void setSize( int size ) - { - this.size = size; - } - - /** - * Gets the size attribute of the IAttributes object - *

- * @return The size value - */ - @Override - public int getSize() - { - return size; - } - - /** - * Gets the createTime attribute of the IAttributes object. - *

- * This should be the current time in milliseconds returned by the sysutem call when the element - * is put in the cache. - *

- * Putting an item in the cache overrides any existing items. - * @return The createTime value - */ - @Override - public long getCreateTime() - { - return createTime; - } - - /** - * Sets the createTime attribute of the IElementAttributes object - */ - public void setCreateTime() - { - createTime = System.currentTimeMillis(); - } - - /** - * Gets the idleTime attribute of the IAttributes object. - *

- * @return The idleTime value - */ - @Override - public long getIdleTime() - { - return this.maxIdleTime; - } - - /** - * Gets the time left to live of the IAttributes object. - *

- * This is the (max life + create time) - current time. - * @return The TimeToLiveSeconds value - */ - @Override - public long getTimeToLiveSeconds() - { - final long now = System.currentTimeMillis(); - final long timeFactorForMilliseconds = getTimeFactorForMilliseconds(); - return ( this.getCreateTime() + this.getMaxLife() * timeFactorForMilliseconds - now ) / 1000; - } - - /** - * Gets the LastAccess attribute of the IAttributes object. - *

- * @return The LastAccess value. - */ - @Override - public long getLastAccessTime() - { - return this.lastAccessTime; - } - - /** - * Sets the LastAccessTime as now of the IElementAttributes object - */ - @Override - public void setLastAccessTimeNow() - { - this.lastAccessTime = System.currentTimeMillis(); - } - - /** - * only for use from test code - */ - public void setLastAccessTime(long time) - { - this.lastAccessTime = time; - } - - /** - * Can this item be spooled to disk - *

- * By default this is true. - * @return The spoolable value - */ - @Override - public boolean getIsSpool() - { - return this.IS_SPOOL; - } - - /** - * Sets the isSpool attribute of the IElementAttributes object - *

- * By default this is true. - * @param val The new isSpool value - */ - @Override - public void setIsSpool( boolean val ) - { - this.IS_SPOOL = val; - } - - /** - * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral. - *

- * By default this is true. - * @return The isLateral value - */ - @Override - public boolean getIsLateral() - { - return this.IS_LATERAL; - } - - /** - * Sets the isLateral attribute of the IElementAttributes object - *

- * By default this is true. - * @param val The new isLateral value - */ - @Override - public void setIsLateral( boolean val ) - { - this.IS_LATERAL = val; - } - - /** - * Can this item be sent to the remote cache - * @return true if the item can be sent to a remote auxiliary - */ - @Override - public boolean getIsRemote() - { - return this.IS_REMOTE; - } - - /** - * Sets the isRemote attribute of the ElementAttributes object - * @param val The new isRemote value - */ - @Override - public void setIsRemote( boolean val ) - { - this.IS_REMOTE = val; - } - - /** - * You can turn off expiration by setting this to true. The max life value will be ignored. - *

- * @return true if the item cannot expire. - */ - @Override - public boolean getIsEternal() - { - return this.IS_ETERNAL; - } - - /** - * Sets the isEternal attribute of the ElementAttributes object. True means that the item should - * never expire. If can still be removed if it is the least recently used, and you are using the - * LRUMemory cache. it just will not be filtered for expiration by the cache hub. - *

- * @param val The new isEternal value - */ - @Override - public void setIsEternal( boolean val ) - { - this.IS_ETERNAL = val; - } - - /** - * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered - * handler will be called at every recognized event. - *

- * The alternative would be to register handlers for each event. Or maybe The handler interface - * should have a method to return whether it cares about certain events. - *

- * @param eventHandler The ElementEventHandler to be added to the list. - */ - @Override - public void addElementEventHandler( IElementEventHandler eventHandler ) - { - // lazy here, no concurrency problems expected - if ( this.eventHandlers == null ) - { - this.eventHandlers = new ArrayList(); - } - this.eventHandlers.add( eventHandler ); - } - - /** - * Sets the eventHandlers of the IElementAttributes object. - *

- * This add the references to the local list. Subsequent changes in the caller's list will not - * be reflected. - *

- * @param eventHandlers List of IElementEventHandler objects - */ - @Override - public void addElementEventHandlers( List eventHandlers ) - { - if ( eventHandlers == null ) - { - return; - } - - for (IElementEventHandler handler : eventHandlers) - { - addElementEventHandler(handler); - } - } - - @Override - public long getTimeFactorForMilliseconds() - { - return timeFactor; - } - - @Override - public void setTimeFactorForMilliseconds(long factor) - { - this.timeFactor = factor; - } - - /** - * Gets the elementEventHandlers. Returns null if none exist. Makes checking easy. - *

- * @return The elementEventHandlers List of IElementEventHandler objects - */ - @Override - public ArrayList getElementEventHandlers() - { - return this.eventHandlers; - } - - /** - * For logging and debugging the element IElementAttributes. - *

- * @return String info about the values. - */ - @Override - public String toString() - { - StringBuilder dump = new StringBuilder(); - - dump.append( "[ IS_LATERAL = " ).append( IS_LATERAL ); - dump.append( ", IS_SPOOL = " ).append( IS_SPOOL ); - dump.append( ", IS_REMOTE = " ).append( IS_REMOTE ); - dump.append( ", IS_ETERNAL = " ).append( IS_ETERNAL ); - dump.append( ", MaxLifeSeconds = " ).append( this.getMaxLife() ); - dump.append( ", IdleTime = " ).append( this.getIdleTime() ); - dump.append( ", CreateTime = " ).append( this.getCreateTime() ); - dump.append( ", LastAccessTime = " ).append( this.getLastAccessTime() ); - dump.append( ", getTimeToLiveSeconds() = " ).append( String.valueOf( getTimeToLiveSeconds() ) ); - dump.append( ", createTime = " ).append( String.valueOf( createTime ) ).append( " ]" ); - - return dump.toString(); - } - - /** - * @see java.lang.Object#clone() - */ - @Override - public IElementAttributes clone() - { - try - { - ElementAttributes c = (ElementAttributes) super.clone(); - c.setCreateTime(); - return c; - } - catch (CloneNotSupportedException e) - { - throw new RuntimeException("Clone not supported. This should never happen.", e); - } - } -} diff --git a/src/org/apache/commons/jcs/engine/PooledCacheEventQueue.java b/src/org/apache/commons/jcs/engine/PooledCacheEventQueue.java deleted file mode 100644 index e4b1089860b..00000000000 --- a/src/org/apache/commons/jcs/engine/PooledCacheEventQueue.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.apache.commons.jcs.engine; - -import java.util.ArrayList; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadPoolExecutor; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * An event queue is used to propagate ordered cache events to one and only one target listener. - *

- * This is a modified version of the experimental version. It uses a PooledExecutor and a - * BoundedBuffer to queue up events and execute them as threads become available. - *

- * The PooledExecutor is static, because presumably these processes will be IO bound, so throwing - * more than a few threads at them will serve no purpose other than to saturate the IO interface. In - * light of this, having one thread per region seems unnecessary. This may prove to be false. - */ -public class PooledCacheEventQueue - extends AbstractCacheEventQueue -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( PooledCacheEventQueue.class ); - - /** The type of event queue */ - private static final QueueType queueType = QueueType.POOLED; - - /** The Thread Pool to execute events with. */ - protected ExecutorService pool = null; - - /** The Thread Pool queue */ - protected BlockingQueue queue = null; - - /** - * Constructor for the CacheEventQueue object - *

- * @param listener - * @param listenerId - * @param cacheName - * @param maxFailure - * @param waitBeforeRetry - * @param threadPoolName - */ - public PooledCacheEventQueue( ICacheListener listener, long listenerId, String cacheName, int maxFailure, - int waitBeforeRetry, String threadPoolName ) - { - initialize( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, threadPoolName ); - } - - /** - * Initializes the queue. - *

- * @param listener - * @param listenerId - * @param cacheName - * @param maxFailure - * @param waitBeforeRetry - * @param threadPoolName - */ - protected void initialize( ICacheListener listener, long listenerId, String cacheName, int maxFailure, - int waitBeforeRetry, String threadPoolName ) - { - super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry); - - // this will share the same pool with other event queues by default. - pool = ThreadPoolManager.getInstance().getExecutorService( - (threadPoolName == null) ? "cache_event_queue" : threadPoolName ); - - if (pool instanceof ThreadPoolExecutor) - { - queue = ((ThreadPoolExecutor) pool).getQueue(); - } - } - - /** - * @return the queue type - */ - @Override - public QueueType getQueueType() - { - return queueType; - } - - /** - * Destroy the queue. Interrupt all threads. - */ - @Override - public synchronized void destroy() - { - if ( isWorking() ) - { - setWorking(false); - pool.shutdownNow(); - if ( log.isInfoEnabled() ) - { - log.info( "Cache event queue destroyed: " + this ); - } - } - } - - /** - * Adds an event to the queue. - *

- * @param event - */ - @Override - protected void put( AbstractCacheEvent event ) - { - pool.execute( event ); - } - - /** - * @return IStats - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Pooled Cache Event Queue" ); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "Working", Boolean.valueOf(isWorking()) ) ); - elems.add(new StatElement( "Empty", Boolean.valueOf(this.isEmpty()) ) ); - - if ( queue != null ) - { - elems.add(new StatElement( "Queue Size", Integer.valueOf(queue.size()) ) ); - elems.add(new StatElement( "Queue Capacity", Integer.valueOf(queue.remainingCapacity()) ) ); - } - - stats.setStatElements( elems ); - - return stats; - } - - /** - * If the Queue is using a bounded channel we can determine the size. If it is zero or we can't - * determine the size, we return true. - *

- * @return whether or not there are items in the queue - */ - @Override - public boolean isEmpty() - { - return size() == 0; - } - - /** - * Returns the number of elements in the queue. If the queue cannot determine the size - * accurately it will return 0. - *

- * @return number of items in the queue. - */ - @Override - public int size() - { - if ( queue == null ) - { - return 0; - } - else - { - return queue.size(); - } - } -} diff --git a/src/org/apache/commons/jcs/engine/ZombieCacheService.java b/src/org/apache/commons/jcs/engine/ZombieCacheService.java deleted file mode 100644 index dfa47fe079b..00000000000 --- a/src/org/apache/commons/jcs/engine/ZombieCacheService.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheService; -import org.apache.commons.jcs.engine.behavior.IZombie; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -/** - * Zombie adapter for any cache service. Balks at every call. - */ -public class ZombieCacheService - implements ICacheService, IZombie -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( ZombieCacheService.class ); - - /** - * @param item - */ - public void put( ICacheElement item ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Zombie put for item " + item ); - } - // zombies have no inner life - } - - /** - * Does nothing. - *

- * @param item - */ - @Override - public void update( ICacheElement item ) - { - // zombies have no inner life - } - - /** - * @param cacheName - * @param key - * @return null. zombies have no internal data - */ - @Override - public ICacheElement get( String cacheName, K key ) - { - return null; - } - - /** - * Returns an empty map. Zombies have no internal data. - *

- * @param cacheName - * @param keys - * @return Collections.EMPTY_MAP - */ - @Override - public Map> getMultiple( String cacheName, Set keys ) - { - return Collections.emptyMap(); - } - - /** - * Returns an empty map. Zombies have no internal data. - *

- * @param cacheName - * @param pattern - * @return Collections.EMPTY_MAP - */ - @Override - public Map> getMatching( String cacheName, String pattern ) - { - return Collections.emptyMap(); - } - - /** - * Logs the get to debug, but always balks. - *

- * @param cacheName - * @param key - * @param container - * @return null always - */ - public Serializable get( String cacheName, K key, boolean container ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Zombie get for key [" + key + "] cacheName [" + cacheName + "] container [" + container + "]" ); - } - // zombies have no inner life - return null; - } - - /** - * @param cacheName - * @param key - */ - @Override - public void remove( String cacheName, K key ) - { - // zombies have no inner life - } - - /** - * @param cacheName - */ - @Override - public void removeAll( String cacheName ) - { - // zombies have no inner life - } - - /** - * @param cacheName - */ - @Override - public void dispose( String cacheName ) - { - // zombies have no inner life - } - - /** - * Frees all caches. - */ - @Override - public void release() - { - // zombies have no inner life - } -} diff --git a/src/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocal.java b/src/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocal.java deleted file mode 100644 index 1c8b34c8481..00000000000 --- a/src/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocal.java +++ /dev/null @@ -1,322 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; -import org.apache.commons.jcs.utils.timing.ElapsedTimer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Zombie adapter for the non local cache services. It just balks if there is no queue configured. - *

- * If a queue is configured, then events will be added to the queue. The idea is that when proper - * operation is restored, the non local cache will walk the queue. The queue must be bounded so it - * does not eat memory. - *

- * This originated in the remote cache. - */ -public class ZombieCacheServiceNonLocal - extends ZombieCacheService - implements ICacheServiceNonLocal -{ - /** The logger */ - private static final Log log = LogFactory.getLog( ZombieCacheServiceNonLocal.class ); - - /** How big can the queue grow. */ - private int maxQueueSize = 0; - - /** The queue */ - private final ConcurrentLinkedQueue queue; - - /** - * Default. - */ - public ZombieCacheServiceNonLocal() - { - queue = new ConcurrentLinkedQueue(); - } - - /** - * Sets the maximum number of items that will be allowed on the queue. - *

- * @param maxQueueSize - */ - public ZombieCacheServiceNonLocal( int maxQueueSize ) - { - this.maxQueueSize = maxQueueSize; - queue = new ConcurrentLinkedQueue(); - } - - /** - * Gets the number of items on the queue. - *

- * @return size of the queue. - */ - public int getQueueSize() - { - return queue.size(); - } - - private void addQueue(ZombieEvent event) - { - queue.add(event); - if (queue.size() > maxQueueSize) - { - queue.poll(); // drop oldest entry - } - } - - /** - * Adds an update event to the queue if the maxSize is greater than 0; - *

- * @param item ICacheElement - * @param listenerId - identifies the caller. - */ - @Override - public void update( ICacheElement item, long listenerId ) - { - if ( maxQueueSize > 0 ) - { - PutEvent event = new PutEvent( item, listenerId ); - addQueue( event ); - } - // Zombies have no inner life - } - - /** - * Adds a removeAll event to the queue if the maxSize is greater than 0; - *

- * @param cacheName - region name - * @param key - item key - * @param listenerId - identifies the caller. - */ - @Override - public void remove( String cacheName, K key, long listenerId ) - { - if ( maxQueueSize > 0 ) - { - RemoveEvent event = new RemoveEvent( cacheName, key, listenerId ); - addQueue( event ); - } - // Zombies have no inner life - } - - /** - * Adds a removeAll event to the queue if the maxSize is greater than 0; - *

- * @param cacheName - name of the region - * @param listenerId - identifies the caller. - */ - @Override - public void removeAll( String cacheName, long listenerId ) - { - if ( maxQueueSize > 0 ) - { - RemoveAllEvent event = new RemoveAllEvent( cacheName, listenerId ); - addQueue( event ); - } - // Zombies have no inner life - } - - /** - * Does nothing. Gets are synchronous and cannot be added to a queue. - *

- * @param cacheName - region name - * @param key - item key - * @param requesterId - identifies the caller. - * @return null - * @throws IOException - */ - @Override - public ICacheElement get( String cacheName, K key, long requesterId ) - throws IOException - { - // Zombies have no inner life - return null; - } - - /** - * Does nothing. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return empty map - * @throws IOException - */ - @Override - public Map> getMatching( String cacheName, String pattern, long requesterId ) - throws IOException - { - return Collections.emptyMap(); - } - - /** - * @param cacheName - region name - * @param keys - item key - * @param requesterId - identity of the caller - * @return an empty map. zombies have no internal data - */ - @Override - public Map> getMultiple( String cacheName, Set keys, long requesterId ) - { - return new HashMap>(); - } - - /** - * Does nothing. - *

- * @param cacheName - region name - * @return empty set - */ - @Override - public Set getKeySet( String cacheName ) - { - return Collections.emptySet(); - } - - /** - * Walk the queue, calling the service for each queue operation. - *

- * @param service - * @throws Exception - */ - public synchronized void propagateEvents( ICacheServiceNonLocal service ) - throws Exception - { - int cnt = 0; - if ( log.isInfoEnabled() ) - { - log.info( "Propagating events to the new ICacheServiceNonLocal." ); - } - ElapsedTimer timer = new ElapsedTimer(); - while ( !queue.isEmpty() ) - { - cnt++; - - // for each item, call the appropriate service method - ZombieEvent event = queue.poll(); - - if ( event instanceof PutEvent ) - { - @SuppressWarnings("unchecked") // Type checked by instanceof - PutEvent putEvent = (PutEvent) event; - service.update( putEvent.element, event.requesterId ); - } - else if ( event instanceof RemoveEvent ) - { - @SuppressWarnings("unchecked") // Type checked by instanceof - RemoveEvent removeEvent = (RemoveEvent) event; - service.remove( event.cacheName, removeEvent.key, event.requesterId ); - } - else if ( event instanceof RemoveAllEvent ) - { - service.removeAll( event.cacheName, event.requesterId ); - } - } - if ( log.isInfoEnabled() ) - { - log.info( "Propagated " + cnt + " events to the new ICacheServiceNonLocal in " - + timer.getElapsedTimeString() ); - } - } - - /** - * Base of the other events. - */ - protected static abstract class ZombieEvent - { - /** The name of the region. */ - String cacheName; - - /** The id of the requester */ - long requesterId; - } - - /** - * A basic put event. - */ - private static class PutEvent - extends ZombieEvent - { - /** The element to put */ - ICacheElement element; - - /** - * Set the element - * @param element - * @param requesterId - */ - public PutEvent( ICacheElement element, long requesterId ) - { - this.requesterId = requesterId; - this.element = element; - } - } - - /** - * A basic Remove event. - */ - private static class RemoveEvent - extends ZombieEvent - { - /** The key to remove */ - K key; - - /** - * Set the element - * @param cacheName - * @param key - * @param requesterId - */ - public RemoveEvent( String cacheName, K key, long requesterId ) - { - this.cacheName = cacheName; - this.requesterId = requesterId; - this.key = key; - } - } - - /** - * A basic RemoveAll event. - */ - private static class RemoveAllEvent - extends ZombieEvent - { - /** - * @param cacheName - * @param requesterId - */ - public RemoveAllEvent( String cacheName, long requesterId ) - { - this.cacheName = cacheName; - this.requesterId = requesterId; - } - } -} diff --git a/src/org/apache/commons/jcs/engine/ZombieCacheWatch.java b/src/org/apache/commons/jcs/engine/ZombieCacheWatch.java deleted file mode 100644 index 8a17e57ee86..00000000000 --- a/src/org/apache/commons/jcs/engine/ZombieCacheWatch.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.apache.commons.jcs.engine; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheListener; -import org.apache.commons.jcs.engine.behavior.ICacheObserver; -import org.apache.commons.jcs.engine.behavior.IZombie; - -/** - * Zombie Observer. - */ -public class ZombieCacheWatch - implements ICacheObserver, IZombie -{ - /** - * Adds a feature to the CacheListener attribute of the ZombieCacheWatch object - *

- * @param cacheName The feature to be added to the CacheListener attribute - * @param obj The feature to be added to the CacheListener attribute - */ - @Override - public void addCacheListener( String cacheName, ICacheListener obj ) - { - // empty - } - - /** - * Adds a feature to the CacheListener attribute of the ZombieCacheWatch object - *

- * @param obj The feature to be added to the CacheListener attribute - */ - @Override - public void addCacheListener( ICacheListener obj ) - { - // empty - } - - /** - * @param cacheName - * @param obj - */ - @Override - public void removeCacheListener( String cacheName, ICacheListener obj ) - { - // empty - } - - /** - * @param obj - */ - @Override - public void removeCacheListener( ICacheListener obj ) - { - // empty - } -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICache.java b/src/org/apache/commons/jcs/engine/behavior/ICache.java deleted file mode 100644 index dc9d313e78d..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICache.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher; - -import java.io.IOException; -import java.util.Map; -import java.util.Set; - -/** - * This is the top level interface for all cache like structures. It defines the methods used - * internally by JCS to access, modify, and instrument such structures. - * - * This allows for a suite of reusable components for accessing such structures, for example - * asynchronous access via an event queue. - */ -public interface ICache - extends ICacheType -{ - /** - * Puts an item to the cache. - * - * @param element - * @throws IOException - */ - void update( ICacheElement element ) - throws IOException; - - /** - * Gets an item from the cache. - * - * @param key - * @return a cache element, or null if there is no data in cache for this key - * @throws IOException - */ - ICacheElement get( K key ) - throws IOException; - - /** - * Gets multiple items from the cache based on the given set of keys. - * - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no data in cache for any of these keys - * @throws IOException - */ - Map> getMultiple(Set keys) - throws IOException; - - /** - * Gets items from the cache matching the given pattern. Items from memory will replace those from remote sources. - * - * This only works with string keys. It's too expensive to do a toString on every key. - * - * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk cache will convert * to % and . to _ - * - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no data matching the pattern. - * @throws IOException - */ - Map> getMatching(String pattern) - throws IOException; - - /** - * Removes an item from the cache. - * - * @param key - * @return false if there was an error in removal - * @throws IOException - */ - boolean remove( K key ) - throws IOException; - - /** - * Removes all cached items from the cache. - * - * @throws IOException - */ - void removeAll() - throws IOException; - - /** - * Prepares for shutdown. - * @throws IOException - */ - void dispose() - throws IOException; - - /** - * Returns the current cache size in number of elements. - * - * @return number of elements - */ - int getSize(); - - /** - * Returns the cache status. - * - * @return Alive or Error - */ - CacheStatus getStatus(); - - /** - * Returns the cache stats. - * - * @return String of important historical information. - */ - String getStats(); - - /** - * Returns the cache name. - * - * @return usually the region name. - */ - String getCacheName(); - - /** - * Sets the key matcher used by get matching. - * - * @param keyMatcher - */ - void setKeyMatcher( IKeyMatcher keyMatcher ); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheElement.java b/src/org/apache/commons/jcs/engine/behavior/ICacheElement.java deleted file mode 100644 index acb82ea1e2d..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheElement.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * Every item is the cache is wrapped in an ICacheElement. This contains - * information about the element: the region name, the key, the value, and the - * element attributes. - *

- * The element attributes have lots of useful information about each element, - * such as when they were created, how long they have to live, and if they are - * allowed to be spooled, etc. - * - */ -public interface ICacheElement - extends Serializable -{ - - /** - * Gets the cacheName attribute of the ICacheElement<K, V> object. The cacheName - * is also known as the region name. - * - * @return The cacheName value - */ - String getCacheName(); - - /** - * Gets the key attribute of the ICacheElement<K, V> object - * - * @return The key value - */ - K getKey(); - - /** - * Gets the val attribute of the ICacheElement<K, V> object - * - * @return The val value - */ - V getVal(); - - /** - * Gets the attributes attribute of the ICacheElement<K, V> object - * - * @return The attributes value - */ - IElementAttributes getElementAttributes(); - - /** - * Sets the attributes attribute of the ICacheElement<K, V> object - * - * @param attr - * The new attributes value - */ - void setElementAttributes( IElementAttributes attr ); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheElementSerialized.java b/src/org/apache/commons/jcs/engine/behavior/ICacheElementSerialized.java deleted file mode 100644 index 1d80da60fde..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheElementSerialized.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This interface defines the behavior of the serialized element wrapper. - *

- * The value is stored as a byte array. This should allow for a variety of serialization mechanisms. - *

- * This currently extends ICacheElement<K, V> for backward compatibility. - *

- * @author Aaron Smuts - */ -public interface ICacheElementSerialized - extends ICacheElement -{ - /** - * Gets the value attribute of the ICacheElementSerialized object. This is the value the client - * cached serialized by some mechanism. - *

- * @return The serialized value - */ - byte[] getSerializedValue(); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheEventQueue.java b/src/org/apache/commons/jcs/engine/behavior/ICacheEventQueue.java deleted file mode 100644 index 3676385281e..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheEventQueue.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -import java.io.IOException; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.stats.behavior.IStats; - -/** - * Interface for a cache event queue. An event queue is used to propagate - * ordered cache events to one and only one target listener. - */ -public interface ICacheEventQueue -{ - enum QueueType - { - /** Does not use a thread pool. */ - SINGLE, - - /** Uses a thread pool. */ - POOLED - } - - /** - * Return the type of event queue we are using, either single or pooled. - *

- * @return the queue type: single or pooled - */ - QueueType getQueueType(); - - /** - * Adds a feature to the PutEvent attribute of the ICacheEventQueue object - *

- * @param ce - * The feature to be added to the PutEvent attribute - * @throws IOException - */ - void addPutEvent( ICacheElement ce ) - throws IOException; - - /** - * Adds a feature to the RemoveEvent attribute of the ICacheEventQueue - * object - *

- * @param key - * The feature to be added to the RemoveEvent attribute - * @throws IOException - */ - void addRemoveEvent( K key ) - throws IOException; - - /** - * Adds a feature to the RemoveAllEvent attribute of the ICacheEventQueue - * object - *

- * @throws IOException - */ - void addRemoveAllEvent() - throws IOException; - - /** - * Adds a feature to the DisposeEvent attribute of the ICacheEventQueue - * object - *

- * @throws IOException - */ - void addDisposeEvent() - throws IOException; - - /** - * Gets the listenerId attribute of the ICacheEventQueue object - * - * @return The listenerId value - */ - long getListenerId(); - - /** Description of the Method */ - void destroy(); - - /** - * A Queue is working unless it has reached its max failure count. - *

- * @return boolean - */ - boolean isWorking(); - - /** - * Returns the number of elements in the queue. If the queue cannot - * determine the size accurately it will return 1. - *

- * @return number of items in the queue. - */ - int size(); - - /** - * Are there elements in the queue. - *

- * @return true if there are stil elements. - */ - boolean isEmpty(); - - /** - * Returns the historical and statistical data for an event queue cache. - *

- * @return IStats - */ - IStats getStatistics(); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheListener.java b/src/org/apache/commons/jcs/engine/behavior/ICacheListener.java deleted file mode 100644 index 5e15913759d..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheListener.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -/** - * Used to receive a cache event notification. - *

- * Note: objects which implement this interface are local listeners to cache changes, whereas - * objects which implement IRmiCacheListener are remote listeners to cache changes. - */ -public interface ICacheListener -{ - /** - * Notifies the subscribers for a cache entry update. - *

- * @param item - * @throws IOException - */ - void handlePut( ICacheElement item ) - throws IOException; - - /** - * Notifies the subscribers for a cache entry removal. - *

- * @param cacheName - * @param key - * @throws IOException - */ - void handleRemove( String cacheName, K key ) - throws IOException; - - /** - * Notifies the subscribers for a cache remove-all. - *

- * @param cacheName - * @throws IOException - */ - void handleRemoveAll( String cacheName ) - throws IOException; - - /** - * Notifies the subscribers for freeing up the named cache. - *

- * @param cacheName - * @throws IOException - */ - void handleDispose( String cacheName ) - throws IOException; - - /** - * sets unique identifier of listener home - *

- * @param id The new listenerId value - * @throws IOException - */ - void setListenerId( long id ) - throws IOException; - - /** - * Gets the listenerId attribute of the ICacheListener object - *

- * @return The listenerId value - * @throws IOException - */ - long getListenerId() - throws IOException; -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheObserver.java b/src/org/apache/commons/jcs/engine/behavior/ICacheObserver.java deleted file mode 100644 index 11c9a058ff7..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheObserver.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -/** - * Used to register interest in receiving cache changes.
- *
- * Note: server which implements this interface provides a local cache event - * notification service, whereas server which implements IRmiCacheWatch provides - * a remote cache event notification service. - * - */ -public interface ICacheObserver -{ - /** - * Subscribes to the specified cache. - * - * @param cacheName - * the specified cache. - * @param obj - * object to notify for cache changes. - * @throws IOException - */ - void addCacheListener( String cacheName, ICacheListener obj ) - throws IOException; - - //, CacheNotFoundException; - - /** - * Subscribes to all caches. - * - * @param obj - * object to notify for all cache changes. - * @throws IOException - */ - void addCacheListener( ICacheListener obj ) - throws IOException; - - /** - * Unsubscribes from the specified cache. - * @param cacheName - * - * @param obj - * existing subscriber. - * @throws IOException - */ - void removeCacheListener( String cacheName, ICacheListener obj ) - throws IOException; - - /** - * Unsubscribes from all caches. - * - * @param obj - * existing subscriber. - * @throws IOException - */ - void removeCacheListener( ICacheListener obj ) - throws IOException; -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheService.java b/src/org/apache/commons/jcs/engine/behavior/ICacheService.java deleted file mode 100644 index 9f4aca57dc4..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheService.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.exception.ObjectExistsException; -import org.apache.commons.jcs.access.exception.ObjectNotFoundException; - -import java.io.IOException; -import java.util.Map; -import java.util.Set; - -/** - * Used to retrieve and update the cache. - *

- * Note: server which implements this interface provides a local cache service, whereas server which - * implements IRmiCacheService provides a remote cache service. - */ -public interface ICacheService -{ - /** - * Puts a cache item to the cache. - *

- * @param item - * @throws ObjectExistsException - * @throws IOException - */ - void update( ICacheElement item ) - throws ObjectExistsException, IOException; - - /** - * Returns a cache bean from the specified cache; or null if the key does not exist. - *

- * @param cacheName - * @param key - * @return the ICacheElement<K, V> or null if not found - * @throws ObjectNotFoundException - * @throws IOException - */ - ICacheElement get( String cacheName, K key ) - throws ObjectNotFoundException, IOException; - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws ObjectNotFoundException - * @throws IOException - */ - Map> getMultiple( String cacheName, Set keys ) - throws ObjectNotFoundException, IOException; - - /** - * Gets multiple items from the cache matching the pattern. - *

- * @param cacheName - * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching the pattern. - * @throws IOException - */ - Map> getMatching( String cacheName, String pattern ) - throws IOException; - - /** - * Removes the given key from the specified cache. - *

- * @param cacheName - * @param key - * @throws IOException - */ - void remove( String cacheName, K key ) - throws IOException; - - /** - * Remove all keys from the specified cache. - * @param cacheName - * @throws IOException - */ - void removeAll( String cacheName ) - throws IOException; - - /** - * Frees the specified cache. - *

- * @param cacheName - * @throws IOException - */ - void dispose( String cacheName ) - throws IOException; - - /** - * Frees all caches. - * @throws IOException - */ - void release() - throws IOException; -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheServiceAdmin.java b/src/org/apache/commons/jcs/engine/behavior/ICacheServiceAdmin.java deleted file mode 100644 index 856ff51c146..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheServiceAdmin.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -/** - * Description of the Interface - * - */ -public interface ICacheServiceAdmin -{ - - /** - * Gets the stats attribute of the ICacheServiceAdmin object - * - * @return The stats value - * @throws IOException - */ - String getStats() - throws IOException; - - /** Description of the Method - * @throws IOException*/ - void shutdown() - throws IOException; - - /** Description of the Method - * @param host - * @param port - * @throws IOException*/ - void shutdown( String host, int port ) - throws IOException; -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheServiceNonLocal.java b/src/org/apache/commons/jcs/engine/behavior/ICacheServiceNonLocal.java deleted file mode 100644 index 4fbf29f8266..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheServiceNonLocal.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.rmi.Remote; -import java.util.Map; -import java.util.Set; - -/** - * Used to retrieve and update non local caches, such as the remote and lateral caches. Unlike - * ICacheService, the methods here have a requester id. This allows us to avoid propagating events - * to ourself. - *

- * TODO consider not extending ICacheService - */ -public interface ICacheServiceNonLocal - extends Remote, ICacheService -{ - /** - * Puts a cache item to the cache. - *

- * @param item - * @param requesterId - * @throws IOException - */ - void update( ICacheElement item, long requesterId ) - throws IOException; - - /** - * Removes the given key from the specified cache. - *

- * @param cacheName - * @param key - * @param requesterId - * @throws IOException - */ - void remove( String cacheName, K key, long requesterId ) - throws IOException; - - /** - * Remove all keys from the specified cache. - *

- * @param cacheName - * @param requesterId - * @throws IOException - */ - void removeAll( String cacheName, long requesterId ) - throws IOException; - - /** - * Returns a cache bean from the specified cache; or null if the key does not exist. - *

- * Adding the requester id, allows the cache to determine the source of the get. - *

- * @param cacheName - * @param key - * @param requesterId - * @return ICacheElement - * @throws IOException - */ - ICacheElement get( String cacheName, K key, long requesterId ) - throws IOException; - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param cacheName - * @param keys - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - Map> getMultiple( String cacheName, Set keys, long requesterId ) - throws IOException; - - /** - * Gets multiple items from the cache matching the pattern. - *

- * @param cacheName - * @param pattern - * @param requesterId - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache matching the pattern. - * @throws IOException - */ - Map> getMatching( String cacheName, String pattern, long requesterId ) - throws IOException; - - /** - * Get a set of the keys for all elements in the cache. - *

- * @param cacheName the name of the cache - * @return a set of the key type - * TODO This should probably be done in chunks with a range passed in. This - * will be a problem if someone puts a 1,000,000 or so items in a - * region. - */ - Set getKeySet( String cacheName ) throws IOException; -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICacheType.java b/src/org/apache/commons/jcs/engine/behavior/ICacheType.java deleted file mode 100644 index 3828f3aa605..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICacheType.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Interface implemented by a specific cache. - * - */ -public interface ICacheType -{ - enum CacheType { - /** Composite/ memory cache type, central hub. */ - CACHE_HUB, - - /** Disk cache type. */ - DISK_CACHE, - - /** Lateral cache type. */ - LATERAL_CACHE, - - /** Remote cache type. */ - REMOTE_CACHE - } - - /** - * Returns the cache type. - *

- * @return The cacheType value - */ - CacheType getCacheType(); - -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICompositeCacheAttributes.java b/src/org/apache/commons/jcs/engine/behavior/ICompositeCacheAttributes.java deleted file mode 100644 index 7d22e4e0cd7..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICompositeCacheAttributes.java +++ /dev/null @@ -1,244 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * This defines the minimal behavior for the Cache Configuration settings. - */ -public interface ICompositeCacheAttributes - extends Serializable, Cloneable -{ - enum DiskUsagePattern - { - /** Items will only go to disk when the memory limit is reached. This is the default. */ - SWAP, - - /** - * Items will go to disk on a normal put. If The disk usage pattern is UPDATE, the swap will be - * disabled. - */ - UPDATE - } - - /** - * SetMaxObjects is used to set the attribute to determine the maximum - * number of objects allowed in the memory cache. If the max number of - * objects or the cache size is set, the default for the one not set is - * ignored. If both are set, both are used to determine the capacity of the - * cache, i.e., object will be removed from the cache if either limit is - * reached. TODO: move to MemoryCache config file. - *

- * @param size - * The new maxObjects value - */ - void setMaxObjects( int size ); - - /** - * Gets the maxObjects attribute of the ICompositeCacheAttributes object - *

- * @return The maxObjects value - */ - int getMaxObjects(); - - /** - * Sets the useDisk attribute of the ICompositeCacheAttributes object - *

- * @param useDisk - * The new useDisk value - */ - void setUseDisk( boolean useDisk ); - - /** - * Gets the useDisk attribute of the ICompositeCacheAttributes object - *

- * @return The useDisk value - */ - boolean isUseDisk(); - - /** - * set whether the cache should use a lateral cache - *

- * @param d - * The new useLateral value - */ - void setUseLateral( boolean d ); - - /** - * Gets the useLateral attribute of the ICompositeCacheAttributes object - *

- * @return The useLateral value - */ - boolean isUseLateral(); - - /** - * Sets whether the cache is remote enabled - *

- * @param isRemote - * The new useRemote value - */ - void setUseRemote( boolean isRemote ); - - /** - * returns whether the cache is remote enabled - *

- * @return The useRemote value - */ - boolean isUseRemote(); - - /** - * Sets the name of the cache, referenced by the appropriate manager. - *

- * @param s - * The new cacheName value - */ - void setCacheName( String s ); - - /** - * Gets the cacheName attribute of the ICompositeCacheAttributes object - *

- * @return The cacheName value - */ - String getCacheName(); - - /** - * Sets the name of the MemoryCache, referenced by the appropriate manager. - * TODO: create a separate memory cache attribute class. - *

- * @param s - * The new memoryCacheName value - */ - void setMemoryCacheName( String s ); - - /** - * Gets the memoryCacheName attribute of the ICompositeCacheAttributes - * object - *

- * @return The memoryCacheName value - */ - String getMemoryCacheName(); - - /** - * Whether the memory cache should perform background memory shrinkage. - *

- * @param useShrinker - * The new UseMemoryShrinker value - */ - void setUseMemoryShrinker( boolean useShrinker ); - - /** - * Whether the memory cache should perform background memory shrinkage. - *

- * @return The UseMemoryShrinker value - */ - boolean isUseMemoryShrinker(); - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements - * to reclaim space. - *

- * @param seconds - * The new MaxMemoryIdleTimeSeconds value - */ - void setMaxMemoryIdleTimeSeconds( long seconds ); - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements - * to reclaim space. - *

- * @return The MaxMemoryIdleTimeSeconds value - */ - long getMaxMemoryIdleTimeSeconds(); - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements - * to reclaim space. This sets the shrinker interval. - *

- * @param seconds - * The new ShrinkerIntervalSeconds value - */ - void setShrinkerIntervalSeconds( long seconds ); - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements - * to reclaim space. This gets the shrinker interval. - *

- * @return The ShrinkerIntervalSeconds value - */ - long getShrinkerIntervalSeconds(); - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements - * to reclaim space. This sets the maximum number of items to spool per run. - *

- * @param maxSpoolPerRun - * The new maxSpoolPerRun value - */ - void setMaxSpoolPerRun( int maxSpoolPerRun ); - - /** - * If UseMemoryShrinker is true the memory cache should auto-expire elements - * to reclaim space. This gets the maximum number of items to spool per run. - *

- * @return The maxSpoolPerRun value - */ - int getMaxSpoolPerRun(); - - /** - * By default this is SWAP_ONLY. - *

- * @param diskUsagePattern The diskUsagePattern to set. - */ - void setDiskUsagePattern( DiskUsagePattern diskUsagePattern ); - - /** - * Translates the name to the disk usage pattern short value. - *

- * The allowed values are SWAP and UPDATE. - *

- * @param diskUsagePatternName The diskUsagePattern to set. - */ - void setDiskUsagePatternName( String diskUsagePatternName ); - - /** - * @return Returns the diskUsagePattern. - */ - DiskUsagePattern getDiskUsagePattern(); - - /** - * Number to send to disk at at time when memory is full. - *

- * @return int - */ - int getSpoolChunkSize(); - - /** - * Number to send to disk at a time. - *

- * @param spoolChunkSize - */ - void setSpoolChunkSize( int spoolChunkSize ); - - /** - * Clone object - */ - ICompositeCacheAttributes clone(); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/ICompositeCacheManager.java b/src/org/apache/commons/jcs/engine/behavior/ICompositeCacheManager.java deleted file mode 100644 index caf499c5854..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/ICompositeCacheManager.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.engine.control.CompositeCache; - -import java.util.Properties; - -/** - * I need the interface so I can plug in mock managers for testing. - * - * @author Aaron Smuts - */ -public interface ICompositeCacheManager extends IShutdownObservable -{ - /** - * Gets the cache attribute of the CacheHub object - * - * @param cacheName - * @return CompositeCache - */ - CompositeCache getCache( String cacheName ); - - /** - * Gets the auxiliary cache attribute of the CacheHub object - * - * @param auxName - * @param cacheName - * @return AuxiliaryCache - */ - AuxiliaryCache getAuxiliaryCache( String auxName, String cacheName ); - - /** - * This is exposed so other manager can get access to the props. - *

- * @return the configurationProperties - */ - Properties getConfigurationProperties(); - - /** - * Gets stats for debugging. - *

- * @return String - */ - String getStats(); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/IElementAttributes.java b/src/org/apache/commons/jcs/engine/behavior/IElementAttributes.java deleted file mode 100644 index 2aa4e4662e9..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/IElementAttributes.java +++ /dev/null @@ -1,203 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler; - -/** - * Interface for cache element attributes classes. Every item is the cache is associated with an - * element attributes object. It is used to track the life of the object as well as to restrict its - * behavior. By default, elements get a clone of the region's attributes. - */ -public interface IElementAttributes extends Serializable, Cloneable -{ - /** - * Sets the maxLife attribute of the IAttributes object. - *

- * @param mls The new MaxLifeSeconds value - */ - void setMaxLife(long mls); - - /** - * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after - * creation. - *

- * If this is exceeded the element will not be returned, instead it will be removed. It will be - * removed on retrieval, or removed actively if the memory shrinker is turned on. - * @return The MaxLifeSeconds value - */ - long getMaxLife(); - - /** - * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can - * be idle in the cache, that is not accessed. - *

- * If this is exceeded the element will not be returned, instead it will be removed. It will be - * removed on retrieval, or removed actively if the memory shrinker is turned on. - * @param idle The new idleTime value - */ - void setIdleTime( long idle ); - - /** - * Size in bytes. This is not used except in the admin pages. It will be -1 by default. - *

- * @param size The new size value - */ - void setSize( int size ); - - /** - * Gets the size attribute of the IAttributes object - *

- * @return The size value - */ - int getSize(); - - /** - * Gets the createTime attribute of the IAttributes object. - *

- * This should be the current time in milliseconds returned by the sysutem call when the element - * is put in the cache. - *

- * Putting an item in the cache overrides any existing items. - * @return The createTime value - */ - long getCreateTime(); - - /** - * Gets the LastAccess attribute of the IAttributes object. - *

- * @return The LastAccess value. - */ - long getLastAccessTime(); - - /** - * Sets the LastAccessTime as now of the IElementAttributes object - */ - void setLastAccessTimeNow(); - - /** - * Gets the idleTime attribute of the IAttributes object - * @return The idleTime value - */ - long getIdleTime(); - - /** - * Gets the time left to live of the IAttributes object. - *

- * This is the (max life + create time) - current time. - * @return The TimeToLiveSeconds value - */ - long getTimeToLiveSeconds(); - - /** - * Can this item be spooled to disk - *

- * By default this is true. - * @return The spoolable value - */ - boolean getIsSpool(); - - /** - * Sets the isSpool attribute of the IElementAttributes object - *

- * By default this is true. - * @param val The new isSpool value - */ - void setIsSpool( boolean val ); - - /** - * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral. - *

- * By default this is true. - * @return The isLateral value - */ - boolean getIsLateral(); - - /** - * Sets the isLateral attribute of the IElementAttributes object - *

- * By default this is true. - * @param val The new isLateral value - */ - void setIsLateral( boolean val ); - - /** - * Can this item be sent to the remote cache. - *

- * By default this is true. - * @return The isRemote value - */ - boolean getIsRemote(); - - /** - * Sets the isRemote attribute of the IElementAttributes object. - *

- * By default this is true. - * @param val The new isRemote value - */ - void setIsRemote( boolean val ); - - /** - * This turns off expiration if it is true. - * @return The IsEternal value - */ - boolean getIsEternal(); - - /** - * Sets the isEternal attribute of the IElementAttributes object - * @param val The new isEternal value - */ - void setIsEternal( boolean val ); - - /** - * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered - * handler will be called at every recognized event. - * @param eventHandler The feature to be added to the ElementEventHandler - */ - void addElementEventHandler( IElementEventHandler eventHandler ); - - /** - * Gets the elementEventHandlers. - *

- * Event handlers are transient. The only events defined are in memory events. All handlers are - * lost if the item goes to disk. - * @return The elementEventHandlers value, null if there are none - */ - ArrayList getElementEventHandlers(); - - /** - * Sets the eventHandlers of the IElementAttributes object - * @param eventHandlers value - */ - void addElementEventHandlers( List eventHandlers ); - - long getTimeFactorForMilliseconds(); - - void setTimeFactorForMilliseconds(long factor); - - /** - * Clone object - */ - IElementAttributes clone(); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/IElementSerializer.java b/src/org/apache/commons/jcs/engine/behavior/IElementSerializer.java deleted file mode 100644 index 547cc1eaa47..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/IElementSerializer.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -/** - * Defines the behavior for cache element serializers. This layer of abstraction allows us to plug - * in different serialization mechanisms, such as a compressing standard serializer. - *

- * @author Aaron Smuts - */ -public interface IElementSerializer -{ - /** - * Turns an object into a byte array. - * @param obj - * @return byte[] - * @throws IOException - */ - byte[] serialize( T obj ) - throws IOException; - - /** - * Turns a byte array into an object. - * @param bytes - * @return Object - * @throws IOException - * @throws ClassNotFoundException thrown if we don't know the object. - */ - T deSerialize( byte[] bytes, ClassLoader loader ) - throws IOException, ClassNotFoundException; -} diff --git a/src/org/apache/commons/jcs/engine/behavior/IProvideScheduler.java b/src/org/apache/commons/jcs/engine/behavior/IProvideScheduler.java deleted file mode 100644 index 29ad9d28d01..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/IProvideScheduler.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.concurrent.ScheduledExecutorService; - - -/** - * Marker interface for providers of the central ScheduledExecutorService - *

- * @author Thomas Vandahl - * - */ -public interface IProvideScheduler -{ - /** - * Get an instance of a central ScheduledExecutorService - * @return the central scheduler - */ - ScheduledExecutorService getScheduledExecutorService(); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/IRequireScheduler.java b/src/org/apache/commons/jcs/engine/behavior/IRequireScheduler.java deleted file mode 100644 index 09ea8a754cb..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/IRequireScheduler.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.concurrent.ScheduledExecutorService; - - -/** - * Marker interface to allow the injection of a central ScheduledExecutorService - * for all modules requiring scheduled background operations. - *

- * @author Thomas Vandahl - * - */ -public interface IRequireScheduler -{ - /** - * Inject an instance of a central ScheduledExecutorService - * @param scheduledExecutor - */ - void setScheduledExecutorService( ScheduledExecutorService scheduledExecutor ); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/IShutdownObservable.java b/src/org/apache/commons/jcs/engine/behavior/IShutdownObservable.java deleted file mode 100644 index c4280376973..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/IShutdownObservable.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * ShutdownObservers can observe ShutdownObservable objects. - * The CacheManager is the primary observable that this is intended for. - *

- * Most shutdown operations will occur outside this framework for now. The initial - * goal is to allow background threads that are not reachable through any reference - * that the cache manager maintains to be killed on shutdown. - *

- * Perhaps the composite cache itself should be the observable object. - * It doesn't make much of a difference. There are some problems with - * region by region shutdown. Some auxiliaries are local. They will - * need to track when every region has shutdown before doing things like - * closing the socket with a lateral. - *

- * @author Aaron Smuts - * - */ -public interface IShutdownObservable -{ - - /** - * Registers an observer with the observable object. - * @param observer - */ - void registerShutdownObserver( IShutdownObserver observer ); - - /** - * Deregisters the observer with the observable. - * - * @param observer - */ - void deregisterShutdownObserver( IShutdownObserver observer ); - -} diff --git a/src/org/apache/commons/jcs/engine/behavior/IShutdownObserver.java b/src/org/apache/commons/jcs/engine/behavior/IShutdownObserver.java deleted file mode 100644 index 22b4052d62d..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/IShutdownObserver.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This interface is required of all shutdown observers. These observers - * can observer ShutdownObservable objects. The CacheManager is the primary - * observable that this is intended for. - *

- * Most shutdown operations will occur outside this framework for now. The initial - * goal is to allow background threads that are not reachable through any reference - * that the cache manager maintains to be killed on shutdown. - * - * @author Aaron Smuts - * - */ -public interface IShutdownObserver -{ - /** - * Tells the observer that the observable has received a shutdown command. - * - */ - void shutdown(); -} diff --git a/src/org/apache/commons/jcs/engine/behavior/IZombie.java b/src/org/apache/commons/jcs/engine/behavior/IZombie.java deleted file mode 100644 index 2c726c6519a..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/IZombie.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.apache.commons.jcs.engine.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Interface to mark an object as zombie for error recovery purposes. - * - */ -public interface IZombie -{ - // Zombies have no inner life. - // No qaulia found. -} diff --git a/src/org/apache/commons/jcs/engine/behavior/package.html b/src/org/apache/commons/jcs/engine/behavior/package.html deleted file mode 100644 index 9cb3956cff9..00000000000 --- a/src/org/apache/commons/jcs/engine/behavior/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - Interfaces used by the core and the auxiliary caches. - - diff --git a/src/org/apache/commons/jcs/engine/control/CompositeCache.java b/src/org/apache/commons/jcs/engine/control/CompositeCache.java deleted file mode 100644 index 088456295e6..00000000000 --- a/src/org/apache/commons/jcs/engine/control/CompositeCache.java +++ /dev/null @@ -1,1846 +0,0 @@ -package org.apache.commons.jcs.engine.control; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.access.exception.ObjectNotFoundException; -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.engine.CacheConstants; -import org.apache.commons.jcs.engine.CacheStatus; -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes.DiskUsagePattern; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.behavior.IRequireScheduler; -import org.apache.commons.jcs.engine.control.event.ElementEvent; -import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue; -import org.apache.commons.jcs.engine.control.group.GroupId; -import org.apache.commons.jcs.engine.match.KeyMatcherPatternImpl; -import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher; -import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache; -import org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache; -import org.apache.commons.jcs.engine.memory.shrinking.ShrinkerThread; -import org.apache.commons.jcs.engine.stats.CacheStats; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.behavior.ICacheStats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This is the primary hub for a single cache/region. It controls the flow of items through the - * cache. The auxiliary and memory caches are plugged in here. - *

- * This is the core of a JCS region. Hence, this simple class is the core of JCS. - */ -public class CompositeCache - implements ICache, IRequireScheduler -{ - /** log instance */ - private static final Log log = LogFactory.getLog( CompositeCache.class ); - - /** - * EventQueue for handling element events. Lazy initialized. One for each region. To be more efficient, the manager - * should pass a shared queue in. - */ - private IElementEventQueue elementEventQ; - - /** Auxiliary caches. */ - @SuppressWarnings("unchecked") // OK because this is an empty array - private AuxiliaryCache[] auxCaches = new AuxiliaryCache[0]; - - /** is this alive? */ - private AtomicBoolean alive; - - /** Region Elemental Attributes, default. */ - private IElementAttributes attr; - - /** Cache Attributes, for hub and memory auxiliary. */ - private ICompositeCacheAttributes cacheAttr; - - /** How many times update was called. */ - private AtomicInteger updateCount; - - /** How many times remove was called. */ - private AtomicInteger removeCount; - - /** Memory cache hit count */ - private AtomicInteger hitCountRam; - - /** Auxiliary cache hit count (number of times found in ANY auxiliary) */ - private AtomicInteger hitCountAux; - - /** Count of misses where element was not found. */ - private AtomicInteger missCountNotFound; - - /** Count of misses where element was expired. */ - private AtomicInteger missCountExpired; - - /** Cache manager. */ - private CompositeCacheManager cacheManager = null; - - /** - * The cache hub can only have one memory cache. This could be made more flexible in the future, - * but they are tied closely together. More than one doesn't make much sense. - */ - private IMemoryCache memCache; - - /** Key matcher used by the getMatching API */ - private IKeyMatcher keyMatcher = new KeyMatcherPatternImpl(); - - private ScheduledFuture future; - - /** - * Constructor for the Cache object - *

- * @param cattr The cache attribute - * @param attr The default element attributes - */ - public CompositeCache( ICompositeCacheAttributes cattr, IElementAttributes attr ) - { - this.attr = attr; - this.cacheAttr = cattr; - this.alive = new AtomicBoolean(true); - this.updateCount = new AtomicInteger(0); - this.removeCount = new AtomicInteger(0); - this.hitCountRam = new AtomicInteger(0); - this.hitCountAux = new AtomicInteger(0); - this.missCountNotFound = new AtomicInteger(0); - this.missCountExpired = new AtomicInteger(0); - - createMemoryCache( cattr ); - - if ( log.isInfoEnabled() ) - { - log.info( "Constructed cache with name [" + cacheAttr.getCacheName() + "] and cache attributes " + cattr ); - } - } - - /** - * Injector for Element event queue - * - * @param queue - */ - public void setElementEventQueue( IElementEventQueue queue ) - { - this.elementEventQ = queue; - } - - /** - * Injector for cache manager - * - * @param manager - */ - public void setCompositeCacheManager( CompositeCacheManager manager ) - { - this.cacheManager = manager; - } - - /** - * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) - */ - @Override - public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor) - { - if ( cacheAttr.isUseMemoryShrinker() ) - { - future = scheduledExecutor.scheduleAtFixedRate( - new ShrinkerThread(this), 0, cacheAttr.getShrinkerIntervalSeconds(), - TimeUnit.SECONDS); - } - } - - /** - * This sets the list of auxiliary caches for this region. - *

- * @param auxCaches - */ - public void setAuxCaches( AuxiliaryCache[] auxCaches ) - { - this.auxCaches = auxCaches; - } - - /** - * Get the list of auxiliary caches for this region. - *

- * @return an array of auxiliary caches, may be empty, never null - */ - public AuxiliaryCache[] getAuxCaches() - { - return this.auxCaches; - } - - /** - * Standard update method. - *

- * @param ce - * @throws IOException - */ - @Override - public void update( ICacheElement ce ) - throws IOException - { - update( ce, false ); - } - - /** - * Standard update method. - *

- * @param ce - * @throws IOException - */ - public void localUpdate( ICacheElement ce ) - throws IOException - { - update( ce, true ); - } - - /** - * Put an item into the cache. If it is localOnly, then do no notify remote or lateral - * auxiliaries. - *

- * @param cacheElement the ICacheElement<K, V> - * @param localOnly Whether the operation should be restricted to local auxiliaries. - * @throws IOException - */ - protected void update( ICacheElement cacheElement, boolean localOnly ) - throws IOException - { - - if ( cacheElement.getKey() instanceof String - && cacheElement.getKey().toString().endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) ) - { - throw new IllegalArgumentException( "key must not end with " + CacheConstants.NAME_COMPONENT_DELIMITER - + " for a put operation" ); - } - else if ( cacheElement.getKey() instanceof GroupId ) - { - throw new IllegalArgumentException( "key cannot be a GroupId " + " for a put operation" ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Updating memory cache " + cacheElement.getKey() ); - } - - updateCount.incrementAndGet(); - - synchronized ( this ) - { - memCache.update( cacheElement ); - updateAuxiliaries( cacheElement, localOnly ); - } - - cacheElement.getElementAttributes().setLastAccessTimeNow(); - } - - /** - * This method is responsible for updating the auxiliaries if they are present. If it is local - * only, any lateral and remote auxiliaries will not be updated. - *

- * Before updating an auxiliary it checks to see if the element attributes permit the operation. - *

- * Disk auxiliaries are only updated if the disk cache is not merely used as a swap. If the disk - * cache is merely a swap, then items will only go to disk when they overflow from memory. - *

- * This is called by update( cacheElement, localOnly ) after it updates the memory cache. - *

- * This is protected to make it testable. - *

- * @param cacheElement - * @param localOnly - * @throws IOException - */ - protected void updateAuxiliaries( ICacheElement cacheElement, boolean localOnly ) - throws IOException - { - // UPDATE AUXILLIARY CACHES - // There are 3 types of auxiliary caches: remote, lateral, and disk - // more can be added if future auxiliary caches don't fit the model - // You could run a database cache as either a remote or a local disk. - // The types would describe the purpose. - if ( log.isDebugEnabled() ) - { - if ( auxCaches.length > 0 ) - { - log.debug( "Updating auxiliary caches" ); - } - else - { - log.debug( "No auxiliary cache to update" ); - } - } - - for ( ICache aux : auxCaches ) - { - if ( aux == null ) - { - continue; - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Auxiliary cache type: " + aux.getCacheType() ); - } - - switch (aux.getCacheType()) - { - // SEND TO REMOTE STORE - case REMOTE_CACHE: - if ( log.isDebugEnabled() ) - { - log.debug( "ce.getElementAttributes().getIsRemote() = " - + cacheElement.getElementAttributes().getIsRemote() ); - } - - if ( cacheElement.getElementAttributes().getIsRemote() && !localOnly ) - { - try - { - // need to make sure the group cache understands that - // the key is a group attribute on update - aux.update( cacheElement ); - if ( log.isDebugEnabled() ) - { - log.debug( "Updated remote store for " + cacheElement.getKey() + cacheElement ); - } - } - catch ( IOException ex ) - { - log.error( "Failure in updateExclude", ex ); - } - } - break; - - // SEND LATERALLY - case LATERAL_CACHE: - // lateral can't do the checking since it is dependent on the - // cache region restrictions - if ( log.isDebugEnabled() ) - { - log.debug( "lateralcache in aux list: cattr " + cacheAttr.isUseLateral() ); - } - if ( cacheAttr.isUseLateral() && cacheElement.getElementAttributes().getIsLateral() && !localOnly ) - { - // DISTRIBUTE LATERALLY - // Currently always multicast even if the value is - // unchanged, to cause the cache item to move to the front. - aux.update( cacheElement ); - if ( log.isDebugEnabled() ) - { - log.debug( "updated lateral cache for " + cacheElement.getKey() ); - } - } - break; - - // update disk if the usage pattern permits - case DISK_CACHE: - if ( log.isDebugEnabled() ) - { - log.debug( "diskcache in aux list: cattr " + cacheAttr.isUseDisk() ); - } - if ( cacheAttr.isUseDisk() - && cacheAttr.getDiskUsagePattern() == DiskUsagePattern.UPDATE - && cacheElement.getElementAttributes().getIsSpool() ) - { - aux.update( cacheElement ); - if ( log.isDebugEnabled() ) - { - log.debug( "updated disk cache for " + cacheElement.getKey() ); - } - } - break; - - default: // CACHE_HUB - break; - } - } - } - - /** - * Writes the specified element to any disk auxiliaries. Might want to rename this "overflow" in - * case the hub wants to do something else. - *

- * If JCS is not configured to use the disk as a swap, that is if the the - * CompositeCacheAttribute diskUsagePattern is not SWAP_ONLY, then the item will not be spooled. - *

- * @param ce The CacheElement - */ - public void spoolToDisk( ICacheElement ce ) - { - // if the item is not spoolable, return - if ( !ce.getElementAttributes().getIsSpool() ) - { - // there is an event defined for this. - handleElementEvent( ce, ElementEventType.SPOOLED_NOT_ALLOWED ); - return; - } - - boolean diskAvailable = false; - - // SPOOL TO DISK. - for ( ICache aux : auxCaches ) - { - if ( aux != null && aux.getCacheType() == CacheType.DISK_CACHE ) - { - diskAvailable = true; - - if ( cacheAttr.getDiskUsagePattern() == DiskUsagePattern.SWAP ) - { - // write the last items to disk.2 - try - { - handleElementEvent( ce, ElementEventType.SPOOLED_DISK_AVAILABLE ); - aux.update( ce ); - } - catch ( IOException ex ) - { - // impossible case. - log.error( "Problem spooling item to disk cache.", ex ); - throw new IllegalStateException( ex.getMessage() ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "spoolToDisk done for: " + ce.getKey() + " on disk cache[" + aux.getCacheName() + "]" ); - } - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "DiskCache available, but JCS is not configured to use the DiskCache as a swap." ); - } - } - } - } - - if ( !diskAvailable ) - { - try - { - handleElementEvent( ce, ElementEventType.SPOOLED_DISK_NOT_AVAILABLE ); - } - catch ( Exception e ) - { - log.error( "Trouble handling the ELEMENT_EVENT_SPOOLED_DISK_NOT_AVAILABLE element event", e ); - } - } - } - - /** - * Gets an item from the cache. - *

- * @param key - * @return element from the cache, or null if not present - * @see org.apache.commons.jcs.engine.behavior.ICache#get(Object) - */ - @Override - public ICacheElement get( K key ) - { - return get( key, false ); - } - - /** - * Do not try to go remote or laterally for this get. - *

- * @param key - * @return ICacheElement - */ - public ICacheElement localGet( K key ) - { - return get( key, true ); - } - - /** - * Look in memory, then disk, remote, or laterally for this item. The order is dependent on the - * order in the cache.ccf file. - *

- * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go - * remote or lateral if such an auxiliary is configured for this region. - *

- * @param key - * @param localOnly - * @return ICacheElement - */ - protected ICacheElement get( K key, boolean localOnly ) - { - ICacheElement element = null; - - boolean found = false; - - final boolean debugEnabled = log.isDebugEnabled(); // tested anyway but don't test it > once - if (debugEnabled) - { - log.debug( "get: key = " + key + ", localOnly = " + localOnly ); - } - - synchronized (this) - { - try - { - // First look in memory cache - element = memCache.get( key ); - - if ( element != null ) - { - // Found in memory cache - if ( isExpired( element ) ) - { - missCountExpired.incrementAndGet(); - remove( key ); - element = null; - } - else - { - // Update counters - hitCountRam.incrementAndGet(); - } - - found = true; - } - else - { - // Item not found in memory. If local invocation look in aux - // caches, even if not local look in disk auxiliaries - for (AuxiliaryCache aux : auxCaches) - { - if ( aux != null ) - { - CacheType cacheType = aux.getCacheType(); - - if ( !localOnly || cacheType == CacheType.DISK_CACHE ) - { - if (debugEnabled) - { - log.debug( "Attempting to get from aux [" + aux.getCacheName() + "] which is of type: " - + cacheType ); - } - - try - { - element = aux.get( key ); - } - catch ( IOException e ) - { - log.error( "Error getting from aux", e ); - } - } - - if (debugEnabled) - { - log.debug( "Got CacheElement: " + element ); - } - - // Item found in one of the auxiliary caches. - if ( element != null ) - { - if ( isExpired( element ) ) - { - if (debugEnabled) - { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit, but element expired." ); - } - - missCountExpired.incrementAndGet(); - - // This will tell the remotes to remove the item - // based on the element's expiration policy. The elements attributes - // associated with the item when it created govern its behavior - // everywhere. - remove( key ); - element = null; - } - else - { - if (debugEnabled) - { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit" ); - } - - // Update counters - hitCountAux.incrementAndGet(); - copyAuxiliaryRetrievedItemToMemory( element ); - } - - found = true; - - break; - } - } - } - } - } - catch ( IOException e ) - { - log.error( "Problem encountered getting element.", e ); - } - } - - if ( !found ) - { - missCountNotFound.incrementAndGet(); - - if (debugEnabled) - { - log.debug( cacheAttr.getCacheName() + " - Miss" ); - } - } - else if (debugEnabled) // we log here to avoid to log in the synchronized block - { - if (element == null) - { - log.debug( cacheAttr.getCacheName() + " - Memory cache hit, but element expired" ); - } - else - { - log.debug( cacheAttr.getCacheName() + " - Memory cache hit" ); - } - } - - if (element != null) - { - element.getElementAttributes().setLastAccessTimeNow(); - } - - return element; - } - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - */ - @Override - public Map> getMultiple( Set keys ) - { - return getMultiple( keys, false ); - } - - /** - * Gets multiple items from the cache based on the given set of keys. Do not try to go remote or - * laterally for this data. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - */ - public Map> localGetMultiple( Set keys ) - { - return getMultiple( keys, true ); - } - - /** - * Look in memory, then disk, remote, or laterally for these items. The order is dependent on - * the order in the cache.ccf file. Keep looking in each cache location until either the element - * is found, or the method runs out of places to look. - *

- * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go - * remote or lateral if such an auxiliary is configured for this region. - *

- * @param keys - * @param localOnly - * @return ICacheElement - */ - protected Map> getMultiple( Set keys, boolean localOnly ) - { - Map> elements = new HashMap>(); - - if ( log.isDebugEnabled() ) - { - log.debug( "get: key = " + keys + ", localOnly = " + localOnly ); - } - - try - { - // First look in memory cache - elements.putAll( getMultipleFromMemory( keys ) ); - - // If fewer than all items were found in memory, then keep looking. - if ( elements.size() != keys.size() ) - { - Set remainingKeys = pruneKeysFound( keys, elements ); - elements.putAll( getMultipleFromAuxiliaryCaches( remainingKeys, localOnly ) ); - } - } - catch ( IOException e ) - { - log.error( "Problem encountered getting elements.", e ); - } - - // if we didn't find all the elements, increment the miss count by the number of elements not found - if ( elements.size() != keys.size() ) - { - missCountNotFound.addAndGet(keys.size() - elements.size()); - - if ( log.isDebugEnabled() ) - { - log.debug( cacheAttr.getCacheName() + " - " + ( keys.size() - elements.size() ) + " Misses" ); - } - } - - return elements; - } - - /** - * Gets items for the keys in the set. Returns a map: key -> result. - *

- * @param keys - * @return the elements found in the memory cache - * @throws IOException - */ - private Map> getMultipleFromMemory( Set keys ) - throws IOException - { - Map> elementsFromMemory = memCache.getMultiple( keys ); - - Iterator> elementFromMemoryIterator = new HashMap>( elementsFromMemory ).values().iterator(); - - while ( elementFromMemoryIterator.hasNext() ) - { - ICacheElement element = elementFromMemoryIterator.next(); - - if ( element != null ) - { - // Found in memory cache - if ( isExpired( element ) ) - { - if ( log.isDebugEnabled() ) - { - log.debug( cacheAttr.getCacheName() + " - Memory cache hit, but element expired" ); - } - - missCountExpired.incrementAndGet(); - remove( element.getKey() ); - elementsFromMemory.remove( element.getKey() ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( cacheAttr.getCacheName() + " - Memory cache hit" ); - } - - // Update counters - hitCountRam.incrementAndGet(); - } - } - } - return elementsFromMemory; - } - - /** - * If local invocation look in aux caches, even if not local look in disk auxiliaries. - *

- * @param keys - * @param localOnly - * @return the elements found in the auxiliary caches - * @throws IOException - */ - private Map> getMultipleFromAuxiliaryCaches( Set keys, boolean localOnly ) - throws IOException - { - Map> elements = new HashMap>(); - Set remainingKeys = new HashSet( keys ); - - for ( AuxiliaryCache aux : auxCaches ) - { - if ( aux != null ) - { - Map> elementsFromAuxiliary = - new HashMap>(); - - CacheType cacheType = aux.getCacheType(); - - if ( !localOnly || cacheType == CacheType.DISK_CACHE ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Attempting to get from aux [" + aux.getCacheName() + "] which is of type: " - + cacheType ); - } - - try - { - elementsFromAuxiliary.putAll( aux.getMultiple( remainingKeys ) ); - } - catch ( IOException e ) - { - log.error( "Error getting from aux", e ); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Got CacheElements: " + elementsFromAuxiliary ); - } - - processRetrievedElements( aux, elementsFromAuxiliary ); - - elements.putAll( elementsFromAuxiliary ); - - if ( elements.size() == keys.size() ) - { - break; - } - else - { - remainingKeys = pruneKeysFound( keys, elements ); - } - } - } - - return elements; - } - - /** - * Build a map of all the matching elements in all of the auxiliaries and memory. - *

- * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any matching keys - */ - @Override - public Map> getMatching( String pattern ) - { - return getMatching( pattern, false ); - } - - /** - * Build a map of all the matching elements in all of the auxiliaries and memory. Do not try to - * go remote or laterally for this data. - *

- * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any matching keys - */ - public Map> localGetMatching( String pattern ) - { - return getMatching( pattern, true ); - } - - /** - * Build a map of all the matching elements in all of the auxiliaries and memory. Items in - * memory will replace from the auxiliaries in the returned map. The auxiliaries are accessed in - * opposite order. It's assumed that those closer to home are better. - *

- * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go - * remote or lateral if such an auxiliary is configured for this region. - *

- * @param pattern - * @param localOnly - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any matching keys - */ - protected Map> getMatching( String pattern, boolean localOnly ) - { - Map> elements = new HashMap>(); - - if ( log.isDebugEnabled() ) - { - log.debug( "get: pattern [" + pattern + "], localOnly = " + localOnly ); - } - - try - { - // First look in auxiliaries - elements.putAll( getMatchingFromAuxiliaryCaches( pattern, localOnly ) ); - - // then look in memory, override aux with newer memory items. - elements.putAll( getMatchingFromMemory( pattern ) ); - } - catch ( Exception e ) - { - log.error( "Problem encountered getting elements.", e ); - } - - return elements; - } - - /** - * Gets the key array from the memcache. Builds a set of matches. Calls getMultiple with the - * set. Returns a map: key -> result. - *

- * @param pattern - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any matching keys - * @throws IOException - */ - protected Map> getMatchingFromMemory( String pattern ) - throws IOException - { - // find matches in key array - // this avoids locking the memory cache, but it uses more memory - Set keyArray = memCache.getKeySet(); - - Set matchingKeys = getKeyMatcher().getMatchingKeysFromArray( pattern, keyArray ); - - // call get multiple - return getMultipleFromMemory( matchingKeys ); - } - - /** - * If local invocation look in aux caches, even if not local look in disk auxiliaries. - *

- * Moves in reverse order of definition. This will allow you to override those that are from the - * remote with those on disk. - *

- * @param pattern - * @param localOnly - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any matching keys - * @throws IOException - */ - private Map> getMatchingFromAuxiliaryCaches( String pattern, boolean localOnly ) - throws IOException - { - Map> elements = new HashMap>(); - - for ( int i = auxCaches.length - 1; i >= 0; i-- ) - { - AuxiliaryCache aux = auxCaches[i]; - - if ( aux != null ) - { - Map> elementsFromAuxiliary = - new HashMap>(); - - CacheType cacheType = aux.getCacheType(); - - if ( !localOnly || cacheType == CacheType.DISK_CACHE ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Attempting to get from aux [" + aux.getCacheName() + "] which is of type: " - + cacheType ); - } - - try - { - elementsFromAuxiliary.putAll( aux.getMatching( pattern ) ); - } - catch ( IOException e ) - { - log.error( "Error getting from aux", e ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Got CacheElements: " + elementsFromAuxiliary ); - } - - processRetrievedElements( aux, elementsFromAuxiliary ); - - elements.putAll( elementsFromAuxiliary ); - } - } - } - - return elements; - } - - /** - * Remove expired elements retrieved from an auxiliary. Update memory with good items. - *

- * @param aux the auxiliary cache instance - * @param elementsFromAuxiliary - * @throws IOException - */ - private void processRetrievedElements( AuxiliaryCache aux, Map> elementsFromAuxiliary ) - throws IOException - { - Iterator> elementFromAuxiliaryIterator = new HashMap>( elementsFromAuxiliary ).values().iterator(); - - while ( elementFromAuxiliaryIterator.hasNext() ) - { - ICacheElement element = elementFromAuxiliaryIterator.next(); - - // Item found in one of the auxiliary caches. - if ( element != null ) - { - if ( isExpired( element ) ) - { - if ( log.isDebugEnabled() ) - { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit, but element expired." ); - } - - missCountExpired.incrementAndGet(); - - // This will tell the remote caches to remove the item - // based on the element's expiration policy. The elements attributes - // associated with the item when it created govern its behavior - // everywhere. - remove( element.getKey() ); - elementsFromAuxiliary.remove( element.getKey() ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( cacheAttr.getCacheName() + " - Aux cache[" + aux.getCacheName() + "] hit" ); - } - - // Update counters - hitCountAux.incrementAndGet(); - copyAuxiliaryRetrievedItemToMemory( element ); - } - } - } - } - - /** - * Copies the item to memory if the memory size is greater than 0. Only spool if the memory - * cache size is greater than 0, else the item will immediately get put into purgatory. - *

- * @param element - * @throws IOException - */ - private void copyAuxiliaryRetrievedItemToMemory( ICacheElement element ) - throws IOException - { - if ( memCache.getCacheAttributes().getMaxObjects() > 0 ) - { - memCache.update( element ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Skipping memory update since no items are allowed in memory" ); - } - } - } - - /** - * Returns a set of keys that were not found. - *

- * @param keys - * @param foundElements - * @return the original set of cache keys, minus any cache keys present in the map keys of the - * foundElements map - */ - private Set pruneKeysFound( Set keys, Map> foundElements ) - { - Set remainingKeys = new HashSet( keys ); - - for (K key : foundElements.keySet()) - { - remainingKeys.remove( key ); - } - - return remainingKeys; - } - - /** - * Get a set of the keys for all elements in the cache - *

- * @return A set of the key type - */ - public Set getKeySet() - { - return getKeySet(false); - } - - /** - * Get a set of the keys for all elements in the cache - *

- * @param localOnly true if only memory keys are requested - * - * @return A set of the key type - */ - public Set getKeySet(boolean localOnly) - { - HashSet allKeys = new HashSet(); - - allKeys.addAll( memCache.getKeySet() ); - for ( AuxiliaryCache aux : auxCaches ) - { - if ( aux != null ) - { - if(!localOnly || aux.getCacheType() == CacheType.DISK_CACHE) - { - try - { - allKeys.addAll( aux.getKeySet() ); - } - catch ( IOException e ) - { - // ignore - } - } - } - } - return allKeys; - } - - /** - * Removes an item from the cache. - *

- * @param key - * @return true is it was removed - * @see org.apache.commons.jcs.engine.behavior.ICache#remove(Object) - */ - @Override - public boolean remove( K key ) - { - return remove( key, false ); - } - - /** - * Do not propagate removeall laterally or remotely. - *

- * @param key - * @return true if the item was already in the cache. - */ - public boolean localRemove( K key ) - { - return remove( key, true ); - } - - /** - * fromRemote: If a remove call was made on a cache with both, then the remote should have been - * called. If it wasn't then the remote is down. we'll assume it is down for all. If it did come - * from the remote then the cache is remotely configured and lateral removal is unnecessary. If - * it came laterally then lateral removal is unnecessary. Does this assume that there is only - * one lateral and remote for the cache? Not really, the initial removal should take care of the - * problem if the source cache was similarly configured. Otherwise the remote cache, if it had - * no laterals, would remove all the elements from remotely configured caches, but if those - * caches had some other weird laterals that were not remotely configured, only laterally - * propagated then they would go out of synch. The same could happen for multiple remotes. If - * this looks necessary we will need to build in an identifier to specify the source of a - * removal. - *

- * @param key - * @param localOnly - * @return true if the item was in the cache, else false - */ - protected boolean remove( K key, boolean localOnly ) - { - removeCount.incrementAndGet(); - - boolean removed = false; - - synchronized (this) - { - try - { - removed = memCache.remove( key ); - } - catch ( IOException e ) - { - log.error( e ); - } - - // Removes from all auxiliary caches. - for ( ICache aux : auxCaches ) - { - if ( aux == null ) - { - continue; - } - - CacheType cacheType = aux.getCacheType(); - - // for now let laterals call remote remove but not vice versa - - if ( localOnly && ( cacheType == CacheType.REMOTE_CACHE || cacheType == CacheType.LATERAL_CACHE ) ) - { - continue; - } - try - { - if ( log.isDebugEnabled() ) - { - log.debug( "Removing " + key + " from cacheType" + cacheType ); - } - - boolean b = aux.remove( key ); - - // Don't take the remote removal into account. - if ( !removed && cacheType != CacheType.REMOTE_CACHE ) - { - removed = b; - } - } - catch ( IOException ex ) - { - log.error( "Failure removing from aux", ex ); - } - } - } - - return removed; - } - - /** - * Clears the region. This command will be sent to all auxiliaries. Some auxiliaries, such as - * the JDBC disk cache, can be configured to not honor removeAll requests. - *

- * @see org.apache.commons.jcs.engine.behavior.ICache#removeAll() - */ - @Override - public void removeAll() - throws IOException - { - removeAll( false ); - } - - /** - * Will not pass the remove message remotely. - *

- * @throws IOException - */ - public void localRemoveAll() - throws IOException - { - removeAll( true ); - } - - /** - * Removes all cached items. - *

- * @param localOnly must pass in false to get remote and lateral aux's updated. This prevents - * looping. - * @throws IOException - */ - protected void removeAll( boolean localOnly ) - throws IOException - { - synchronized (this) - { - try - { - memCache.removeAll(); - - if ( log.isDebugEnabled() ) - { - log.debug( "Removed All keys from the memory cache." ); - } - } - catch ( IOException ex ) - { - log.error( "Trouble updating memory cache.", ex ); - } - - // Removes from all auxiliary disk caches. - for ( ICache aux : auxCaches ) - { - if ( aux != null && ( aux.getCacheType() == CacheType.DISK_CACHE || !localOnly ) ) - { - try - { - if ( log.isDebugEnabled() ) - { - log.debug( "Removing All keys from cacheType" + aux.getCacheType() ); - } - - aux.removeAll(); - } - catch ( IOException ex ) - { - log.error( "Failure removing all from aux", ex ); - } - } - } - } - } - - /** - * Flushes all cache items from memory to auxiliary caches and close the auxiliary caches. - */ - @Override - public void dispose() - { - dispose( false ); - } - - /** - * Invoked only by CacheManager. This method disposes of the auxiliaries one by one. For the - * disk cache, the items in memory are freed, meaning that they will be sent through the - * overflow channel to disk. After the auxiliaries are disposed, the memory cache is disposed. - *

- * @param fromRemote - */ - public void dispose( boolean fromRemote ) - { - // If already disposed, return immediately - if ( alive.compareAndSet(true, false) == false ) - { - return; - } - - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] fromRemote [" + fromRemote + "]" ); - } - - synchronized (this) - { - // Remove us from the cache managers list - // This will call us back but exit immediately - if (cacheManager != null) - { - cacheManager.freeCache(getCacheName(), fromRemote); - } - - // Try to stop shrinker thread - if (future != null) - { - future.cancel(true); - } - - // Now, shut down the event queue - if (elementEventQ != null) - { - elementEventQ.dispose(); - elementEventQ = null; - } - - // Dispose of each auxiliary cache, Remote auxiliaries will be - // skipped if 'fromRemote' is true. - for ( ICache aux : auxCaches ) - { - try - { - // Skip this auxiliary if: - // - The auxiliary is null - // - The auxiliary is not alive - // - The auxiliary is remote and the invocation was remote - if ( aux == null || aux.getStatus() != CacheStatus.ALIVE - || ( fromRemote && aux.getCacheType() == CacheType.REMOTE_CACHE ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] SKIPPING auxiliary [" + aux.getCacheName() + "] fromRemote [" - + fromRemote + "]" ); - } - continue; - } - - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] auxiliary [" + aux.getCacheName() + "]" ); - } - - // IT USED TO BE THE CASE THAT (If the auxiliary is not a lateral, or the cache - // attributes - // have 'getUseLateral' set, all the elements currently in - // memory are written to the lateral before disposing) - // I changed this. It was excessive. Only the disk cache needs the items, since only - // the disk cache is in a situation to not get items on a put. - if ( aux.getCacheType() == CacheType.DISK_CACHE ) - { - int numToFree = memCache.getSize(); - memCache.freeElements( numToFree ); - - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] put " + numToFree + " into auxiliary " + aux.getCacheName() ); - } - } - - // Dispose of the auxiliary - aux.dispose(); - } - catch ( IOException ex ) - { - log.error( "Failure disposing of aux.", ex ); - } - } - - if ( log.isInfoEnabled() ) - { - log.info( "In DISPOSE, [" + this.cacheAttr.getCacheName() + "] disposing of memory cache." ); - } - try - { - memCache.dispose(); - } - catch ( IOException ex ) - { - log.error( "Failure disposing of memCache", ex ); - } - } - } - - /** - * Calling save cause the entire contents of the memory cache to be flushed to all auxiliaries. - * Though this put is extremely fast, this could bog the cache and should be avoided. The - * dispose method should call a version of this. Good for testing. - */ - public void save() - { - if ( alive.compareAndSet(true, false) == false ) - { - return; - } - - synchronized ( this ) - { - for ( ICache aux : auxCaches ) - { - try - { - if ( aux.getStatus() == CacheStatus.ALIVE ) - { - for (K key : memCache.getKeySet()) - { - ICacheElement ce = memCache.get(key); - - if (ce != null) - { - aux.update( ce ); - } - } - } - } - catch ( IOException ex ) - { - log.error( "Failure saving aux caches.", ex ); - } - } - } - if ( log.isDebugEnabled() ) - { - log.debug( "Called save for [" + cacheAttr.getCacheName() + "]" ); - } - } - - /** - * Gets the size attribute of the Cache object. This return the number of elements, not the byte - * size. - *

- * @return The size value - */ - @Override - public int getSize() - { - return memCache.getSize(); - } - - /** - * Gets the cacheType attribute of the Cache object. - *

- * @return The cacheType value - */ - @Override - public CacheType getCacheType() - { - return CacheType.CACHE_HUB; - } - - /** - * Gets the status attribute of the Cache object. - *

- * @return The status value - */ - @Override - public CacheStatus getStatus() - { - return alive.get() ? CacheStatus.ALIVE : CacheStatus.DISPOSED; - } - - /** - * Gets stats for debugging. - *

- * @return String - */ - @Override - public String getStats() - { - return getStatistics().toString(); - } - - /** - * This returns data gathered for this region and all the auxiliaries it currently uses. - *

- * @return Statistics and Info on the Region. - */ - public ICacheStats getStatistics() - { - ICacheStats stats = new CacheStats(); - stats.setRegionName( this.getCacheName() ); - - // store the composite cache stats first - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "HitCountRam", Integer.valueOf(getHitCountRam()) ) ); - elems.add(new StatElement( "HitCountAux", Integer.valueOf(getHitCountAux()) ) ); - - stats.setStatElements( elems ); - - // memory + aux, memory is not considered an auxiliary internally - int total = auxCaches.length + 1; - ArrayList auxStats = new ArrayList(total); - - auxStats.add(getMemoryCache().getStatistics()); - - for ( AuxiliaryCache aux : auxCaches ) - { - auxStats.add(aux.getStatistics()); - } - - // store the auxiliary stats - stats.setAuxiliaryCacheStats( auxStats ); - - return stats; - } - - /** - * Gets the cacheName attribute of the Cache object. This is also known as the region name. - *

- * @return The cacheName value - */ - @Override - public String getCacheName() - { - return cacheAttr.getCacheName(); - } - - /** - * Gets the default element attribute of the Cache object This returns a copy. It does not - * return a reference to the attributes. - *

- * @return The attributes value - */ - public IElementAttributes getElementAttributes() - { - if ( attr != null ) - { - return attr.clone(); - } - return null; - } - - /** - * Sets the default element attribute of the Cache object. - *

- * @param attr - */ - public void setElementAttributes( IElementAttributes attr ) - { - this.attr = attr; - } - - /** - * Gets the ICompositeCacheAttributes attribute of the Cache object. - *

- * @return The ICompositeCacheAttributes value - */ - public ICompositeCacheAttributes getCacheAttributes() - { - return this.cacheAttr; - } - - /** - * Sets the ICompositeCacheAttributes attribute of the Cache object. - *

- * @param cattr The new ICompositeCacheAttributes value - */ - public void setCacheAttributes( ICompositeCacheAttributes cattr ) - { - this.cacheAttr = cattr; - // need a better way to do this, what if it is in error - this.memCache.initialize( this ); - } - - /** - * Gets the elementAttributes attribute of the Cache object. - *

- * @param key - * @return The elementAttributes value - * @throws CacheException - * @throws IOException - */ - public IElementAttributes getElementAttributes( K key ) - throws CacheException, IOException - { - ICacheElement ce = get( key ); - if ( ce == null ) - { - throw new ObjectNotFoundException( "key " + key + " is not found" ); - } - return ce.getElementAttributes(); - } - - /** - * Determine if the element is expired based on the values of the element attributes - * - * @param element the element - * - * @return true if the element is expired - */ - public boolean isExpired( ICacheElement element) - { - return isExpired(element, System.currentTimeMillis(), - ElementEventType.EXCEEDED_MAXLIFE_ONREQUEST, - ElementEventType.EXCEEDED_IDLETIME_ONREQUEST ); - } - - /** - * Check if the element is expired based on the values of the element attributes - * - * @param element the element - * @param timestamp the timestamp to compare to - * @param eventMaxlife the event to fire in case the max life time is exceeded - * @param eventIdle the event to fire in case the idle time is exceeded - * - * @return true if the element is expired - */ - public boolean isExpired(ICacheElement element, long timestamp, - ElementEventType eventMaxlife, ElementEventType eventIdle) - { - try - { - IElementAttributes attributes = element.getElementAttributes(); - - if ( !attributes.getIsEternal() ) - { - // Remove if maxLifeSeconds exceeded - - long maxLifeSeconds = attributes.getMaxLife(); - long createTime = attributes.getCreateTime(); - - final long timeFactorForMilliseconds = attributes.getTimeFactorForMilliseconds(); - - if ( maxLifeSeconds != -1 && ( timestamp - createTime ) > ( maxLifeSeconds * timeFactorForMilliseconds) ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Exceeded maxLife: " + element.getKey() ); - } - - handleElementEvent( element, eventMaxlife ); - - return true; - } - long idleTime = attributes.getIdleTime(); - long lastAccessTime = attributes.getLastAccessTime(); - - // Remove if maxIdleTime exceeded - // If you have a 0 size memory cache, then the last access will - // not get updated. - // you will need to set the idle time to -1. - - if ( ( idleTime != -1 ) && ( timestamp - lastAccessTime ) > idleTime * timeFactorForMilliseconds ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Exceeded maxIdle: " + element.getKey() ); - } - - handleElementEvent( element, eventIdle ); - - return true; - } - } - } - catch ( Exception e ) - { - log.error( "Error determining expiration period, expiring", e ); - - return true; - } - - return false; - } - - /** - * If there are event handlers for the item, then create an event and queue it up. - *

- * This does not call handle directly; instead the handler and the event are put into a queue. - * This prevents the event handling from blocking normal cache operations. - *

- * @param element the item - * @param eventType the event type - */ - public void handleElementEvent( ICacheElement element, ElementEventType eventType ) - { - ArrayList eventHandlers = element.getElementAttributes().getElementEventHandlers(); - if ( eventHandlers != null ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Element Handlers are registered. Create event type " + eventType ); - } - if ( elementEventQ == null ) - { - log.warn("No element event queue available for cache " + getCacheName()); - return; - } - IElementEvent> event = new ElementEvent>( element, eventType ); - for (IElementEventHandler hand : eventHandlers) - { - try - { - elementEventQ.addElementEvent( hand, event ); - } - catch ( IOException e ) - { - log.error( "Trouble adding element event to queue", e ); - } - } - } - } - - /** - * Create the MemoryCache based on the config parameters. - * TODO: consider making this an auxiliary, despite its close tie to the CacheHub. - * TODO: might want to create a memory cache config file separate from that of the hub -- ICompositeCacheAttributes - *

- * @param cattr - */ - private void createMemoryCache( ICompositeCacheAttributes cattr ) - { - if ( memCache == null ) - { - try - { - Class c = Class.forName( cattr.getMemoryCacheName() ); - @SuppressWarnings("unchecked") // Need cast - IMemoryCache newInstance = (IMemoryCache) c.newInstance(); - memCache = newInstance; - memCache.initialize( this ); - } - catch ( Exception e ) - { - log.warn( "Failed to init mem cache, using: LRUMemoryCache", e ); - - this.memCache = new LRUMemoryCache(); - this.memCache.initialize( this ); - } - } - else - { - log.warn( "Refusing to create memory cache -- already exists." ); - } - } - - /** - * Access to the memory cache for instrumentation. - *

- * @return the MemoryCache implementation - */ - public IMemoryCache getMemoryCache() - { - return memCache; - } - - /** - * Number of times a requested item was found in the memory cache. - *

- * @return number of hits in memory - */ - public int getHitCountRam() - { - return hitCountRam.get(); - } - - /** - * Number of times a requested item was found in and auxiliary cache. - * @return number of auxiliary hits. - */ - public int getHitCountAux() - { - return hitCountAux.get(); - } - - /** - * Number of times a requested element was not found. - * @return number of misses. - */ - public int getMissCountNotFound() - { - return missCountNotFound.get(); - } - - /** - * Number of times a requested element was found but was expired. - * @return number of found but expired gets. - */ - public int getMissCountExpired() - { - return missCountExpired.get(); - } - - /** - * @return Returns the updateCount. - */ - public int getUpdateCount() - { - return updateCount.get(); - } - - /** - * Sets the key matcher used by get matching. - *

- * @param keyMatcher - */ - @Override - public void setKeyMatcher( IKeyMatcher keyMatcher ) - { - if ( keyMatcher != null ) - { - this.keyMatcher = keyMatcher; - } - } - - /** - * Returns the key matcher used by get matching. - *

- * @return keyMatcher - */ - public IKeyMatcher getKeyMatcher() - { - return this.keyMatcher; - } - - /** - * This returns the stats. - *

- * @return getStats() - */ - @Override - public String toString() - { - return getStats(); - } -} diff --git a/src/org/apache/commons/jcs/engine/control/CompositeCacheConfigurator.java b/src/org/apache/commons/jcs/engine/control/CompositeCacheConfigurator.java deleted file mode 100644 index f80efcb9bc6..00000000000 --- a/src/org/apache/commons/jcs/engine/control/CompositeCacheConfigurator.java +++ /dev/null @@ -1,570 +0,0 @@ -package org.apache.commons.jcs.engine.control; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.StringTokenizer; - -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheFactory; -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.engine.behavior.IRequireScheduler; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.jcs.engine.match.KeyMatcherPatternImpl; -import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher; -import org.apache.commons.jcs.utils.config.OptionConverter; -import org.apache.commons.jcs.utils.config.PropertySetter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class configures JCS based on a properties object. - *

- * This class is based on the log4j class org.apache.log4j.PropertyConfigurator which was made by: - * "Luke Blanshard" <Luke@quiq.com>"Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>"Anders Kristensen" - * <akristensen@dynamicsoft.com> - */ -public class CompositeCacheConfigurator -{ - /** The logger */ - private static final Log log = LogFactory.getLog( CompositeCacheConfigurator.class ); - - /** The prefix of relevant system properties */ - protected static final String SYSTEM_PROPERTY_KEY_PREFIX = "jcs"; - - /** normal region prefix */ - protected static final String REGION_PREFIX = "jcs.region."; - - /** system region prefix. might not be used */ - protected static final String SYSTEM_REGION_PREFIX = "jcs.system."; - - /** auxiliary prefix */ - protected static final String AUXILIARY_PREFIX = "jcs.auxiliary."; - - /** .attributes */ - protected static final String ATTRIBUTE_PREFIX = ".attributes"; - - /** .cacheattributes */ - protected static final String CACHE_ATTRIBUTE_PREFIX = ".cacheattributes"; - - /** .elementattributes */ - protected static final String ELEMENT_ATTRIBUTE_PREFIX = ".elementattributes"; - - /** - * jcs.auxiliary.NAME.keymatcher=CLASSNAME - *

- * jcs.auxiliary.NAME.keymatcher.attributes.CUSTOMPROPERTY=VALUE - */ - public static final String KEY_MATCHER_PREFIX = ".keymatcher"; - - /** - * Constructor for the CompositeCacheConfigurator object - */ - public CompositeCacheConfigurator() - { - // empty - } - - /** - * Create caches used internally. System status gives them creation priority. - *

- * @param props Configuration properties - * @param ccm Cache hub - */ - protected void parseSystemRegions( Properties props, CompositeCacheManager ccm ) - { - for (String key : props.stringPropertyNames() ) - { - if ( key.startsWith( SYSTEM_REGION_PREFIX ) && key.indexOf( "attributes" ) == -1 ) - { - String regionName = key.substring( SYSTEM_REGION_PREFIX.length() ); - String auxiliaries = OptionConverter.findAndSubst( key, props ); - ICache cache; - synchronized ( regionName ) - { - cache = parseRegion( props, ccm, regionName, auxiliaries, null, SYSTEM_REGION_PREFIX ); - } - ccm.addCache( regionName, cache ); - } - } - } - - /** - * Parse region elements. - *

- * @param props Configuration properties - * @param ccm Cache hub - */ - protected void parseRegions( Properties props, CompositeCacheManager ccm ) - { - List regionNames = new ArrayList(); - - for (String key : props.stringPropertyNames() ) - { - if ( key.startsWith( REGION_PREFIX ) && key.indexOf( "attributes" ) == -1 ) - { - String regionName = key.substring( REGION_PREFIX.length() ); - regionNames.add( regionName ); - String auxiliaries = OptionConverter.findAndSubst( key, props ); - ICache cache; - synchronized ( regionName ) - { - cache = parseRegion( props, ccm, regionName, auxiliaries ); - } - ccm.addCache( regionName, cache ); - } - } - - if ( log.isInfoEnabled() ) - { - log.info( "Parsed regions " + regionNames ); - } - } - - /** - * Create cache region. - *

- * @param props Configuration properties - * @param ccm Cache hub - * @param regName Name of the cache region - * @param auxiliaries Comma separated list of auxiliaries - * - * @return CompositeCache - */ - protected CompositeCache parseRegion( - Properties props, CompositeCacheManager ccm, String regName, String auxiliaries ) - { - return parseRegion( props, ccm, regName, auxiliaries, null, REGION_PREFIX ); - } - - /** - * Get all the properties for a region and configure its cache. - *

- * This method tells the other parse method the name of the region prefix. - *

- * @param props Configuration properties - * @param ccm Cache hub - * @param regName Name of the cache region - * @param auxiliaries Comma separated list of auxiliaries - * @param cca Cache configuration - * - * @return CompositeCache - */ - protected CompositeCache parseRegion( - Properties props, CompositeCacheManager ccm, String regName, String auxiliaries, - ICompositeCacheAttributes cca ) - { - return parseRegion( props, ccm, regName, auxiliaries, cca, REGION_PREFIX ); - } - - /** - * Get all the properties for a region and configure its cache. - *

- * @param props Configuration properties - * @param ccm Cache hub - * @param regName Name of the cache region - * @param auxiliaries Comma separated list of auxiliaries - * @param cca Cache configuration - * @param regionPrefix Prefix for the region - * - * @return CompositeCache - */ - protected CompositeCache parseRegion( - Properties props, CompositeCacheManager ccm, String regName, String auxiliaries, - ICompositeCacheAttributes cca, String regionPrefix ) - { - // First, create or get the cache and element attributes, and create - // the cache. - IElementAttributes ea = parseElementAttributes( props, regName, - ccm.getDefaultElementAttributes(), regionPrefix ); - - CompositeCache cache = ( cca == null ) - ? new CompositeCache( parseCompositeCacheAttributes( props, regName, - ccm.getDefaultCacheAttributes(), regionPrefix ), ea ) - : new CompositeCache( cca, ea ); - - // Inject cache manager - cache.setCompositeCacheManager(ccm); - - // Inject scheduler service - cache.setScheduledExecutorService(ccm.getScheduledExecutorService()); - - // Inject element event queue - cache.setElementEventQueue(ccm.getElementEventQueue()); - - if (cache.getMemoryCache() instanceof IRequireScheduler) - { - ((IRequireScheduler)cache.getMemoryCache()).setScheduledExecutorService( - ccm.getScheduledExecutorService()); - } - - if (auxiliaries != null) - { - // Next, create the auxiliaries for the new cache - List> auxList = new ArrayList>(); - - if ( log.isDebugEnabled() ) - { - log.debug( "Parsing region name '" + regName + "', value '" + auxiliaries + "'" ); - } - - // We must skip over ',' but not white space - StringTokenizer st = new StringTokenizer( auxiliaries, "," ); - - // If value is not in the form ", appender.." or "", then we should set - // the priority of the category. - - if ( !( auxiliaries.startsWith( "," ) || auxiliaries.equals( "" ) ) ) - { - // just to be on the safe side... - if ( !st.hasMoreTokens() ) - { - return null; - } - } - - AuxiliaryCache auxCache; - String auxName; - while ( st.hasMoreTokens() ) - { - auxName = st.nextToken().trim(); - if ( auxName == null || auxName.equals( "," ) ) - { - continue; - } - log.debug( "Parsing auxiliary named \"" + auxName + "\"." ); - - auxCache = parseAuxiliary( props, ccm, auxName, regName ); - - if ( auxCache != null ) - { - if (auxCache instanceof IRequireScheduler) - { - ((IRequireScheduler) auxCache).setScheduledExecutorService( - ccm.getScheduledExecutorService()); - } - - auxList.add( auxCache ); - } - } - - // Associate the auxiliaries with the cache - @SuppressWarnings("unchecked") // No generic arrays in java - AuxiliaryCache[] auxArray = auxList.toArray( new AuxiliaryCache[0] ); - cache.setAuxCaches( auxArray ); - } - - // Return the new cache - return cache; - } - - /** - * Get an ICompositeCacheAttributes for the listed region. - *

- * @param props Configuration properties - * @param regName the region name - * @param defaultCCAttr the default cache attributes - * - * @return ICompositeCacheAttributes - */ - protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props, - String regName, ICompositeCacheAttributes defaultCCAttr ) - { - return parseCompositeCacheAttributes( props, regName, defaultCCAttr, REGION_PREFIX ); - } - - /** - * Get the main attributes for a region. - *

- * @param props Configuration properties - * @param regName the region name - * @param defaultCCAttr the default cache attributes - * @param regionPrefix the region prefix - * - * @return ICompositeCacheAttributes - */ - protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props, - String regName, ICompositeCacheAttributes defaultCCAttr, String regionPrefix ) - { - ICompositeCacheAttributes ccAttr; - - String attrName = regionPrefix + regName + CACHE_ATTRIBUTE_PREFIX; - - // auxFactory was not previously initialized. - // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX; - ccAttr = OptionConverter.instantiateByKey( props, attrName, null ); - - if ( ccAttr == null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "No special CompositeCacheAttributes class defined for key [" + attrName - + "], using default class." ); - } - - ccAttr = defaultCCAttr; - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Parsing options for '" + attrName + "'" ); - } - - PropertySetter.setProperties( ccAttr, props, attrName + "." ); - ccAttr.setCacheName( regName ); - - if ( log.isDebugEnabled() ) - { - log.debug( "End of parsing for \"" + attrName + "\"." ); - } - - // GET CACHE FROM FACTORY WITH ATTRIBUTES - ccAttr.setCacheName( regName ); - return ccAttr; - } - - /** - * Create the element attributes from the properties object for a cache region. - *

- * @param props Configuration properties - * @param regName the region name - * @param defaultEAttr the default element attributes - * @param regionPrefix the region prefix - * - * @return IElementAttributes - */ - protected IElementAttributes parseElementAttributes( Properties props, String regName, - IElementAttributes defaultEAttr, String regionPrefix ) - { - IElementAttributes eAttr; - - String attrName = regionPrefix + regName + CompositeCacheConfigurator.ELEMENT_ATTRIBUTE_PREFIX; - - // auxFactory was not previously initialized. - // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX; - eAttr = OptionConverter.instantiateByKey( props, attrName, null ); - if ( eAttr == null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "No special ElementAttribute class defined for key [" + attrName + "], using default class." ); - } - - eAttr = defaultEAttr; - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Parsing options for '" + attrName + "'" ); - } - - PropertySetter.setProperties( eAttr, props, attrName + "." ); - // eAttr.setCacheName( regName ); - - if ( log.isDebugEnabled() ) - { - log.debug( "End of parsing for \"" + attrName + "\"." ); - } - - // GET CACHE FROM FACTORY WITH ATTRIBUTES - // eAttr.setCacheName( regName ); - return eAttr; - } - - /** - * Get an aux cache for the listed aux for a region. - *

- * @param props the configuration properties - * @param ccm Cache hub - * @param auxName the name of the auxiliary cache - * @param regName the name of the region. - * @return AuxiliaryCache - */ - protected AuxiliaryCache parseAuxiliary( Properties props, CompositeCacheManager ccm, - String auxName, String regName ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "parseAuxiliary " + auxName ); - } - - // GET CACHE - @SuppressWarnings("unchecked") // Common map for all caches - AuxiliaryCache auxCache = (AuxiliaryCache) ccm.getAuxiliaryCache(auxName, regName); - - if (auxCache == null) - { - // GET FACTORY - AuxiliaryCacheFactory auxFac = ccm.registryFacGet( auxName ); - if ( auxFac == null ) - { - // auxFactory was not previously initialized. - String prefix = AUXILIARY_PREFIX + auxName; - auxFac = OptionConverter.instantiateByKey( props, prefix, null ); - if ( auxFac == null ) - { - log.error( "Could not instantiate auxFactory named \"" + auxName + "\"." ); - return null; - } - - auxFac.setName( auxName ); - - if ( auxFac instanceof IRequireScheduler) - { - ((IRequireScheduler)auxFac).setScheduledExecutorService(ccm.getScheduledExecutorService()); - } - - auxFac.initialize(); - ccm.registryFacPut( auxFac ); - } - - // GET ATTRIBUTES - AuxiliaryCacheAttributes auxAttr = ccm.registryAttrGet( auxName ); - String attrName = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX; - if ( auxAttr == null ) - { - // auxFactory was not previously initialized. - String prefix = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX; - auxAttr = OptionConverter.instantiateByKey( props, prefix, null ); - if ( auxAttr == null ) - { - log.error( "Could not instantiate auxAttr named '" + attrName + "'" ); - return null; - } - auxAttr.setName( auxName ); - ccm.registryAttrPut( auxAttr ); - } - - auxAttr = auxAttr.clone(); - - if ( log.isDebugEnabled() ) - { - log.debug( "Parsing options for '" + attrName + "'" ); - } - - PropertySetter.setProperties( auxAttr, props, attrName + "." ); - auxAttr.setCacheName( regName ); - - if ( log.isDebugEnabled() ) - { - log.debug( "End of parsing for '" + attrName + "'" ); - } - - // GET CACHE FROM FACTORY WITH ATTRIBUTES - auxAttr.setCacheName( regName ); - - String auxPrefix = AUXILIARY_PREFIX + auxName; - - // CONFIGURE THE EVENT LOGGER - ICacheEventLogger cacheEventLogger = - AuxiliaryCacheConfigurator.parseCacheEventLogger( props, auxPrefix ); - - // CONFIGURE THE ELEMENT SERIALIZER - IElementSerializer elementSerializer = - AuxiliaryCacheConfigurator.parseElementSerializer( props, auxPrefix ); - - // CONFIGURE THE KEYMATCHER - //IKeyMatcher keyMatcher = parseKeyMatcher( props, auxPrefix ); - // TODO add to factory interface - - // Consider putting the compositeCache back in the factory interface - // since the manager may not know about it at this point. - // need to make sure the manager already has the cache - // before the auxiliary is created. - try - { - auxCache = auxFac.createCache( auxAttr, ccm, cacheEventLogger, elementSerializer ); - } - catch (Exception e) - { - log.error( "Could not instantiate auxiliary cache named \"" + regName + "\"." ); - return null; - } - - ccm.addAuxiliaryCache(auxName, regName, auxCache); - } - - return auxCache; - } - - /** - * Any property values will be replaced with system property values that match the key. - *

- * @param props - */ - protected static void overrideWithSystemProperties( Properties props ) - { - // override any setting with values from the system properties. - Properties sysProps = System.getProperties(); - for (String key : sysProps.stringPropertyNames()) - { - if ( key.startsWith( SYSTEM_PROPERTY_KEY_PREFIX ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Using system property [[" + key + "] [" + sysProps.getProperty( key ) + "]]" ); - } - props.setProperty( key, sysProps.getProperty( key ) ); - } - } - } - - /** - * Creates a custom key matcher if one is defined. Else, it uses the default. - *

- * @param props - * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName - * @return IKeyMatcher - */ - protected IKeyMatcher parseKeyMatcher( Properties props, String auxPrefix ) - { - - // auxFactory was not previously initialized. - String keyMatcherClassName = auxPrefix + KEY_MATCHER_PREFIX; - IKeyMatcher keyMatcher = OptionConverter.instantiateByKey( props, keyMatcherClassName, null ); - if ( keyMatcher != null ) - { - String attributePrefix = auxPrefix + KEY_MATCHER_PREFIX + ATTRIBUTE_PREFIX; - PropertySetter.setProperties( keyMatcher, props, attributePrefix + "." ); - if ( log.isInfoEnabled() ) - { - log.info( "Using custom key matcher [" + keyMatcher + "] for auxiliary [" + auxPrefix - + "]" ); - } - } - else - { - // use the default standard serializer - keyMatcher = new KeyMatcherPatternImpl(); - if ( log.isInfoEnabled() ) - { - log.info( "Using standard key matcher [" + keyMatcher + "] for auxiliary [" + auxPrefix + "]" ); - } - } - return keyMatcher; - } -} diff --git a/src/org/apache/commons/jcs/engine/control/CompositeCacheManager.java b/src/org/apache/commons/jcs/engine/control/CompositeCacheManager.java deleted file mode 100644 index e62cb9ac535..00000000000 --- a/src/org/apache/commons/jcs/engine/control/CompositeCacheManager.java +++ /dev/null @@ -1,986 +0,0 @@ -package org.apache.commons.jcs.engine.control; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.InputStream; -import java.lang.management.ManagementFactory; -import java.security.AccessControlException; -import java.util.ArrayList; -import java.util.Properties; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; - -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.admin.JCSAdminBean; -import org.apache.commons.jcs.auxiliary.AuxiliaryCache; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; -import org.apache.commons.jcs.auxiliary.AuxiliaryCacheFactory; -import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants; -import org.apache.commons.jcs.engine.CacheConstants; -import org.apache.commons.jcs.engine.CompositeCacheAttributes; -import org.apache.commons.jcs.engine.ElementAttributes; -import org.apache.commons.jcs.engine.behavior.ICache; -import org.apache.commons.jcs.engine.behavior.ICacheType.CacheType; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.behavior.IProvideScheduler; -import org.apache.commons.jcs.engine.behavior.IShutdownObserver; -import org.apache.commons.jcs.engine.control.event.ElementEventQueue; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue; -import org.apache.commons.jcs.engine.stats.CacheStats; -import org.apache.commons.jcs.engine.stats.behavior.ICacheStats; -import org.apache.commons.jcs.utils.config.OptionConverter; -import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory; -import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Manages a composite cache. This provides access to caches and is the primary way to shutdown the - * caching system as a whole. - *

- * The composite cache manager is responsible for creating / configuring cache regions. It serves as - * a factory for the ComositeCache class. The CompositeCache is the core of JCS, the hub for various - * auxiliaries. - */ -public class CompositeCacheManager - implements IRemoteCacheConstants, ICompositeCacheManager, IProvideScheduler -{ - /** The logger */ - private static final Log log = LogFactory.getLog( CompositeCacheManager.class ); - - /** JMX object name */ - public static final String JMX_OBJECT_NAME = "org.apache.commons.jcs:type=JCSAdminBean"; - - /** default region prefix */ - private static final String DEFAULT_REGION = "jcs.default"; - - /** Caches managed by this cache manager */ - private final ConcurrentMap> caches = - new ConcurrentHashMap>(); - - /** Lock for initialization of caches */ - private final ReentrantLock cacheLock = new ReentrantLock(); - - /** Number of clients accessing this cache manager */ - private final AtomicInteger clients = new AtomicInteger(0); - - /** Default cache attributes for this cache manager */ - private ICompositeCacheAttributes defaultCacheAttr = new CompositeCacheAttributes(); - - /** Default element attributes for this cache manager */ - private IElementAttributes defaultElementAttr = new ElementAttributes(); - - /** Used to keep track of configured auxiliaries */ - private final ConcurrentMap auxiliaryFactoryRegistry = - new ConcurrentHashMap( ); - - /** Used to keep track of attributes for auxiliaries. */ - private final ConcurrentMap auxiliaryAttributeRegistry = - new ConcurrentHashMap( ); - - /** Used to keep track of configured auxiliaries */ - private final ConcurrentMap> auxiliaryCaches = - new ConcurrentHashMap>( ); - - /** Properties with which this manager was configured. This is exposed for other managers. */ - private Properties configurationProperties; - - /** The default auxiliary caches to be used if not preconfigured */ - private String defaultAuxValues; - - /** The Singleton Instance */ - private static CompositeCacheManager instance; - - /** Should we use system property substitutions. */ - private static final boolean DEFAULT_USE_SYSTEM_PROPERTIES = true; - - /** Once configured, you can force a reconfiguration of sorts. */ - private static final boolean DEFAULT_FORCE_RECONFIGURATION = false; - - /** Stack for those waiting for notification of a shutdown. */ - private final LinkedBlockingDeque shutdownObservers = new LinkedBlockingDeque(); - - /** The central background scheduler. */ - private ScheduledExecutorService scheduledExecutor; - - /** The central event queue. */ - private IElementEventQueue elementEventQueue; - - /** Shutdown hook thread instance */ - private ShutdownHook shutdownHook; - - /** Indicates whether the instance has been initialized. */ - private boolean isInitialized = false; - - /** Indicates whether configure has been called. */ - private boolean isConfigured = false; - - /** Indicates whether JMX bean has been registered. */ - private boolean isJMXRegistered = false; - - private String jmxName = JMX_OBJECT_NAME; - - /** - * Gets the CacheHub instance. For backward compatibility, if this creates the instance it will - * attempt to configure it with the default configuration. If you want to configure from your - * own source, use {@link #getUnconfiguredInstance}and then call {@link #configure} - *

- * @return CompositeCacheManager - * @throws CacheException if the configuration cannot be loaded - */ - public static synchronized CompositeCacheManager getInstance() throws CacheException - { - return getInstance( CacheConstants.DEFAULT_CONFIG ); - } - - /** - * Initializes the cache manager using the props file for the given name. - *

- * @param propsFilename - * @return CompositeCacheManager configured from the give propsFileName - * @throws CacheException if the configuration cannot be loaded - */ - public static synchronized CompositeCacheManager getInstance( String propsFilename ) throws CacheException - { - if ( instance == null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Instance is null, creating with config [" + propsFilename + "]" ); - } - - instance = createInstance(); - } - - if (!instance.isInitialized()) - { - instance.initialize(); - } - - if (!instance.isConfigured()) - { - instance.configure( propsFilename ); - } - - instance.clients.incrementAndGet(); - - return instance; - } - - /** - * Get a CacheHub instance which is not configured. If an instance already exists, it will be - * returned. - *

- * @return CompositeCacheManager - */ - public static synchronized CompositeCacheManager getUnconfiguredInstance() - { - if ( instance == null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Instance is null, returning unconfigured instance" ); - } - - instance = createInstance(); - } - - if (!instance.isInitialized()) - { - instance.initialize(); - } - - instance.clients.incrementAndGet(); - - return instance; - } - - /** - * Simple factory method, must override in subclasses so getInstance creates / returns the - * correct object. - *

- * @return CompositeCacheManager - */ - protected static CompositeCacheManager createInstance() - { - return new CompositeCacheManager(); - } - - /** - * Default constructor - */ - protected CompositeCacheManager() - { - // empty - } - - /** Creates a shutdown hook and starts the scheduler service */ - protected void initialize() - { - if (!isInitialized) - { - this.shutdownHook = new ShutdownHook(); - try - { - Runtime.getRuntime().addShutdownHook( shutdownHook ); - } - catch ( AccessControlException e ) - { - log.error( "Could not register shutdown hook.", e ); - } - - this.scheduledExecutor = Executors.newScheduledThreadPool(4, - new DaemonThreadFactory("JCS-Scheduler-", Thread.MIN_PRIORITY)); - - // Register JMX bean - if (!isJMXRegistered && jmxName != null) - { - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - JCSAdminBean adminBean = new JCSAdminBean(this); - try - { - ObjectName jmxObjectName = new ObjectName(jmxName); - mbs.registerMBean(adminBean, jmxObjectName); - isJMXRegistered = true; - } - catch (Exception e) - { - log.warn( "Could not register JMX bean.", e ); - } - } - - this.elementEventQueue = new ElementEventQueue(); - - isInitialized = true; - } - } - - /** - * Get the element event queue - * - * @return the elementEventQueue - */ - public IElementEventQueue getElementEventQueue() - { - return elementEventQueue; - } - - /** - * Get the scheduler service - * - * @return the scheduledExecutor - */ - @Override - public ScheduledExecutorService getScheduledExecutorService() - { - return scheduledExecutor; - } - - /** - * Configure with default properties file - * @throws CacheException if the configuration cannot be loaded - */ - public void configure() throws CacheException - { - configure( CacheConstants.DEFAULT_CONFIG ); - } - - /** - * Configure from specific properties file. - *

- * @param propFile Path within classpath to load configuration from - * @throws CacheException if the configuration cannot be loaded - */ - public void configure( String propFile ) throws CacheException - { - log.info( "Creating cache manager from config file: " + propFile ); - - Properties props = new Properties(); - - InputStream is = getClass().getResourceAsStream( propFile ); - - if ( is != null ) - { - try - { - props.load( is ); - - if ( log.isDebugEnabled() ) - { - log.debug( "File [" + propFile + "] contained " + props.size() + " properties" ); - } - } - catch ( IOException ex ) - { - throw new CacheException("Failed to load properties for name [" + propFile + "]", ex); - } - finally - { - try - { - is.close(); - } - catch ( IOException ignore ) - { - // Ignored - } - } - } - else - { - throw new CacheException( "Failed to read configuration file [" + propFile + "]" ); - } - - configure( props ); - } - - /** - * Configure from properties object. - *

- * This method will call configure, instructing it to use system properties as a default. - * @param props - */ - public void configure( Properties props ) - { - configure( props, DEFAULT_USE_SYSTEM_PROPERTIES ); - } - - /** - * Configure from properties object, overriding with values from the system properties if - * instructed. - *

- * You can override a specific value by passing in a system property: - *

- * For example, you could override this value in the cache.ccf file by starting up your program - * with the argument: -Djcs.auxiliary.LTCP.attributes.TcpListenerPort=1111 - *

- * @param props - * @param useSystemProperties -- if true, values starting with jcs will be put into the props - * file prior to configuring the cache. - */ - public void configure( Properties props, boolean useSystemProperties ) - { - configure( props, useSystemProperties, DEFAULT_FORCE_RECONFIGURATION ); - } - - /** - * Configure from properties object, overriding with values from the system properties if - * instructed. - *

- * You can override a specific value by passing in a system property: - *

- * For example, you could override this value in the cache.ccf file by starting up your program - * with the argument: -Djcs.auxiliary.LTCP.attributes.TcpListenerPort=1111 - *

- * @param props - * @param useSystemProperties -- if true, values starting with jcs will be put into the props - * file prior to configuring the cache. - * @param forceReconfiguration - if the manager is already configured, we will try again. This - * may not work properly. - */ - public synchronized void configure( Properties props, boolean useSystemProperties, boolean forceReconfiguration ) - { - if ( props == null ) - { - log.error( "No properties found. Please configure the cache correctly." ); - return; - } - - if ( isConfigured ) - { - if ( !forceReconfiguration ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Configure called after the manager has been configured. " - + "Force reconfiguration is false. Doing nothing" ); - } - return; - } - else - { - if ( log.isInfoEnabled() ) - { - log.info( "Configure called after the manager has been configured. " - + "Force reconfiguration is true. Reconfiguring as best we can." ); - } - } - } - if ( useSystemProperties ) - { - CompositeCacheConfigurator.overrideWithSystemProperties( props ); - } - doConfigure( props ); - } - - /** - * Configure the cache using the supplied properties. - *

- * @param properties assumed not null - */ - private void doConfigure( Properties properties ) - { - // We will expose this for managers that need raw properties. - this.configurationProperties = properties; - - // set the props value and then configure the ThreadPoolManager - ThreadPoolManager.setProps( properties ); - ThreadPoolManager poolMgr = ThreadPoolManager.getInstance(); - if ( log.isDebugEnabled() ) - { - log.debug( "ThreadPoolManager = " + poolMgr ); - } - - // configure the cache - CompositeCacheConfigurator configurator = new CompositeCacheConfigurator(); - - long start = System.currentTimeMillis(); - - // set default value list - this.defaultAuxValues = OptionConverter.findAndSubst( CompositeCacheManager.DEFAULT_REGION, - properties ); - - log.info( "Setting default auxiliaries to " + this.defaultAuxValues ); - - // set default cache attr - this.defaultCacheAttr = configurator.parseCompositeCacheAttributes( properties, "", - new CompositeCacheAttributes(), DEFAULT_REGION ); - - log.info( "setting defaultCompositeCacheAttributes to " + this.defaultCacheAttr ); - - // set default element attr - this.defaultElementAttr = configurator.parseElementAttributes( properties, "", - new ElementAttributes(), DEFAULT_REGION ); - - log.info( "setting defaultElementAttributes to " + this.defaultElementAttr ); - - // set up system caches to be used by non system caches - // need to make sure there is no circularity of reference - configurator.parseSystemRegions( properties, this ); - - // setup preconfigured caches - configurator.parseRegions( properties, this ); - - long end = System.currentTimeMillis(); - if ( log.isInfoEnabled() ) - { - log.info( "Finished configuration in " + ( end - start ) + " ms." ); - } - - isConfigured = true; - } - - /** - * Gets the defaultCacheAttributes attribute of the CacheHub object - *

- * @return The defaultCacheAttributes value - */ - public ICompositeCacheAttributes getDefaultCacheAttributes() - { - return this.defaultCacheAttr.clone(); - } - - /** - * Gets the defaultElementAttributes attribute of the CacheHub object - *

- * @return The defaultElementAttributes value - */ - public IElementAttributes getDefaultElementAttributes() - { - return this.defaultElementAttr.clone(); - } - - /** - * Gets the cache attribute of the CacheHub object - *

- * @param cacheName - * @return CompositeCache -- the cache region controller - */ - @Override - public CompositeCache getCache( String cacheName ) - { - return getCache( cacheName, getDefaultCacheAttributes() ); - } - - /** - * Gets the cache attribute of the CacheHub object - *

- * @param cacheName - * @param cattr - * @return CompositeCache - */ - public CompositeCache getCache( String cacheName, ICompositeCacheAttributes cattr ) - { - cattr.setCacheName( cacheName ); - return getCache( cattr, getDefaultElementAttributes() ); - } - - /** - * Gets the cache attribute of the CacheHub object - *

- * @param cacheName - * @param cattr - * @param attr - * @return CompositeCache - */ - public CompositeCache getCache( String cacheName, ICompositeCacheAttributes cattr, IElementAttributes attr ) - { - cattr.setCacheName( cacheName ); - return getCache( cattr, attr ); - } - - /** - * Gets the cache attribute of the CacheHub object - *

- * @param cattr - * @return CompositeCache - */ - public CompositeCache getCache( ICompositeCacheAttributes cattr ) - { - return getCache( cattr, getDefaultElementAttributes() ); - } - - /** - * If the cache has already been created, then the CacheAttributes and the element Attributes - * will be ignored. Currently there is no overriding the CacheAttributes once it is set up. You - * can change the default ElementAttributes for a region later. - *

- * Overriding the default elemental attributes will require changing the way the attributes are - * assigned to elements. Get cache creates a cache with defaults if none are specified. We might - * want to create separate method for creating/getting. . . - *

- * @param cattr - * @param attr - * @return CompositeCache - */ - @SuppressWarnings("unchecked") // Need to cast because of common map for all caches - public CompositeCache getCache( ICompositeCacheAttributes cattr, IElementAttributes attr ) - { - CompositeCache cache; - - if ( log.isDebugEnabled() ) - { - log.debug( "attr = " + attr ); - } - - cache = (CompositeCache) caches.get( cattr.getCacheName() ); - - if (cache == null) - { - cacheLock.lock(); - - try - { - // double check - cache = (CompositeCache) caches.get( cattr.getCacheName() ); - - if ( cache == null ) - { - CompositeCacheConfigurator configurator = new CompositeCacheConfigurator(); - - cache = configurator.parseRegion( this.getConfigurationProperties(), this, cattr.getCacheName(), - this.defaultAuxValues, cattr ); - - caches.put( cattr.getCacheName(), cache ); - } - } - finally - { - cacheLock.unlock(); - } - } - - return cache; - } - - /** - * @param name - */ - public void freeCache( String name ) - { - freeCache( name, false ); - } - - /** - * @param name - * @param fromRemote - */ - public void freeCache( String name, boolean fromRemote ) - { - CompositeCache cache = (CompositeCache) caches.remove( name ); - - if ( cache != null ) - { - cache.dispose( fromRemote ); - } - } - - /** - * Calls freeCache on all regions - */ - public void shutDown() - { - synchronized (CompositeCacheManager.class) - { - // shutdown element event queue - this.elementEventQueue.dispose(); - - // shutdown all scheduled jobs - this.scheduledExecutor.shutdownNow(); - - // shutdown all thread pools - ThreadPoolManager.dispose(); - - // notify any observers - IShutdownObserver observer = null; - while ((observer = shutdownObservers.poll()) != null) - { - observer.shutdown(); - } - - // Unregister JMX bean - if (isJMXRegistered) - { - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - try - { - ObjectName jmxObjectName = new ObjectName(jmxName); - mbs.unregisterMBean(jmxObjectName); - } - catch (Exception e) - { - log.warn( "Could not unregister JMX bean.", e ); - } - - isJMXRegistered = false; - } - - // do the traditional shutdown of the regions. - for (String name : getCacheNames()) - { - freeCache( name ); - } - - // shut down factories - for (AuxiliaryCacheFactory factory : auxiliaryFactoryRegistry.values()) - { - factory.dispose(); - } - - auxiliaryAttributeRegistry.clear(); - auxiliaryFactoryRegistry.clear(); - - if (shutdownHook != null) - { - try - { - Runtime.getRuntime().removeShutdownHook(shutdownHook); - } - catch (IllegalStateException e) - { - // May fail if the JVM is already shutting down - } - - this.shutdownHook = null; - } - - isConfigured = false; - isInitialized = false; - } - } - - /** */ - public void release() - { - release( false ); - } - - /** - * @param fromRemote - */ - private void release( boolean fromRemote ) - { - synchronized ( CompositeCacheManager.class ) - { - // Wait until called by the last client - if ( clients.decrementAndGet() > 0 ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Release called, but " + clients + " remain" ); - } - return; - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Last client called release. There are " + caches.size() + " caches which will be disposed" ); - } - - for (ICache c : caches.values() ) - { - CompositeCache cache = (CompositeCache) c; - - if ( cache != null ) - { - cache.dispose( fromRemote ); - } - } - } - } - - /** - * Returns a list of the current cache names. - * @return String[] - */ - public String[] getCacheNames() - { - return caches.keySet().toArray(new String[caches.size()]); - } - - /** - * @return ICacheType.CACHE_HUB - */ - public CacheType getCacheType() - { - return CacheType.CACHE_HUB; - } - - /** - * @param auxFac - */ - public void registryFacPut( AuxiliaryCacheFactory auxFac ) - { - auxiliaryFactoryRegistry.put( auxFac.getName(), auxFac ); - } - - /** - * @param name - * @return AuxiliaryCacheFactory - */ - public AuxiliaryCacheFactory registryFacGet( String name ) - { - return auxiliaryFactoryRegistry.get( name ); - } - - /** - * @param auxAttr - */ - public void registryAttrPut( AuxiliaryCacheAttributes auxAttr ) - { - auxiliaryAttributeRegistry.put( auxAttr.getName(), auxAttr ); - } - - /** - * @param name - * @return AuxiliaryCacheAttributes - */ - public AuxiliaryCacheAttributes registryAttrGet( String name ) - { - return auxiliaryAttributeRegistry.get( name ); - } - - /** - * Add a cache to the map of registered caches - * - * @param cacheName the region name - * @param cache the cache instance - */ - public void addCache(String cacheName, ICache cache) - { - caches.put(cacheName, cache); - } - - /** - * Add a cache to the map of registered auxiliary caches - * - * @param auxName the auxiliary name - * @param cacheName the region name - * @param cache the cache instance - */ - public void addAuxiliaryCache(String auxName, String cacheName, AuxiliaryCache cache) - { - String key = String.format("aux.%s.region.%s", auxName, cacheName); - auxiliaryCaches.put(key, cache); - } - - /** - * Get a cache from the map of registered auxiliary caches - * - * @param auxName the auxiliary name - * @param cacheName the region name - * - * @return the cache instance - */ - @Override - @SuppressWarnings("unchecked") // because of common map for all auxiliary caches - public AuxiliaryCache getAuxiliaryCache(String auxName, String cacheName) - { - String key = String.format("aux.%s.region.%s", auxName, cacheName); - return (AuxiliaryCache) auxiliaryCaches.get(key); - } - - /** - * Gets stats for debugging. This calls gets statistics and then puts all the results in a - * string. This returns data for all regions. - *

- * @return String - */ - @Override - public String getStats() - { - ICacheStats[] stats = getStatistics(); - if ( stats == null ) - { - return "NONE"; - } - - // force the array elements into a string. - StringBuilder buf = new StringBuilder(); - int statsLen = stats.length; - for ( int i = 0; i < statsLen; i++ ) - { - buf.append( "\n---------------------------\n" ); - buf.append( stats[i] ); - } - return buf.toString(); - } - - /** - * This returns data gathered for all regions and all the auxiliaries they currently uses. - *

- * @return ICacheStats[] - */ - public ICacheStats[] getStatistics() - { - ArrayList cacheStats = new ArrayList(); - for (ICache c : caches.values()) - { - CompositeCache cache = (CompositeCache) c; - if ( cache != null ) - { - cacheStats.add( cache.getStatistics() ); - } - } - ICacheStats[] stats = cacheStats.toArray( new CacheStats[0] ); - return stats; - } - - /** - * Perhaps the composite cache itself should be the observable object. It doesn't make much of a - * difference. There are some problems with region by region shutdown. Some auxiliaries are - * global. They will need to track when every region has shutdown before doing things like - * closing the socket with a lateral. - *

- * @param observer - */ - @Override - public void registerShutdownObserver( IShutdownObserver observer ) - { - if (!shutdownObservers.contains(observer)) - { - shutdownObservers.push( observer ); - } - else - { - log.warn("Shutdown observer added twice " + observer); - } - } - - /** - * @param observer - */ - @Override - public void deregisterShutdownObserver( IShutdownObserver observer ) - { - shutdownObservers.remove( observer ); - } - - /** - * This is exposed so other manager can get access to the props. - *

- * @return the configurationProperties - */ - @Override - public Properties getConfigurationProperties() - { - return configurationProperties; - } - - /** - * @return the isInitialized - */ - public boolean isInitialized() - { - return isInitialized; - } - - /** - * @return the isConfigured - */ - public boolean isConfigured() - { - return isConfigured; - } - - public void setJmxName(final String name) - { - if (isJMXRegistered) - { - throw new IllegalStateException("Too late, MBean registration is done"); - } - jmxName = name; - } - - /** - * Called on shutdown. This gives use a chance to store the keys and to optimize even if the - * cache manager's shutdown method was not called manually. - */ - class ShutdownHook - extends Thread - { - /** - * This will persist the keys on shutdown. - *

- * @see java.lang.Thread#run() - */ - @SuppressWarnings("synthetic-access") - @Override - public void run() - { - if ( isInitialized() ) - { - log.info( "Shutdown hook activated. Shutdown was not called. Shutting down JCS." ); - shutDown(); - } - } - } -} diff --git a/src/org/apache/commons/jcs/engine/control/event/ElementEvent.java b/src/org/apache/commons/jcs/engine/control/event/ElementEvent.java deleted file mode 100644 index e25a6033a71..00000000000 --- a/src/org/apache/commons/jcs/engine/control/event/ElementEvent.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.apache.commons.jcs.engine.control.event; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.EventObject; - -import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent; - -/** - * Element events will trigger the creation of Element Event objects. This is a wrapper around the - * cache element that indicates the event triggered. - */ -public class ElementEvent - extends EventObject - implements IElementEvent -{ - /** Don't change */ - private static final long serialVersionUID = -5364117411457467056L; - - /** default event code */ - private ElementEventType elementEvent = ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND; - - /** - * Constructor for the ElementEvent object - *

- * @param source The Cache Element - * @param elementEvent The event id defined in the enum class. - */ - public ElementEvent( T source, ElementEventType elementEvent ) - { - super( source ); - this.elementEvent = elementEvent; - } - - /** - * Gets the elementEvent attribute of the ElementEvent object - *

- * @return The elementEvent value. The List of values is defined in ElementEventType. - */ - @Override - public ElementEventType getElementEvent() - { - return elementEvent; - } - - /** - * @return the source of the event. - */ - @SuppressWarnings("unchecked") // Generified - @Override - public T getSource() - { - return (T) super.getSource(); - - } -} diff --git a/src/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java b/src/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java deleted file mode 100644 index 44ab5739ea7..00000000000 --- a/src/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.apache.commons.jcs.engine.control.event; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.concurrent.ExecutorService; - -import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler; -import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue; -import org.apache.commons.jcs.utils.threadpool.PoolConfiguration; -import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy; -import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * An event queue is used to propagate ordered cache events to one and only one target listener. - */ -public class ElementEventQueue - implements IElementEventQueue -{ - private static final String THREAD_PREFIX = "JCS-ElementEventQueue-"; - - /** The logger */ - private static final Log log = LogFactory.getLog( ElementEventQueue.class ); - - /** shutdown or not */ - private boolean destroyed = false; - - /** The worker thread pool. */ - private ExecutorService queueProcessor; - - /** - * Constructor for the ElementEventQueue object - */ - public ElementEventQueue() - { - queueProcessor = ThreadPoolManager.getInstance().createPool( - new PoolConfiguration(false, 0, 1, 1, 0, WhenBlockedPolicy.RUN, 1), THREAD_PREFIX); - - if ( log.isDebugEnabled() ) - { - log.debug( "Constructed: " + this ); - } - } - - /** - * Dispose queue - */ - @Override - public void dispose() - { - if ( !destroyed ) - { - destroyed = true; - - // synchronize on queue so the thread will not wait forever, - // and then interrupt the QueueProcessor - queueProcessor.shutdownNow(); - queueProcessor = null; - - if ( log.isInfoEnabled() ) - { - log.info( "Element event queue destroyed: " + this ); - } - } - } - - /** - * Adds an ElementEvent to be handled - * @param hand The IElementEventHandler - * @param event The IElementEventHandler IElementEvent event - * @throws IOException - */ - @Override - public void addElementEvent( IElementEventHandler hand, IElementEvent event ) - throws IOException - { - - if ( log.isDebugEnabled() ) - { - log.debug( "Adding Event Handler to QUEUE, !destroyed = " + !destroyed ); - } - - if (destroyed) - { - log.warn("Event submitted to disposed element event queue " + event); - } - else - { - ElementEventRunner runner = new ElementEventRunner( hand, event ); - - if ( log.isDebugEnabled() ) - { - log.debug( "runner = " + runner ); - } - - queueProcessor.execute(runner); - } - } - - // /////////////////////////// Inner classes ///////////////////////////// - - /** - * Retries before declaring failure. - */ - protected abstract class AbstractElementEventRunner - implements Runnable - { - /** - * Main processing method for the AbstractElementEvent object - */ - @SuppressWarnings("synthetic-access") - @Override - public void run() - { - try - { - doRun(); - // happy and done. - } - catch ( IOException e ) - { - // Too bad. The handler has problems. - log.warn( "Giving up element event handling " + ElementEventQueue.this, e ); - } - } - - /** - * This will do the work or trigger the work to be done. - *

- * @throws IOException - */ - protected abstract void doRun() - throws IOException; - } - - /** - * ElementEventRunner. - */ - private class ElementEventRunner - extends AbstractElementEventRunner - { - /** the handler */ - private final IElementEventHandler hand; - - /** event */ - private final IElementEvent event; - - /** - * Constructor for the PutEvent object. - *

- * @param hand - * @param event - * @throws IOException - */ - @SuppressWarnings("synthetic-access") - ElementEventRunner( IElementEventHandler hand, IElementEvent event ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "Constructing " + this ); - } - this.hand = hand; - this.event = event; - } - - /** - * Tells the handler to handle the event. - *

- * @throws IOException - */ - @Override - protected void doRun() - throws IOException - { - hand.handleElementEvent( event ); - } - } -} diff --git a/src/org/apache/commons/jcs/engine/control/event/behavior/ElementEventType.java b/src/org/apache/commons/jcs/engine/control/event/behavior/ElementEventType.java deleted file mode 100644 index 52b0fe8fe3c..00000000000 --- a/src/org/apache/commons/jcs/engine/control/event/behavior/ElementEventType.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.apache.commons.jcs.engine.control.event.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This describes the events that an item can encounter. - */ -public enum ElementEventType -{ - /** Background expiration */ - EXCEEDED_MAXLIFE_BACKGROUND, - - /*** Expiration discovered on request */ - EXCEEDED_MAXLIFE_ONREQUEST, - - /** Background expiration */ - EXCEEDED_IDLETIME_BACKGROUND, - - /** Expiration discovered on request */ - EXCEEDED_IDLETIME_ONREQUEST, - - /** Moving from memory to disk (what if no disk?) */ - SPOOLED_DISK_AVAILABLE, - - /** Moving from memory to disk (what if no disk?) */ - SPOOLED_DISK_NOT_AVAILABLE, - - /** Moving from memory to disk, but item is not spoolable */ - SPOOLED_NOT_ALLOWED //, - - /** Removed actively by a remove command. (Could distinguish between local and remote) */ - //REMOVED, - /** - * Element was requested from cache. Not sure we ever want to implement this. - */ - //GET -} diff --git a/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEvent.java b/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEvent.java deleted file mode 100644 index 74b9c7f2c0b..00000000000 --- a/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEvent.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.apache.commons.jcs.engine.control.event.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * Defines how an element event object should behave. - */ -public interface IElementEvent - extends Serializable -{ - /** - * Gets the elementEvent attribute of the IElementEvent object. This code is Contained in the - * IElememtEventConstants class. - *

- * @return The elementEvent value - */ - ElementEventType getElementEvent(); - - /** - * @return the source of the event. - */ - T getSource(); -} diff --git a/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEventHandler.java b/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEventHandler.java deleted file mode 100644 index 3aed8b79b36..00000000000 --- a/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEventHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.apache.commons.jcs.engine.control.event.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This interface defines the behavior for event handler. Event handlers are - * transient. They are not replicated and are not written to disk. - *

- * If you want an event handler by default for all elements in a region, then - * you can add it to the default element attributes. This way it will get created - * whenever an item gets put into the cache. - * - */ -public interface IElementEventHandler -{ - /** - * Handle events for this element. The events are typed. - * - * @param event - * The event created by the cache. - */ - void handleElementEvent( IElementEvent event ); -} diff --git a/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEventQueue.java b/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEventQueue.java deleted file mode 100644 index fc5f84e83cb..00000000000 --- a/src/org/apache/commons/jcs/engine/control/event/behavior/IElementEventQueue.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.apache.commons.jcs.engine.control.event.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -/** - * Interface for an element event queue. An event queue is used to propagate - * ordered element events in one region. - * - */ -public interface IElementEventQueue -{ - /** - * Adds an ElementEvent to be handled - * - * @param hand - * The IElementEventHandler - * @param event - * The IElementEventHandler IElementEvent event - * @throws IOException - */ - void addElementEvent( IElementEventHandler hand, IElementEvent event ) - throws IOException; - - /** - * Destroy the event queue - * - */ - void dispose(); -} diff --git a/src/org/apache/commons/jcs/engine/control/group/GroupAttrName.java b/src/org/apache/commons/jcs/engine/control/group/GroupAttrName.java deleted file mode 100644 index 8da08eb677c..00000000000 --- a/src/org/apache/commons/jcs/engine/control/group/GroupAttrName.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.apache.commons.jcs.engine.control.group; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * Description of the Class - */ -public class GroupAttrName - implements Serializable -{ - /** Don't change */ - private static final long serialVersionUID = 1586079686300744198L; - - /** Description of the Field */ - public final GroupId groupId; - - /** the name of the attribute */ - public final T attrName; - - /** Cached toString value */ - private String toString; - - /** - * Constructor for the GroupAttrName object - * @param groupId - * @param attrName - */ - public GroupAttrName( GroupId groupId, T attrName ) - { - this.groupId = groupId; - this.attrName = attrName; - - if ( groupId == null ) - { - throw new IllegalArgumentException( "groupId must not be null." ); - } - } - - /** - * Tests object equality. - * @param obj The GroupAttrName instance to test. - * @return Whether equal. - */ - @Override - public boolean equals( Object obj ) - { - if ( obj == null || !( obj instanceof GroupAttrName ) ) - { - return false; - } - GroupAttrName to = (GroupAttrName) obj; - - if (groupId.equals( to.groupId )) - { - if (attrName == null && to.attrName == null) - { - return true; - } - else if (attrName == null || to.attrName == null) - { - return false; - } - - return attrName.equals( to.attrName ); - } - - return false; - } - - /** - * @return A hash code based on the hash code of @ #groupid} and {@link #attrName}. - */ - @Override - public int hashCode() - { - if (attrName == null) - { - return groupId.hashCode(); - } - - return groupId.hashCode() ^ attrName.hashCode(); - } - - /** - * @return the cached value. - */ - @Override - public String toString() - { - if ( toString == null ) - { - toString = "[GAN: groupId=" + groupId + ", attrName=" + attrName + "]"; - } - - return toString; - } - -} diff --git a/src/org/apache/commons/jcs/engine/control/group/GroupId.java b/src/org/apache/commons/jcs/engine/control/group/GroupId.java deleted file mode 100644 index 5bdd83a9d54..00000000000 --- a/src/org/apache/commons/jcs/engine/control/group/GroupId.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.apache.commons.jcs.engine.control.group; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * Used to avoid name conflict when group cache items are mixed with non-group cache items in the - * same cache. - */ -public class GroupId - implements Serializable -{ - /** Don't change. */ - private static final long serialVersionUID = 4626368486444860133L; - - /** Description of the Field */ - public final String groupName; - - /** the name of the region. */ - public final String cacheName; - - /** Cached toString value. */ - private String toString; - - /** - * Constructor for the GroupId object - *

- * @param cacheName - * @param groupName - */ - public GroupId( String cacheName, String groupName ) - { - this.cacheName = cacheName; - this.groupName = groupName; - - if ( cacheName == null ) - { - throw new IllegalArgumentException( "cacheName must not be null." ); - } - if ( groupName == null ) - { - throw new IllegalArgumentException( "groupName must not be null." ); - } - } - - /** - * @param obj - * @return cacheName.equals( g.cacheName ) &&groupName.equals( g.groupName ); - */ - @Override - public boolean equals( Object obj ) - { - if ( obj == null || !( obj instanceof GroupId ) ) - { - return false; - } - GroupId g = (GroupId) obj; - return cacheName.equals( g.cacheName ) && groupName.equals( g.groupName ); - } - - /** - * @return cacheName.hashCode() + groupName.hashCode(); - */ - @Override - public int hashCode() - { - return cacheName.hashCode() + groupName.hashCode(); - } - - /** - * Caches the value. - *

- * @return debugging string. - */ - @Override - public String toString() - { - if ( toString == null ) - { - toString = "[groupId=" + cacheName + ", " + groupName + ']'; - } - - return toString; - } -} diff --git a/src/org/apache/commons/jcs/engine/control/package.html b/src/org/apache/commons/jcs/engine/control/package.html deleted file mode 100644 index 82b9a4c0e67..00000000000 --- a/src/org/apache/commons/jcs/engine/control/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - The primary cache classes and the hub. - - diff --git a/src/org/apache/commons/jcs/engine/logging/CacheEvent.java b/src/org/apache/commons/jcs/engine/logging/CacheEvent.java deleted file mode 100644 index c07ecacdd86..00000000000 --- a/src/org/apache/commons/jcs/engine/logging/CacheEvent.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.apache.commons.jcs.engine.logging; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; - -import java.util.Date; - -/** It's returned from create and passed into log. */ -public class CacheEvent - implements ICacheEvent -{ - /** Don't change. */ - private static final long serialVersionUID = -5913139566421714330L; - - /** The time at which this object was created. */ - private final long createTime = System.currentTimeMillis(); - - /** The auxiliary or other source of the event. */ - private String source; - - /** The cache region */ - private String region; - - /** The event name: update, get, remove, etc. */ - private String eventName; - - /** disk location, ip, etc. */ - private String optionalDetails; - - /** The key that was put or retrieved. */ - private K key; - - /** - * @param source the source to set - */ - @Override - public void setSource( String source ) - { - this.source = source; - } - - /** - * @return the source - */ - @Override - public String getSource() - { - return source; - } - - /** - * @param region the region to set - */ - @Override - public void setRegion( String region ) - { - this.region = region; - } - - /** - * @return the region - */ - @Override - public String getRegion() - { - return region; - } - - /** - * @param eventName the eventName to set - */ - @Override - public void setEventName( String eventName ) - { - this.eventName = eventName; - } - - /** - * @return the eventName - */ - @Override - public String getEventName() - { - return eventName; - } - - /** - * @param optionalDetails the optionalDetails to set - */ - @Override - public void setOptionalDetails( String optionalDetails ) - { - this.optionalDetails = optionalDetails; - } - - /** - * @return the optionalDetails - */ - @Override - public String getOptionalDetails() - { - return optionalDetails; - } - - /** - * @param key the key to set - */ - @Override - public void setKey( K key ) - { - this.key = key; - } - - /** - * @return the key - */ - @Override - public K getKey() - { - return key; - } - - /** - * The time at which this object was created. - *

- * @return the createTime - */ - public long getCreateTime() - { - return createTime; - } - - /** - * @return reflection toString - */ - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append("CacheEvent: ").append(eventName).append(" Created: ").append(new Date(createTime)); - if (source != null) - { - sb.append(" Source: ").append(source); - } - if (region != null) - { - sb.append(" Region: ").append(region); - } - if (key != null) - { - sb.append(" Key: ").append(key); - } - if (optionalDetails != null) - { - sb.append(" Details: ").append(optionalDetails); - } - return sb.toString(); - } -} diff --git a/src/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLogger.java b/src/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLogger.java deleted file mode 100644 index e38a9c5419b..00000000000 --- a/src/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLogger.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.apache.commons.jcs.engine.logging; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; -import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This implementation simple logs to a commons logger at debug level, for all events. It's mainly - * for testing. It isn't very useful otherwise. - */ -public class CacheEventLoggerDebugLogger - implements ICacheEventLogger -{ - /** This is the name of the category. */ - private String logCategoryName = CacheEventLoggerDebugLogger.class.getName(); - - /** The logger. This is recreated on set logCategoryName */ - private Log log = LogFactory.getLog( logCategoryName ); - - /** - * @param source - * @param region - * @param eventName - * @param optionalDetails - * @param key - * @return ICacheEvent - */ - @Override - public ICacheEvent createICacheEvent( String source, String region, String eventName, - String optionalDetails, T key ) - { - ICacheEvent event = new CacheEvent(); - event.setSource( source ); - event.setRegion( region ); - event.setEventName( eventName ); - event.setOptionalDetails( optionalDetails ); - event.setKey( key ); - - return event; - } - - /** - * @param source - * @param eventName - * @param optionalDetails - */ - @Override - public void logApplicationEvent( String source, String eventName, String optionalDetails ) - { - if ( log.isDebugEnabled() ) - { - log.debug( source + " | " + eventName + " | " + optionalDetails ); - } - } - - /** - * @param source - * @param eventName - * @param errorMessage - */ - @Override - public void logError( String source, String eventName, String errorMessage ) - { - if ( log.isDebugEnabled() ) - { - log.debug( source + " | " + eventName + " | " + errorMessage ); - } - } - - /** - * @param event - */ - @Override - public void logICacheEvent( ICacheEvent event ) - { - if ( log.isDebugEnabled() ) - { - log.debug( event ); - } - } - - /** - * @param logCategoryName - */ - public synchronized void setLogCategoryName( String logCategoryName ) - { - if ( logCategoryName != null && !logCategoryName.equals( this.logCategoryName ) ) - { - this.logCategoryName = logCategoryName; - log = LogFactory.getLog( logCategoryName ); - } - } -} diff --git a/src/org/apache/commons/jcs/engine/logging/behavior/ICacheEvent.java b/src/org/apache/commons/jcs/engine/logging/behavior/ICacheEvent.java deleted file mode 100644 index 82238f2acb5..00000000000 --- a/src/org/apache/commons/jcs/engine/logging/behavior/ICacheEvent.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.apache.commons.jcs.engine.logging.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** Defines the common fields required by a cache event. */ -public interface ICacheEvent - extends Serializable -{ - /** - * @param source the source to set - */ - void setSource( String source ); - - /** - * @return the source - */ - String getSource(); - - /** - * @param region the region to set - */ - void setRegion( String region ); - - /** - * @return the region - */ - String getRegion(); - - /** - * @param eventName the eventName to set - */ - void setEventName( String eventName ); - - /** - * @return the eventName - */ - String getEventName(); - - /** - * @param optionalDetails the optionalDetails to set - */ - void setOptionalDetails( String optionalDetails ); - - /** - * @return the optionalDetails - */ - String getOptionalDetails(); - - /** - * @param key the key to set - */ - void setKey( K key ); - - /** - * @return the key - */ - K getKey(); -} diff --git a/src/org/apache/commons/jcs/engine/logging/behavior/ICacheEventLogger.java b/src/org/apache/commons/jcs/engine/logging/behavior/ICacheEventLogger.java deleted file mode 100644 index 7b08c67e976..00000000000 --- a/src/org/apache/commons/jcs/engine/logging/behavior/ICacheEventLogger.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.apache.commons.jcs.engine.logging.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This defines the behavior for event logging. Auxiliaries will send events to injected event - * loggers. - *

- * In general all ICache interface methods should call the logger if one is configured. This will be - * done on an ad hoc basis for now. Various auxiliaries may have additional events. - */ -public interface ICacheEventLogger -{ - // TODO: Use enum - /** ICache update */ - String UPDATE_EVENT = "update"; - - /** ICache get */ - String GET_EVENT = "get"; - - /** ICache getMultiple */ - String GETMULTIPLE_EVENT = "getMultiple"; - - /** ICache getMatching */ - String GETMATCHING_EVENT = "getMatching"; - - /** ICache remove */ - String REMOVE_EVENT = "remove"; - - /** ICache removeAll */ - String REMOVEALL_EVENT = "removeAll"; - - /** ICache dispose */ - String DISPOSE_EVENT = "dispose"; - - /** ICache enqueue. The time in the queue. */ - //String ENQUEUE_EVENT = "enqueue"; - /** - * Creates an event. - *

- * @param source - e.g. RemoteCacheServer - * @param region - the name of the region - * @param eventName - e.g. update, get, put, remove - * @param optionalDetails - any extra message - * @param key - the cache key - * @return ICacheEvent - */ - ICacheEvent createICacheEvent( String source, String region, - String eventName, String optionalDetails, T key ); - - /** - * Logs an event. - *

- * @param event - the event created in createICacheEvent - */ - void logICacheEvent( ICacheEvent event ); - - /** - * Logs an event. These are internal application events that do not correspond to ICache calls. - *

- * @param source - e.g. RemoteCacheServer - * @param eventName - e.g. update, get, put, remove - * @param optionalDetails - any extra message - */ - void logApplicationEvent( String source, String eventName, String optionalDetails ); - - /** - * Logs an error. - *

- * @param source - e.g. RemoteCacheServer - * @param eventName - e.g. update, get, put, remove - * @param errorMessage - any error message - */ - void logError( String source, String eventName, String errorMessage ); -} diff --git a/src/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpl.java b/src/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpl.java deleted file mode 100644 index 4bd235a08c7..00000000000 --- a/src/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.apache.commons.jcs.engine.match; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher; - -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** This implementation of the KeyMatcher uses standard Java Pattern matching. */ -public class KeyMatcherPatternImpl - implements IKeyMatcher -{ - /** Serial version */ - private static final long serialVersionUID = 6667352064144381264L; - - /** - * Creates a pattern and find matches on the array. - *

- * @param pattern - * @param keyArray - * @return Set of the matching keys - */ - @Override - public Set getMatchingKeysFromArray( String pattern, Set keyArray ) - { - Pattern compiledPattern = Pattern.compile( pattern ); - - Set matchingKeys = new HashSet(); - - // Look for matches - for (K key : keyArray) - { - // TODO we might want to match on the toString. - if ( key instanceof String ) - { - Matcher matcher = compiledPattern.matcher( (String) key ); - if ( matcher.matches() ) - { - matchingKeys.add( key ); - } - } - } - - return matchingKeys; - } -} diff --git a/src/org/apache/commons/jcs/engine/match/behavior/IKeyMatcher.java b/src/org/apache/commons/jcs/engine/match/behavior/IKeyMatcher.java deleted file mode 100644 index 74e9d0103bb..00000000000 --- a/src/org/apache/commons/jcs/engine/match/behavior/IKeyMatcher.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.apache.commons.jcs.engine.match.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; -import java.util.Set; - -/** Key matchers need to implement this interface. */ -public interface IKeyMatcher extends Serializable -{ - /** - * Creates a pattern and find matches on the array. - *

- * @param pattern - * @param keyArray - * @return Set of the matching keys - */ - Set getMatchingKeysFromArray( String pattern, Set keyArray ); -} diff --git a/src/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java deleted file mode 100644 index 5f85104f6d9..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java +++ /dev/null @@ -1,524 +0,0 @@ -package org.apache.commons.jcs.engine.memory; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.group.GroupAttrName; -import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.jcs.utils.struct.DoubleLinkedList; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class contains methods that are common to memory caches using the double linked list, such - * as the LRU, MRU, FIFO, and LIFO caches. - *

- * Children can control the expiration algorithm by controlling the update and get. The last item in the list will be the one - * removed when the list fills. For instance LRU should more items to the front as they are used. FIFO should simply add new items - * to the front of the list. - */ -public abstract class AbstractDoubleLinkedListMemoryCache extends AbstractMemoryCache -{ - /** The logger. */ - private static final Log log = LogFactory.getLog(AbstractDoubleLinkedListMemoryCache.class); - - /** thread-safe double linked list for lru */ - protected DoubleLinkedList> list; // TODO privatise - - /** - * For post reflection creation initialization. - *

- * - * @param hub - */ - @Override - public void initialize(CompositeCache hub) - { - super.initialize(hub); - list = new DoubleLinkedList>(); - log.info("initialized MemoryCache for " + getCacheName()); - } - - /** - * This is called by super initialize. - * - * NOTE: should return a thread safe map - * - *

- * - * @return new ConcurrentHashMap() - */ - @Override - public ConcurrentMap> createMap() - { - return new ConcurrentHashMap>(); - } - - /** - * Calls the abstract method updateList. - *

- * If the max size is reached, an element will be put to disk. - *

- * - * @param ce - * The cache element, or entry wrapper - * @throws IOException - */ - @Override - public final void update(ICacheElement ce) throws IOException - { - putCnt.incrementAndGet(); - - lock.lock(); - try - { - MemoryElementDescriptor newNode = adjustListForUpdate(ce); - - // this should be synchronized if we were not using a ConcurrentHashMap - final K key = newNode.getCacheElement().getKey(); - MemoryElementDescriptor oldNode = map.put(key, newNode); - - // If the node was the same as an existing node, remove it. - if (oldNode != null && key.equals(oldNode.getCacheElement().getKey())) - { - list.remove(oldNode); - } - } - finally - { - lock.unlock(); - } - - // If we are over the max spool some - spoolIfNeeded(); - } - - /** - * Children implement this to control the cache expiration algorithm - *

- * - * @param ce - * @return MemoryElementDescriptor the new node - * @throws IOException - */ - protected abstract MemoryElementDescriptor adjustListForUpdate(ICacheElement ce) throws IOException; - - /** - * If the max size has been reached, spool. - *

- * - * @throws Error - */ - private void spoolIfNeeded() throws Error - { - int size = map.size(); - // If the element limit is reached, we need to spool - - if (size <= this.getCacheAttributes().getMaxObjects()) - { - return; - } - - if (log.isDebugEnabled()) - { - log.debug("In memory limit reached, spooling"); - } - - // Write the last 'chunkSize' items to disk. - int chunkSizeCorrected = Math.min(size, chunkSize); - - if (log.isDebugEnabled()) - { - log.debug("About to spool to disk cache, map size: " + size + ", max objects: " - + this.getCacheAttributes().getMaxObjects() + ", maximum items to spool: " + chunkSizeCorrected); - } - - // The spool will put them in a disk event queue, so there is no - // need to pre-queue the queuing. This would be a bit wasteful - // and wouldn't save much time in this synchronous call. - lock.lock(); - - try - { - for (int i = 0; i < chunkSizeCorrected; i++) - { - ICacheElement lastElement = spoolLastElement(); - if (lastElement == null) - { - break; - } - } - - // If this is out of the sync block it can detect a mismatch - // where there is none. - if (log.isDebugEnabled() && map.size() != list.size()) - { - log.debug("update: After spool, size mismatch: map.size() = " + map.size() + ", linked list size = " + list.size()); - } - } - finally - { - lock.unlock(); - } - - if (log.isDebugEnabled()) - { - log.debug("update: After spool map size: " + map.size() + " linked list size = " + list.size()); - } - } - - /** - * This instructs the memory cache to remove the numberToFree according to its eviction - * policy. For example, the LRUMemoryCache will remove the numberToFree least recently - * used items. These will be spooled to disk if a disk auxiliary is available. - *

- * - * @param numberToFree - * @return the number that were removed. if you ask to free 5, but there are only 3, you will - * get 3. - * @throws IOException - */ - @Override - public int freeElements(int numberToFree) throws IOException - { - int freed = 0; - - lock.lock(); - - try - { - for (; freed < numberToFree; freed++) - { - ICacheElement element = spoolLastElement(); - if (element == null) - { - break; - } - } - } - finally - { - lock.unlock(); - } - - return freed; - } - - /** - * This spools the last element in the LRU, if one exists. - *

- * - * @return ICacheElement<K, V> if there was a last element, else null. - * @throws Error - */ - private ICacheElement spoolLastElement() throws Error - { - ICacheElement toSpool = null; - - final MemoryElementDescriptor last = list.getLast(); - if (last != null) - { - toSpool = last.getCacheElement(); - if (toSpool != null) - { - getCompositeCache().spoolToDisk(toSpool); - if (map.remove(toSpool.getKey()) == null) - { - log.warn("update: remove failed for key: " + toSpool.getKey()); - - if (log.isDebugEnabled()) - { - verifyCache(); - } - } - } - else - { - throw new Error("update: last.ce is null!"); - } - - list.remove(last); - } - - return toSpool; - } - - /** - * @see org.apache.commons.jcs.engine.memory.AbstractMemoryCache#get(java.lang.Object) - */ - @Override - public ICacheElement get(K key) throws IOException - { - ICacheElement ce = super.get(key); - - if (log.isDebugEnabled()) - { - verifyCache(); - } - - return ce; - } - - /** - * Adjust the list as needed for a get. This allows children to control the algorithm - *

- * - * @param me - */ - protected abstract void adjustListForGet(MemoryElementDescriptor me); - - /** - * Update control structures after get - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - @Override - protected void lockedGetElement(MemoryElementDescriptor me) - { - adjustListForGet(me); - } - - /** - * Remove element from control structure - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - @Override - protected void lockedRemoveElement(MemoryElementDescriptor me) - { - list.remove(me); - } - - /** - * Removes all cached items from the cache control structures. - * (guarded by the lock) - */ - @Override - protected void lockedRemoveAll() - { - list.removeAll(); - } - - // --------------------------- internal methods (linked list implementation) - /** - * Adds a new node to the start of the link list. - *

- * - * @param ce - * The feature to be added to the First - * @return MemoryElementDescriptor - */ - protected MemoryElementDescriptor addFirst(ICacheElement ce) - { - lock.lock(); - try - { - MemoryElementDescriptor me = new MemoryElementDescriptor(ce); - list.addFirst(me); - if ( log.isDebugEnabled() ) - { - verifyCache(ce.getKey()); - } - return me; - } - finally - { - lock.unlock(); - } - } - - /** - * Adds a new node to the end of the link list. - *

- * - * @param ce - * The feature to be added to the First - * @return MemoryElementDescriptor - */ - protected MemoryElementDescriptor addLast(ICacheElement ce) - { - lock.lock(); - try - { - MemoryElementDescriptor me = new MemoryElementDescriptor(ce); - list.addLast(me); - if ( log.isDebugEnabled() ) - { - verifyCache(ce.getKey()); - } - return me; - } - finally - { - lock.unlock(); - } - } - - // ---------------------------------------------------------- debug methods - - /** - * Dump the cache entries from first to list for debugging. - */ - @SuppressWarnings("unchecked") - // No generics for public fields - private void dumpCacheEntries() - { - log.debug("dumpingCacheEntries"); - for (MemoryElementDescriptor me = list.getFirst(); me != null; me = (MemoryElementDescriptor) me.next) - { - log.debug("dumpCacheEntries> key=" + me.getCacheElement().getKey() + ", val=" + me.getCacheElement().getVal()); - } - } - - /** - * Checks to see if all the items that should be in the cache are. Checks consistency between - * List and map. - */ - @SuppressWarnings("unchecked") - // No generics for public fields - private void verifyCache() - { - boolean found = false; - log.debug("verifycache[" + getCacheName() + "]: mapContains " + map.size() + " elements, linked list contains " - + list.size() + " elements"); - log.debug("verifycache: checking linked list by key "); - for (MemoryElementDescriptor li = list.getFirst(); li != null; li = (MemoryElementDescriptor) li.next) - { - K key = li.getCacheElement().getKey(); - if (!map.containsKey(key)) - { - log.error("verifycache[" + getCacheName() + "]: map does not contain key : " + key); - log.error("key class=" + key.getClass()); - log.error("key hashcode=" + key.hashCode()); - log.error("key toString=" + key.toString()); - if (key instanceof GroupAttrName) - { - GroupAttrName name = (GroupAttrName) key; - log.error("GroupID hashcode=" + name.groupId.hashCode()); - log.error("GroupID.class=" + name.groupId.getClass()); - log.error("AttrName hashcode=" + name.attrName.hashCode()); - log.error("AttrName.class=" + name.attrName.getClass()); - } - dumpMap(); - } - else if (map.get(key) == null) - { - log.error("verifycache[" + getCacheName() + "]: linked list retrieval returned null for key: " + key); - } - } - - log.debug("verifycache: checking linked list by value "); - for (MemoryElementDescriptor li3 = list.getFirst(); li3 != null; li3 = (MemoryElementDescriptor) li3.next) - { - if (map.containsValue(li3) == false) - { - log.error("verifycache[" + getCacheName() + "]: map does not contain value : " + li3); - dumpMap(); - } - } - - log.debug("verifycache: checking via keysets!"); - for (Object val : map.keySet()) - { - found = false; - - for (MemoryElementDescriptor li2 = list.getFirst(); li2 != null; li2 = (MemoryElementDescriptor) li2.next) - { - if (val.equals(li2.getCacheElement().getKey())) - { - found = true; - break; - } - } - if (!found) - { - log.error("verifycache[" + getCacheName() + "]: key not found in list : " + val); - dumpCacheEntries(); - if (map.containsKey(val)) - { - log.error("verifycache: map contains key"); - } - else - { - log.error("verifycache: map does NOT contain key, what the HECK!"); - } - } - } - } - - /** - * Logs an error if an element that should be in the cache is not. - *

- * - * @param key - */ - @SuppressWarnings("unchecked") - // No generics for public fields - private void verifyCache(K key) - { - boolean found = false; - - // go through the linked list looking for the key - for (MemoryElementDescriptor li = list.getFirst(); li != null; li = (MemoryElementDescriptor) li.next) - { - if (li.getCacheElement().getKey() == key) - { - found = true; - log.debug("verifycache(key) key match: " + key); - break; - } - } - if (!found) - { - log.error("verifycache(key)[" + getCacheName() + "], couldn't find key! : " + key); - } - } - - /** - * This returns semi-structured information on the memory cache, such as the size, put count, - * hit count, and miss count. - *

- * - * @see org.apache.commons.jcs.engine.memory.behavior.IMemoryCache#getStatistics() - */ - @Override - public IStats getStatistics() - { - IStats stats = super.getStatistics(); - stats.setTypeName( /* add algorithm name */"Memory Cache"); - - List> elems = stats.getStatElements(); - - elems.add(new StatElement("List Size", Integer.valueOf(list.size()))); - - return stats; - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java deleted file mode 100644 index dc4bf5c5b85..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java +++ /dev/null @@ -1,523 +0,0 @@ -package org.apache.commons.jcs.engine.memory; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.jcs.engine.CacheConstants; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.group.GroupAttrName; -import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache; -import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This base includes some common code for memory caches. - */ -public abstract class AbstractMemoryCache - implements IMemoryCache -{ - /** Log instance */ - private static final Log log = LogFactory.getLog( AbstractMemoryCache.class ); - - /** Cache Attributes. Regions settings. */ - private ICompositeCacheAttributes cacheAttributes; - - /** The cache region this store is associated with */ - private CompositeCache cache; - - /** How many to spool at a time. */ - protected int chunkSize; - - protected final Lock lock = new ReentrantLock(); - - /** Map where items are stored by key. This is created by the concrete child class. */ - protected Map> map;// TODO privatise - - /** number of hits */ - protected AtomicLong hitCnt; - - /** number of misses */ - protected AtomicLong missCnt; - - /** number of puts */ - protected AtomicLong putCnt; - - /** - * For post reflection creation initialization - *

- * @param hub - */ - @Override - public void initialize( CompositeCache hub ) - { - hitCnt = new AtomicLong(0); - missCnt = new AtomicLong(0); - putCnt = new AtomicLong(0); - - this.cacheAttributes = hub.getCacheAttributes(); - this.chunkSize = cacheAttributes.getSpoolChunkSize(); - this.cache = hub; - - this.map = createMap(); - } - - /** - * Children must implement this method. A FIFO implementation may use a tree map. An LRU might - * use a hashtable. The map returned should be threadsafe. - *

- * @return a threadsafe Map - */ - public abstract Map> createMap(); - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no - * data in cache for any of these keys - * @throws IOException - */ - @Override - public Map> getMultiple( Set keys ) - throws IOException - { - Map> elements = new HashMap>(); - - if ( keys != null && !keys.isEmpty() ) - { - for (K key : keys) - { - ICacheElement element = get( key ); - - if ( element != null ) - { - elements.put( key, element ); - } - } - } - - return elements; - } - - /** - * Get an item from the cache without affecting its last access time or position. Not all memory - * cache implementations can get quietly. - *

- * @param key Identifies item to find - * @return Element matching key if found, or null - * @throws IOException - */ - @Override - public ICacheElement getQuiet( K key ) - throws IOException - { - ICacheElement ce = null; - - MemoryElementDescriptor me = map.get( key ); - if ( me != null ) - { - if ( log.isDebugEnabled() ) - { - log.debug( getCacheName() + ": MemoryCache quiet hit for " + key ); - } - - ce = me.getCacheElement(); - } - else if ( log.isDebugEnabled() ) - { - log.debug( getCacheName() + ": MemoryCache quiet miss for " + key ); - } - - return ce; - } - - /** - * Puts an item to the cache. - *

- * @param ce Description of the Parameter - * @throws IOException Description of the Exception - */ - @Override - public abstract void update( ICacheElement ce ) - throws IOException; - - /** - * Removes all cached items from the cache. - *

- * @throws IOException - */ - @Override - public void removeAll() throws IOException - { - lock.lock(); - try - { - lockedRemoveAll(); - map.clear(); - } - finally - { - lock.unlock(); - } - } - - /** - * Removes all cached items from the cache control structures. - * (guarded by the lock) - */ - protected abstract void lockedRemoveAll(); - - /** - * Prepares for shutdown. Reset statistics - *

- * @throws IOException - */ - @Override - public void dispose() - throws IOException - { - removeAll(); - hitCnt.set(0); - missCnt.set(0); - putCnt.set(0); - log.info( "Memory Cache dispose called." ); - } - - /** - * @return statistics about the cache - */ - @Override - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "Abstract Memory Cache" ); - - ArrayList> elems = new ArrayList>(); - stats.setStatElements(elems); - - elems.add(new StatElement("Put Count", putCnt)); - elems.add(new StatElement("Hit Count", hitCnt)); - elems.add(new StatElement("Miss Count", missCnt)); - elems.add(new StatElement( "Map Size", Integer.valueOf(getSize()) ) ); - - return stats; - } - - /** - * Returns the current cache size. - *

- * @return The size value - */ - @Override - public int getSize() - { - return this.map.size(); - } - - /** - * Returns the cache (aka "region") name. - *

- * @return The cacheName value - */ - public String getCacheName() - { - String attributeCacheName = this.cacheAttributes.getCacheName(); - if(attributeCacheName != null) - { - return attributeCacheName; - } - return cache.getCacheName(); - } - - /** - * Puts an item to the cache. - *

- * @param ce the item - */ - @Override - public void waterfal( ICacheElement ce ) - { - this.cache.spoolToDisk( ce ); - } - - // ---------------------------------------------------------- debug method - /** - * Dump the cache map for debugging. - */ - public void dumpMap() - { - log.debug( "dumpingMap" ); - for (Map.Entry> e : map.entrySet()) - { - MemoryElementDescriptor me = e.getValue(); - log.debug( "dumpMap> key=" + e.getKey() + ", val=" + me.getCacheElement().getVal() ); - } - } - - /** - * Returns the CacheAttributes. - *

- * @return The CacheAttributes value - */ - @Override - public ICompositeCacheAttributes getCacheAttributes() - { - return this.cacheAttributes; - } - - /** - * Sets the CacheAttributes. - *

- * @param cattr The new CacheAttributes value - */ - @Override - public void setCacheAttributes( ICompositeCacheAttributes cattr ) - { - this.cacheAttributes = cattr; - } - - /** - * Gets the cache hub / region that the MemoryCache is used by - *

- * @return The cache value - */ - @Override - public CompositeCache getCompositeCache() - { - return this.cache; - } - - /** - * Remove all keys of the same group hierarchy. - * @param key the key - * @return true if something has been removed - */ - protected boolean removeByGroup(K key) - { - boolean removed = false; - - // remove all keys of the same group hierarchy. - for (Iterator>> itr = map.entrySet().iterator(); itr.hasNext();) - { - Map.Entry> entry = itr.next(); - K k = entry.getKey(); - - if (k instanceof GroupAttrName && ((GroupAttrName) k).groupId.equals(((GroupAttrName) key).groupId)) - { - lock.lock(); - try - { - itr.remove(); - lockedRemoveElement(entry.getValue()); - removed = true; - } - finally - { - lock.unlock(); - } - } - } - - return removed; - } - - /** - * Remove all keys of the same name hierarchy. - * - * @param key the key - * @return true if something has been removed - */ - protected boolean removeByHierarchy(K key) - { - boolean removed = false; - - // remove all keys of the same name hierarchy. - for (Iterator>> itr = map.entrySet().iterator(); itr.hasNext();) - { - Map.Entry> entry = itr.next(); - K k = entry.getKey(); - - if (k instanceof String && ((String) k).startsWith(key.toString())) - { - lock.lock(); - try - { - itr.remove(); - lockedRemoveElement(entry.getValue()); - removed = true; - } - finally - { - lock.unlock(); - } - } - } - - return removed; - } - - /** - * Remove element from control structure - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - protected abstract void lockedRemoveElement(MemoryElementDescriptor me); - - /** - * Removes an item from the cache. This method handles hierarchical removal. If the key is a - * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys - * starting with the argument String will be removed. - *

- * - * @param key - * @return true if the removal was successful - * @throws IOException - */ - @Override - public boolean remove(K key) throws IOException - { - if (log.isDebugEnabled()) - { - log.debug("removing item for key: " + key); - } - - boolean removed = false; - - // handle partial removal - if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER)) - { - removed = removeByHierarchy(key); - } - else if (key instanceof GroupAttrName && ((GroupAttrName) key).attrName == null) - { - removed = removeByGroup(key); - } - else - { - // remove single item. - lock.lock(); - try - { - MemoryElementDescriptor me = map.remove(key); - if (me != null) - { - lockedRemoveElement(me); - removed = true; - } - } - finally - { - lock.unlock(); - } - } - - return removed; - } - - /** - * Get an Array of the keys for all elements in the memory cache - * - * @return An Object[] - */ - @Override - public Set getKeySet() - { - return new LinkedHashSet(map.keySet()); - } - - /** - * Get an item from the cache. - *

- * - * @param key Identifies item to find - * @return ICacheElement<K, V> if found, else null - * @throws IOException - */ - @Override - public ICacheElement get(K key) throws IOException - { - ICacheElement ce = null; - - if (log.isDebugEnabled()) - { - log.debug(getCacheName() + ": getting item for key " + key); - } - - MemoryElementDescriptor me = map.get(key); - - if (me != null) - { - hitCnt.incrementAndGet(); - ce = me.getCacheElement(); - - lock.lock(); - try - { - lockedGetElement(me); - } - finally - { - lock.unlock(); - } - - if (log.isDebugEnabled()) - { - log.debug(getCacheName() + ": MemoryCache hit for " + key); - } - } - else - { - missCnt.incrementAndGet(); - - if (log.isDebugEnabled()) - { - log.debug(getCacheName() + ": MemoryCache miss for " + key); - } - } - - return ce; - } - - /** - * Update control structures after get - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - protected abstract void lockedGetElement(MemoryElementDescriptor me); -} diff --git a/src/org/apache/commons/jcs/engine/memory/behavior/IMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/behavior/IMemoryCache.java deleted file mode 100644 index 3ac2f4b287a..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/behavior/IMemoryCache.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.apache.commons.jcs.engine.memory.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.stats.behavior.IStats; - -import java.io.IOException; -import java.util.Map; -import java.util.Set; - -/** For the framework. Insures methods a MemoryCache needs to access. */ -public interface IMemoryCache -{ - /** - * Initialize the memory cache - *

- * @param cache The cache (region) this memory store is attached to. - */ - void initialize( CompositeCache cache ); - - /** - * Destroy the memory cache - *

- * @throws IOException - */ - void dispose() - throws IOException; - - /** - * Get the number of elements contained in the memory store - *

- * @return Element count - */ - int getSize(); - - /** - * Returns the historical and statistical data for a region's memory cache. - *

- * @return Statistics and Info for the Memory Cache. - */ - IStats getStatistics(); - - /** - * Get a set of the keys for all elements in the memory cache. - *

- * @return a set of the key type - * TODO This should probably be done in chunks with a range passed in. This - * will be a problem if someone puts a 1,000,000 or so items in a - * region. - */ - Set getKeySet(); - - /** - * Removes an item from the cache - *

- * @param key - * Identifies item to be removed - * @return Description of the Return Value - * @throws IOException - * Description of the Exception - */ - boolean remove( K key ) - throws IOException; - - /** - * Removes all cached items from the cache. - *

- * @throws IOException - * Description of the Exception - */ - void removeAll() - throws IOException; - - /** - * This instructs the memory cache to remove the numberToFree - * according to its eviction policy. For example, the LRUMemoryCache will - * remove the numberToFree least recently used items. These will be - * spooled to disk if a disk auxiliary is available. - *

- * @param numberToFree - * @return the number that were removed. if you ask to free 5, but there are - * only 3, you will get 3. - * @throws IOException - */ - int freeElements( int numberToFree ) - throws IOException; - - /** - * Get an item from the cache - *

- * @param key - * Description of the Parameter - * @return Description of the Return Value - * @throws IOException - * Description of the Exception - */ - ICacheElement get( K key ) - throws IOException; - - /** - * Gets multiple items from the cache based on the given set of keys. - *

- * @param keys - * @return a map of K key to ICacheElement<K, V> element, or an empty map - * if there is no data in cache for any of these keys - * @throws IOException - */ - Map> getMultiple( Set keys ) - throws IOException; - - /** - * Get an item from the cache without effecting its order or last access - * time - *

- * @param key - * Description of the Parameter - * @return The quiet value - * @throws IOException - * Description of the Exception - */ - ICacheElement getQuiet( K key ) - throws IOException; - - /** - * Spools the item contained in the provided element to disk - *

- * @param ce - * Description of the Parameter - * @throws IOException - * Description of the Exception - */ - void waterfal( ICacheElement ce ) - throws IOException; - - /** - * Puts an item to the cache. - *

- * @param ce - * Description of the Parameter - * @throws IOException - * Description of the Exception - */ - void update( ICacheElement ce ) - throws IOException; - - /** - * Returns the CacheAttributes for the region. - *

- * @return The cacheAttributes value - */ - ICompositeCacheAttributes getCacheAttributes(); - - /** - * Sets the CacheAttributes of the region. - *

- * @param cattr - * The new cacheAttributes value - */ - void setCacheAttributes( ICompositeCacheAttributes cattr ); - - /** - * Gets the cache hub / region that uses the MemoryCache. - *

- * @return The cache value - */ - CompositeCache getCompositeCache(); -} diff --git a/src/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCache.java deleted file mode 100644 index 00f48f92794..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCache.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.apache.commons.jcs.engine.memory.fifo; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.memory.AbstractDoubleLinkedListMemoryCache; -import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; - -/** - * The items are spooled in the order they are added. No adjustments to the list are made on get. - */ -public class FIFOMemoryCache - extends AbstractDoubleLinkedListMemoryCache -{ - /** - * Puts an item to the cache. Removes any pre-existing entries of the same key from the linked - * list and adds this one first. - *

- * @param ce The cache element, or entry wrapper - * @return MemoryElementDescriptor the new node - * @throws IOException - */ - @Override - protected MemoryElementDescriptor adjustListForUpdate( ICacheElement ce ) - throws IOException - { - return addFirst( ce ); - } - - /** - * Does nothing. - *

- * @param me - */ - @Override - protected void adjustListForGet( MemoryElementDescriptor me ) - { - // DO NOTHING - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java deleted file mode 100644 index 2679fb79c1a..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.apache.commons.jcs.engine.memory.lru; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.util.Collections; -import java.util.Map; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.memory.AbstractMemoryCache; -import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This is a test memory manager using the jdk1.4 LinkedHashMap. - */ -public class LHMLRUMemoryCache - extends AbstractMemoryCache -{ - /** The Logger. */ - private static final Log log = LogFactory.getLog( LRUMemoryCache.class ); - - /** - * For post reflection creation initialization - *

- * @param hub - */ - @Override - public void initialize( CompositeCache hub ) - { - super.initialize( hub ); - log.info( "initialized LHMLRUMemoryCache for " + getCacheName() ); - } - - /** - * Returns a synchronized LHMSpooler - *

- * @return Collections.synchronizedMap( new LHMSpooler() ) - */ - @Override - public Map> createMap() - { - return Collections.synchronizedMap( new LHMSpooler() ); - } - - /** - * Puts an item to the cache. - *

- * @param ce Description of the Parameter - * @throws IOException - */ - @Override - public void update( ICacheElement ce ) - throws IOException - { - putCnt.incrementAndGet(); - map.put( ce.getKey(), new MemoryElementDescriptor(ce) ); - } - - /** - * Update control structures after get - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - @Override - protected void lockedGetElement(MemoryElementDescriptor me) - { - // empty - } - - /** - * Remove element from control structure - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - @Override - protected void lockedRemoveElement(MemoryElementDescriptor me) - { - // empty - } - - /** - * Removes all cached items from the cache control structures. - * (guarded by the lock) - */ - @Override - protected void lockedRemoveAll() - { - // empty - } - - /** - * This returns semi-structured information on the memory cache, such as the size, put count, - * hit count, and miss count. - *

- * @return IStats - */ - @Override - public IStats getStatistics() - { - IStats stats = super.getStatistics(); - stats.setTypeName( "LHMLRU Memory Cache" ); - - return stats; - } - - // ---------------------------------------------------------- debug methods - - /** - * Dump the cache entries from first to last for debugging. - */ - public void dumpCacheEntries() - { - dumpMap(); - } - - /** - * This can't be implemented. - *

- * @param numberToFree - * @return 0 - * @throws IOException - */ - @Override - public int freeElements( int numberToFree ) - throws IOException - { - // can't be implemented using the LHM - return 0; - } - - // ---------------------------------------------------------- extended map - - /** - * Implementation of removeEldestEntry in LinkedHashMap - */ - protected class LHMSpooler - extends java.util.LinkedHashMap> - { - /** Don't change. */ - private static final long serialVersionUID = -1255907868906762484L; - - /** - * Initialize to a small size--for now, 1/2 of max 3rd variable "true" indicates that it - * should be access and not time governed. This could be configurable. - */ - public LHMSpooler() - { - super( (int) ( getCacheAttributes().getMaxObjects() * .5 ), .75F, true ); - } - - /** - * Remove eldest. Automatically called by LinkedHashMap. - *

- * @param eldest - * @return true if removed - */ - @SuppressWarnings("synthetic-access") - @Override - protected boolean removeEldestEntry( Map.Entry> eldest ) - { - ICacheElement element = eldest.getValue().getCacheElement(); - - if ( size() <= getCacheAttributes().getMaxObjects() ) - { - return false; - } - else - { - - if ( log.isDebugEnabled() ) - { - log.debug( "LHMLRU max size: " + getCacheAttributes().getMaxObjects() - + ". Spooling element, key: " + element.getKey() ); - } - - waterfal( element ); - - if ( log.isDebugEnabled() ) - { - log.debug( "LHMLRU size: " + map.size() ); - } - } - return true; - } - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCache.java deleted file mode 100644 index a9eb4de8bd2..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCache.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.apache.commons.jcs.engine.memory.lru; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.memory.AbstractDoubleLinkedListMemoryCache; -import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; - -/** - * A fast reference management system. The least recently used items move to the end of the list and - * get spooled to disk if the cache hub is configured to use a disk cache. Most of the cache - * bottlenecks are in IO. There are no io bottlenecks here, it's all about processing power. - *

- * Even though there are only a few adjustments necessary to maintain the double linked list, we - * might want to find a more efficient memory manager for large cache regions. - *

- * The LRUMemoryCache is most efficient when the first element is selected. The smaller the region, - * the better the chance that this will be the case. < .04 ms per put, p3 866, 1/10 of that per get - */ -public class LRUMemoryCache - extends AbstractDoubleLinkedListMemoryCache -{ - /** - * Puts an item to the cache. Removes any pre-existing entries of the same key from the linked - * list and adds this one first. - *

- * @param ce The cache element, or entry wrapper - * @return MemoryElementDescriptor the new node - * @throws IOException - */ - @Override - protected MemoryElementDescriptor adjustListForUpdate( ICacheElement ce ) - throws IOException - { - return addFirst( ce ); - } - - /** - * Makes the item the first in the list. - *

- * @param me - */ - @Override - protected void adjustListForGet( MemoryElementDescriptor me ) - { - list.makeFirst( me ); - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/lru/package.html b/src/org/apache/commons/jcs/engine/memory/lru/package.html deleted file mode 100644 index af2bde561f5..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/lru/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - The primary memory plugin using a 'least recently used' removal policy. - - diff --git a/src/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCache.java deleted file mode 100644 index 3638fd95cf4..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCache.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.apache.commons.jcs.engine.memory.mru; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.memory.AbstractDoubleLinkedListMemoryCache; -import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; - -/** - * The most recently used items move to the front of the list and get spooled to disk if the cache - * hub is configured to use a disk cache. - */ -public class MRUMemoryCache - extends AbstractDoubleLinkedListMemoryCache -{ - /** - * Adds the item to the front of the list. A put doesn't count as a usage. - *

- * It's not clear if the put operation should be different. Perhaps this should remove the oldest - * if full, and then put. - *

- * @param ce - * @return MemoryElementDescriptor the new node - * @throws IOException - */ - @Override - protected MemoryElementDescriptor adjustListForUpdate( ICacheElement ce ) - throws IOException - { - return addFirst( ce ); - } - - /** - * Makes the item the last in the list. - *

- * @param me - */ - @Override - protected void adjustListForGet( MemoryElementDescriptor me ) - { - list.makeLast( me ); - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/mru/package.html b/src/org/apache/commons/jcs/engine/memory/mru/package.html deleted file mode 100644 index 2377c2debc9..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/mru/package.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - A memory plugin implemented using a 'most recently used' removal policy. - In general this is slow and should not be used. - - diff --git a/src/org/apache/commons/jcs/engine/memory/package.html b/src/org/apache/commons/jcs/engine/memory/package.html deleted file mode 100644 index 47f02c23324..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - Parent package for memory type plugins. - - diff --git a/src/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThread.java b/src/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThread.java deleted file mode 100644 index 4de3b3a1f8a..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThread.java +++ /dev/null @@ -1,221 +0,0 @@ -package org.apache.commons.jcs.engine.memory.shrinking; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Set; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.IElementAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType; -import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A background memory shrinker. Memory problems and concurrent modification exception caused by - * acting directly on an iterator of the underlying memory cache should have been solved. - * @version $Id: ShrinkerThread.java 1719092 2015-12-10 15:07:30Z tv $ - */ -public class ShrinkerThread - implements Runnable -{ - /** The logger */ - private static final Log log = LogFactory.getLog( ShrinkerThread.class ); - - /** The CompositeCache instance which this shrinker is watching */ - private final CompositeCache cache; - - /** Maximum memory idle time for the whole cache */ - private final long maxMemoryIdleTime; - - /** Maximum number of items to spool per run. Default is -1, or no limit. */ - private final int maxSpoolPerRun; - - /** Should we limit the number spooled per run. If so, the maxSpoolPerRun will be used. */ - private boolean spoolLimit = false; - - /** - * Constructor for the ShrinkerThread object. - *

- * @param cache The MemoryCache which the new shrinker should watch. - */ - public ShrinkerThread( CompositeCache cache ) - { - super(); - - this.cache = cache; - - long maxMemoryIdleTimeSeconds = cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds(); - - if ( maxMemoryIdleTimeSeconds < 0 ) - { - this.maxMemoryIdleTime = -1; - } - else - { - this.maxMemoryIdleTime = maxMemoryIdleTimeSeconds * 1000; - } - - this.maxSpoolPerRun = cache.getCacheAttributes().getMaxSpoolPerRun(); - if ( this.maxSpoolPerRun != -1 ) - { - this.spoolLimit = true; - } - - } - - /** - * Main processing method for the ShrinkerThread object - */ - @Override - public void run() - { - shrink(); - } - - /** - * This method is called when the thread wakes up. First the method obtains an array of keys for - * the cache region. It iterates through the keys and tries to get the item from the cache - * without affecting the last access or position of the item. The item is checked for - * expiration, the expiration check has 3 parts: - *

    - *
  1. Has the cacheattributes.MaxMemoryIdleTimeSeconds defined for the region been exceeded? If - * so, the item should be move to disk.
  2. Has the item exceeded MaxLifeSeconds defined in - * the element attributes? If so, remove it.
  3. Has the item exceeded IdleTime defined in - * the element attributes? If so, remove it. If there are event listeners registered for the - * cache element, they will be called.
  4. - *
- * TODO Change element event handling to use the queue, then move the queue to the region and - * access via the Cache. - */ - protected void shrink() - { - if ( log.isDebugEnabled() ) - { - log.debug( "Shrinking memory cache for: " + this.cache.getCacheName() ); - } - - IMemoryCache memCache = cache.getMemoryCache(); - - try - { - Set keys = memCache.getKeySet(); - int size = keys.size(); - if ( log.isDebugEnabled() ) - { - log.debug( "Keys size: " + size ); - } - - ICacheElement cacheElement; - IElementAttributes attributes; - - int spoolCount = 0; - - for (K key : keys) - { - cacheElement = memCache.getQuiet( key ); - - if ( cacheElement == null ) - { - continue; - } - - attributes = cacheElement.getElementAttributes(); - - boolean remove = false; - - long now = System.currentTimeMillis(); - - // If the element is not eternal, check if it should be - // removed and remove it if so. - if ( !cacheElement.getElementAttributes().getIsEternal() ) - { - remove = cache.isExpired( cacheElement, now, - ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND, - ElementEventType.EXCEEDED_IDLETIME_BACKGROUND ); - - if ( remove ) - { - memCache.remove( cacheElement.getKey() ); - } - } - - // If the item is not removed, check is it has been idle - // long enough to be spooled. - - if ( !remove && maxMemoryIdleTime != -1 ) - { - if ( !spoolLimit || spoolCount < this.maxSpoolPerRun ) - { - final long lastAccessTime = attributes.getLastAccessTime(); - - if ( lastAccessTime + maxMemoryIdleTime < now ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Exceeded memory idle time: " + cacheElement.getKey() ); - } - - // Shouldn't we ensure that the element is - // spooled before removing it from memory? - // No the disk caches have a purgatory. If it fails - // to spool that does not affect the - // responsibilities of the memory cache. - - spoolCount++; - - memCache.remove( cacheElement.getKey() ); - - memCache.waterfal( cacheElement ); - - key = null; - cacheElement = null; - } - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "spoolCount = '" + spoolCount + "'; " + "maxSpoolPerRun = '" + maxSpoolPerRun - + "'" ); - } - - // stop processing if limit has been reached. - if ( spoolLimit && spoolCount >= this.maxSpoolPerRun ) - { - return; - } - } - } - } - } - catch ( Throwable t ) - { - log.info( "Unexpected trouble in shrink cycle", t ); - - // concurrent modifications should no longer be a problem - // It is up to the IMemoryCache to return an array of keys - - // stop for now - return; - } - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java b/src/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java deleted file mode 100644 index b5c703b4086..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java +++ /dev/null @@ -1,239 +0,0 @@ -package org.apache.commons.jcs.engine.memory.soft; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.lang.ref.SoftReference; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.LinkedBlockingQueue; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; -import org.apache.commons.jcs.engine.control.CompositeCache; -import org.apache.commons.jcs.engine.memory.AbstractMemoryCache; -import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; -import org.apache.commons.jcs.engine.memory.util.SoftReferenceElementDescriptor; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A JCS IMemoryCache that has {@link SoftReference} to all its values. - * This cache does not respect {@link ICompositeCacheAttributes#getMaxObjects()} - * as overflowing is handled by Java GC. - *

- * The cache also has strong references to a maximum number of objects given by - * the maxObjects parameter - * - * @author halset - */ -public class SoftReferenceMemoryCache extends AbstractMemoryCache -{ - /** The logger. */ - private static final Log log = LogFactory.getLog(SoftReferenceMemoryCache.class); - - /** - * Strong references to the maxObjects number of newest objects. - *

- * Trimming is done by {@link #trimStrongReferences()} instead of by - * overriding removeEldestEntry to be able to control waterfalling as easy - * as possible - */ - private LinkedBlockingQueue> strongReferences; - - /** - * For post reflection creation initialization - *

- * @param hub - */ - @Override - public synchronized void initialize( CompositeCache hub ) - { - super.initialize( hub ); - strongReferences = new LinkedBlockingQueue>(); - log.info( "initialized Soft Reference Memory Cache for " + getCacheName() ); - } - - /** - * @see org.apache.commons.jcs.engine.memory.AbstractMemoryCache#createMap() - */ - @Override - public ConcurrentMap> createMap() - { - return new ConcurrentHashMap>(); - } - - /** - * @see org.apache.commons.jcs.engine.memory.behavior.IMemoryCache#getKeySet() - */ - @Override - public Set getKeySet() - { - Set keys = new HashSet(); - for (Map.Entry> e : map.entrySet()) - { - SoftReferenceElementDescriptor sred = (SoftReferenceElementDescriptor) e.getValue(); - if (sred.getCacheElement() != null) - { - keys.add(e.getKey()); - } - } - - return keys; - } - - /** - * Returns the current cache size. - *

- * @return The size value - */ - @Override - public int getSize() - { - int size = 0; - for (MemoryElementDescriptor me : map.values()) - { - SoftReferenceElementDescriptor sred = (SoftReferenceElementDescriptor) me; - if (sred.getCacheElement() != null) - { - size++; - } - } - return size; - } - - /** - * @return statistics about the cache - */ - @Override - public IStats getStatistics() - { - IStats stats = super.getStatistics(); - stats.setTypeName("Soft Reference Memory Cache"); - - List> elems = stats.getStatElements(); - int emptyrefs = map.size() - getSize(); - elems.add(new StatElement("Empty References", Integer.valueOf(emptyrefs))); - elems.add(new StatElement("Strong References", Integer.valueOf(strongReferences.size()))); - - return stats; - } - - /** - * Update control structures after get - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - @Override - protected void lockedGetElement(MemoryElementDescriptor me) - { - ICacheElement val = me.getCacheElement(); - val.getElementAttributes().setLastAccessTimeNow(); - - // update the ordering of the strong references - strongReferences.add(val); - trimStrongReferences(); - } - - /** - * Remove element from control structure - * (guarded by the lock) - * - * @param me the memory element descriptor - */ - @Override - protected void lockedRemoveElement(MemoryElementDescriptor me) - { - strongReferences.remove(me.getCacheElement()); - } - - /** - * Removes all cached items from the cache control structures. - * (guarded by the lock) - */ - @Override - protected void lockedRemoveAll() - { - strongReferences.clear(); - } - - /** - * Puts an item to the cache. - *

- * @param ce Description of the Parameter - * @throws IOException Description of the Exception - */ - @Override - public void update(ICacheElement ce) throws IOException - { - putCnt.incrementAndGet(); - ce.getElementAttributes().setLastAccessTimeNow(); - - lock.lock(); - - try - { - map.put(ce.getKey(), new SoftReferenceElementDescriptor(ce)); - strongReferences.add(ce); - trimStrongReferences(); - } - finally - { - lock.unlock(); - } - } - - /** - * Trim the number of strong references to equal or below the number given - * by the maxObjects parameter. - */ - private void trimStrongReferences() - { - int max = getCacheAttributes().getMaxObjects(); - int startsize = strongReferences.size(); - - for (int cursize = startsize; cursize > max; cursize--) - { - ICacheElement ce = strongReferences.poll(); - waterfal(ce); - } - } - - /** - * This can't be implemented. - *

- * @param numberToFree - * @return 0 - * @throws IOException - */ - @Override - public int freeElements(int numberToFree) throws IOException - { - return 0; - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/soft/package.html b/src/org/apache/commons/jcs/engine/memory/soft/package.html deleted file mode 100644 index 526c18aa048..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/soft/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - A memory plugin implemented using soft references. - - diff --git a/src/org/apache/commons/jcs/engine/memory/util/MemoryElementDescriptor.java b/src/org/apache/commons/jcs/engine/memory/util/MemoryElementDescriptor.java deleted file mode 100644 index 613f2b5a44f..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/util/MemoryElementDescriptor.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.apache.commons.jcs.engine.memory.util; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.utils.struct.DoubleLinkedListNode; - -/** - * This wrapper is needed for double linked lists. - */ -public class MemoryElementDescriptor - extends DoubleLinkedListNode> -{ - /** Don't change */ - private static final long serialVersionUID = -1905161209035522460L; - - /** - * Constructs a usable MemoryElementDescriptor. - *

- * @param ce - */ - public MemoryElementDescriptor( ICacheElement ce ) - { - super( ce ); - } - - /** - * Get the cache element - * - * @return the ce - */ - public ICacheElement getCacheElement() - { - return getPayload(); - } -} diff --git a/src/org/apache/commons/jcs/engine/memory/util/SoftReferenceElementDescriptor.java b/src/org/apache/commons/jcs/engine/memory/util/SoftReferenceElementDescriptor.java deleted file mode 100644 index 32050e7aded..00000000000 --- a/src/org/apache/commons/jcs/engine/memory/util/SoftReferenceElementDescriptor.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.apache.commons.jcs.engine.memory.util; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.lang.ref.SoftReference; - -import org.apache.commons.jcs.engine.behavior.ICacheElement; - -/** - * This wrapper is needed for double linked lists. - */ -public class SoftReferenceElementDescriptor - extends MemoryElementDescriptor -{ - /** Don't change */ - private static final long serialVersionUID = -1905161209035522460L; - - /** The CacheElement wrapped by this descriptor */ - private final SoftReference> srce; - - /** - * Constructs a usable MemoryElementDescriptor. - *

- * @param ce - */ - public SoftReferenceElementDescriptor( ICacheElement ce ) - { - super( null ); - this.srce = new SoftReference>(ce); - } - - /** - * @return the ce - */ - @Override - public ICacheElement getCacheElement() - { - if (srce != null) - { - return srce.get(); - } - - return null; - } -} diff --git a/src/org/apache/commons/jcs/engine/package.html b/src/org/apache/commons/jcs/engine/package.html deleted file mode 100644 index 9cb3956cff9..00000000000 --- a/src/org/apache/commons/jcs/engine/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - Interfaces used by the core and the auxiliary caches. - - diff --git a/src/org/apache/commons/jcs/engine/stats/CacheStats.java b/src/org/apache/commons/jcs/engine/stats/CacheStats.java deleted file mode 100644 index eacede7ce3b..00000000000 --- a/src/org/apache/commons/jcs/engine/stats/CacheStats.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.apache.commons.jcs.engine.stats; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.stats.behavior.ICacheStats; -import org.apache.commons.jcs.engine.stats.behavior.IStats; - -import java.util.List; - -/** - * This class stores cache historical and statistics data for a region. - *

- * Only the composite cache knows what the hit count across all auxiliaries is. - */ -public class CacheStats - extends Stats - implements ICacheStats -{ - /** Don't change. */ - private static final long serialVersionUID = 529914708798168590L; - - /** The region */ - private String regionName = null; - - /** What that auxiliaries are reporting. */ - private List auxStats = null; - - /** - * Stats are for a region, though auxiliary data may be for more. - *

- * @return The region name - */ - @Override - public String getRegionName() - { - return regionName; - } - - /** - * Stats are for a region, though auxiliary data may be for more. - *

- * @param name - The region name - */ - @Override - public void setRegionName( String name ) - { - regionName = name; - } - - /** - * @return IStats[] - */ - @Override - public List getAuxiliaryCacheStats() - { - return auxStats; - } - - /** - * @param stats - */ - @Override - public void setAuxiliaryCacheStats( List stats ) - { - auxStats = stats; - } - - /** - * @return readable string that can be logged. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - - buf.append( "Region Name = " + regionName ); - - if ( getStatElements() != null ) - { - for ( Object stat : getStatElements() ) - { - buf.append( "\n" ); - buf.append( stat ); - } - } - - if ( auxStats != null ) - { - for ( Object auxStat : auxStats ) - { - buf.append( "\n" ); - buf.append( "---------------------------" ); - buf.append( auxStat ); - } - } - - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/engine/stats/StatElement.java b/src/org/apache/commons/jcs/engine/stats/StatElement.java deleted file mode 100644 index fd2b3458384..00000000000 --- a/src/org/apache/commons/jcs/engine/stats/StatElement.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.apache.commons.jcs.engine.stats; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; - -/** - * This is a stat data holder. - */ -public class StatElement - implements IStatElement -{ - /** Don't change */ - private static final long serialVersionUID = -2982373725267618092L; - - /** name of the stat */ - private String name = null; - - /** the data */ - private V data = null; - - /** - * Constructor - * - * @param name - * @param data - */ - public StatElement(String name, V data) - { - super(); - this.name = name; - this.data = data; - } - - /** - * Get the name of the stat element, ex. HitCount - *

- * @return the stat element name - */ - @Override - public String getName() - { - return name; - } - - /** - * @param name - */ - @Override - public void setName( String name ) - { - this.name = name; - } - - /** - * Get the data, ex. for hit count you would get a value for some number. - *

- * @return data - */ - @Override - public V getData() - { - return data; - } - - /** - * Set the data for this element. - *

- * @param data - */ - @Override - public void setData( V data ) - { - this.data = data; - } - - /** - * @return a readable string. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( name ).append(" = ").append( data ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/engine/stats/Stats.java b/src/org/apache/commons/jcs/engine/stats/Stats.java deleted file mode 100644 index dfbf3888d58..00000000000 --- a/src/org/apache/commons/jcs/engine/stats/Stats.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.apache.commons.jcs.engine.stats; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; - -import java.util.List; - -/** - * @author aaronsm - */ -public class Stats - implements IStats -{ - /** Don't change */ - private static final long serialVersionUID = 227327902875154010L; - - /** The stats */ - private List> stats = null; - - /** The type of stat */ - private String typeName = null; - - /** - * @return IStatElement[] - */ - @Override - public List> getStatElements() - { - return stats; - } - - /** - * @param stats - */ - @Override - public void setStatElements( List> stats ) - { - this.stats = stats; - } - - /** - * @return typeName - */ - @Override - public String getTypeName() - { - return typeName; - } - - /** - * @param name - */ - @Override - public void setTypeName( String name ) - { - typeName = name; - } - - /** - * @return the stats in a readable string - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - - buf.append( typeName ); - - if ( stats != null ) - { - for (Object stat : stats) - { - buf.append( "\n" ); - buf.append( stat ); - } - } - - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/engine/stats/behavior/ICacheStats.java b/src/org/apache/commons/jcs/engine/stats/behavior/ICacheStats.java deleted file mode 100644 index 4efd282ceb2..00000000000 --- a/src/org/apache/commons/jcs/engine/stats/behavior/ICacheStats.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.apache.commons.jcs.engine.stats.behavior; - -import java.util.List; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This holds stat information on a region. It contains both auxiliary and core stats. - */ -public interface ICacheStats - extends IStats -{ - /** - * Stats are for a region, though auxiliary data may be for more. - *

- * @return The region name - */ - String getRegionName(); - - /** - * @param name - */ - void setRegionName( String name ); - - /** - * @return IStats[] - */ - List getAuxiliaryCacheStats(); - - /** - * @param stats - */ - void setAuxiliaryCacheStats( List stats ); -} diff --git a/src/org/apache/commons/jcs/engine/stats/behavior/IStatElement.java b/src/org/apache/commons/jcs/engine/stats/behavior/IStatElement.java deleted file mode 100644 index 64139df50c8..00000000000 --- a/src/org/apache/commons/jcs/engine/stats/behavior/IStatElement.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.apache.commons.jcs.engine.stats.behavior; - -import java.io.Serializable; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * IAuxiliaryCacheStats will hold these IStatElements. - */ -public interface IStatElement extends Serializable -{ - /** - * Get the name of the stat element, ex. HitCount - *

- * @return the stat element name - */ - String getName(); - - /** - * @param name - */ - void setName( String name ); - - /** - * Get the data, ex. for hit count you would get a value for some number. - *

- * @return data - */ - V getData(); - - /** - * Set the data for this element. - *

- * @param data - */ - void setData( V data ); -} diff --git a/src/org/apache/commons/jcs/engine/stats/behavior/IStats.java b/src/org/apache/commons/jcs/engine/stats/behavior/IStats.java deleted file mode 100644 index 352225a32ad..00000000000 --- a/src/org/apache/commons/jcs/engine/stats/behavior/IStats.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.apache.commons.jcs.engine.stats.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; -import java.util.List; - -/** - * This interface defines the common behavior for a stats holder. - * - * @author aaronsm - * - */ -public interface IStats - extends Serializable -{ - - /** - * Return generic statistical or historical data. - * - * @return list of IStatElements - */ - List> getStatElements(); - - /** - * Set the generic statistical or historical data. - * - * @param stats - */ - void setStatElements( List> stats ); - - /** - * Get the type name, such as "LRU Memory Cache." No formal type is defined. - * - * @return String - */ - String getTypeName(); - - /** - * Set the type name, such as "LRU Memory Cache." No formal type is defined. - * If we need formal types, we can use the cachetype param - * - * @param name - */ - void setTypeName( String name ); -} diff --git a/src/org/apache/commons/jcs/io/ObjectInputStreamClassLoaderAware.java b/src/org/apache/commons/jcs/io/ObjectInputStreamClassLoaderAware.java deleted file mode 100644 index 09c8f552f0f..00000000000 --- a/src/org/apache/commons/jcs/io/ObjectInputStreamClassLoaderAware.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.jcs.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectStreamClass; -import java.lang.reflect.Proxy; - -public class ObjectInputStreamClassLoaderAware extends ObjectInputStream { - private final ClassLoader classLoader; - - public ObjectInputStreamClassLoaderAware(final InputStream in, final ClassLoader classLoader) throws IOException { - super(in); - this.classLoader = classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader(); - } - - @Override - protected Class resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException { - return Class.forName(BlacklistClassResolver.DEFAULT.check(desc.getName()), false, classLoader); - } - - @Override - protected Class resolveProxyClass(final String[] interfaces) throws IOException, ClassNotFoundException { - final Class[] cinterfaces = new Class[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) { - cinterfaces[i] = Class.forName(interfaces[i], false, classLoader); - } - - try { - return Proxy.getProxyClass(classLoader, cinterfaces); - } catch (IllegalArgumentException e) { - throw new ClassNotFoundException(null, e); - } - } - - private static class BlacklistClassResolver { - private static final BlacklistClassResolver DEFAULT = new BlacklistClassResolver( - toArray(System.getProperty( - "jcs.serialization.class.blacklist", - "org.codehaus.groovy.runtime.,org.apache.commons.collections.functors.,org.apache.xalan")), - toArray(System.getProperty("jcs.serialization.class.whitelist"))); - - private final String[] blacklist; - private final String[] whitelist; - - protected BlacklistClassResolver(final String[] blacklist, final String[] whitelist) { - this.whitelist = whitelist; - this.blacklist = blacklist; - } - - protected boolean isBlacklisted(final String name) { - return (whitelist != null && !contains(whitelist, name)) || contains(blacklist, name); - } - - public final String check(final String name) { - if (isBlacklisted(name)) { - throw new SecurityException(name + " is not whitelisted as deserialisable, prevented before loading."); - } - return name; - } - - private static String[] toArray(final String property) { - return property == null ? null : property.split(" *, *"); - } - - private static boolean contains(final String[] list, String name) { - if (list != null) { - for (final String white : list) { - if (name.startsWith(white)) { - return true; - } - } - } - return false; - } - } -} diff --git a/src/org/apache/commons/jcs/package.html b/src/org/apache/commons/jcs/package.html deleted file mode 100644 index bce936d2610..00000000000 --- a/src/org/apache/commons/jcs/package.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - Contains the class JCS which provides a simple interface for clients to use - JCS. - - diff --git a/src/org/apache/commons/jcs/utils/access/AbstractJCSWorkerHelper.java b/src/org/apache/commons/jcs/utils/access/AbstractJCSWorkerHelper.java deleted file mode 100644 index d25b633c92e..00000000000 --- a/src/org/apache/commons/jcs/utils/access/AbstractJCSWorkerHelper.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.apache.commons.jcs.utils.access; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This is an abstract template for JCSWorkerHelper implementations. it simple has a convenience - * method for setting the finished flag. - *

- * @author tsavo - */ -public abstract class AbstractJCSWorkerHelper implements JCSWorkerHelper -{ - /** finished flag. Can't we use wait notify? */ - private boolean finished = false; - - /** - * Default - */ - public AbstractJCSWorkerHelper() - { - super(); - } - - /** - * @return finished - */ - @Override - public synchronized boolean isFinished() - { - return finished; - } - - /** - * @param isFinished - */ - @Override - public synchronized void setFinished( boolean isFinished ) - { - finished = isFinished; - } -} diff --git a/src/org/apache/commons/jcs/utils/access/JCSWorker.java b/src/org/apache/commons/jcs/utils/access/JCSWorker.java deleted file mode 100644 index 12395ab8c22..00000000000 --- a/src/org/apache/commons/jcs/utils/access/JCSWorker.java +++ /dev/null @@ -1,297 +0,0 @@ -package org.apache.commons.jcs.utils.access; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.jcs.JCS; -import org.apache.commons.jcs.access.CacheAccess; -import org.apache.commons.jcs.access.GroupCacheAccess; -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Utility class to encapsulate doing a piece of work, and caching the results - * in JCS. Simply construct this class with the region name for the Cache and - * keep a static reference to it instead of the JCS itself. Then make a new - * org.apache.commons.jcs.utils.access.AbstractJCSWorkerHelper and implement Object - * doWork() and do the work in there, returning the object to be cached. Then - * call .getResult() with the key and the AbstractJCSWorkerHelper to get the - * result of the work. If the object isn't already in the Cache, - * AbstractJCSWorkerHelper.doWork() will get called, and the result will be put - * into the cache. If the object is already in cache, the cached result will be - * returned instead. - *

- * As an added bonus, multiple JCSWorkers with the same region, and key won't do - * the work multiple times: The first JCSWorker to get started will do the work, - * and all subsequent workers with the same region, group, and key will wait on - * the first one and use his resulting work instead of doing the work - * themselves. - *

- * This is ideal when the work being done is a query to the database where the - * results may take time to be retrieved. - *

- * For example: - * - *

- *      public static JCSWorker cachingWorker = new JCSWorker("example region");
- *   		public Object getSomething(Serializable aKey){
- *        JCSWorkerHelper helper = new AbstractJCSWorkerHelper(){
- *          public Object doWork(){
- *            // Do some (DB?) work here which results in a list
- *            // This only happens if the cache dosn't have a item in this region for aKey
- *            // Note this is especially useful with Hibernate, which will cache indiviual
- *            // Objects, but not entire query result sets.
- *            List results = query.list();
- *            // Whatever we return here get's cached with aKey, and future calls to
- *            // getResult() on a CachedWorker with the same region and key will return that instead.
- *            return results;
- *        };
- *        List result = worker.getResult(aKey, helper);
- *      }
- * 
- * - * This is essentially the same as doing: - * - *
- * JCS jcs = JCS.getInstance( "exampleregion" );
- * List results = (List) jcs.get( aKey );
- * if ( results != null )
- * {
- *     //do the work here
- *     results = query.list();
- *     jcs.put( aKey, results );
- * }
- * 
- * - *

- * But has the added benefit of the work-load sharing; under normal - * circumstances if multiple threads all tried to do the same query at the same - * time, the same query would happen multiple times on the database, and the - * resulting object would get put into JCS multiple times. - *

- * @author Travis Savo - */ -public class JCSWorker -{ - /** The logger */ - private static final Log logger = LogFactory.getLog( JCSWorker.class ); - - /** The cache we are working with */ - private CacheAccess cache; - - /** The cache we are working with */ - private GroupCacheAccess groupCache; - - /** - * Map to hold who's doing work presently. - */ - private volatile ConcurrentMap> map = new ConcurrentHashMap>(); - - /** - * Region for the JCS cache. - */ - private final String region; - - /** - * Constructor which takes a region for the JCS cache. - * @param aRegion - * The Region to use for the JCS cache. - */ - public JCSWorker( final String aRegion ) - { - region = aRegion; - try - { - cache = JCS.getInstance( aRegion ); - groupCache = JCS.getGroupCacheInstance( aRegion ); - } - catch ( CacheException e ) - { - throw new RuntimeException( e.getMessage() ); - } - } - - /** - * Getter for the region of the JCS Cache. - * @return The JCS region in which the result will be cached. - */ - public String getRegion() - { - return region; - } - - /** - * Gets the cached result for this region/key OR does the work and caches - * the result, returning the result. If the result has not been cached yet, - * this calls doWork() on the JCSWorkerHelper to do the work and cache the - * result. This is also an opportunity to do any post processing of the - * result in your CachedWorker implementation. - * @param aKey - * The key to get/put with on the Cache. - * @param aWorker - * The JCSWorkerHelper implementing Object doWork(). This gets - * called if the cache get misses, and the result is put into - * cache. - * @return The result of doing the work, or the cached result. - * @throws Exception - * Throws an exception if anything goes wrong while doing the - * work. - */ - public V getResult( K aKey, JCSWorkerHelper aWorker ) - throws Exception - { - return run( aKey, null, aWorker ); - } - - /** - * Gets the cached result for this region/key OR does the work and caches - * the result, returning the result. If the result has not been cached yet, - * this calls doWork() on the JCSWorkerHelper to do the work and cache the - * result. This is also an opportunity to do any post processing of the - * result in your CachedWorker implementation. - * @param aKey - * The key to get/put with on the Cache. - * @param aGroup - * The cache group to put the result in. - * @param aWorker - * The JCSWorkerHelper implementing Object doWork(). This gets - * called if the cache get misses, and the result is put into - * cache. - * @return The result of doing the work, or the cached result. - * @throws Exception - * Throws an exception if anything goes wrong while doing the - * work. - */ - public V getResult( K aKey, String aGroup, JCSWorkerHelper aWorker ) - throws Exception - { - return run( aKey, aGroup, aWorker ); - } - - /** - * Try and get the object from the cache, and if it's not there, do the work - * and cache it. This also ensures that only one CachedWorker is doing the - * work and subsequent calls to a CachedWorker with identical - * region/key/group will wait on the results of this call. It will call the - * JCSWorkerHelper.doWork() if the cache misses, and will put the result. - * @param aKey - * @param aGroup - * @param aHelper - * @return Either the result of doing the work, or the cached result. - * @throws Exception - * If something goes wrong while doing the work, throw an - * exception. - */ - private V run( K aKey, String aGroup, JCSWorkerHelper aHelper ) - throws Exception - { - V result = null; - // long start = 0; - // long dbTime = 0; - JCSWorkerHelper helper = map.putIfAbsent(getRegion() + aKey, aHelper); - - if ( helper != null ) - { - synchronized ( helper ) - { - if ( logger.isDebugEnabled() ) - { - logger.debug( "Found a worker already doing this work (" + getRegion() + ":" + aKey + ")." ); - } - while ( !helper.isFinished() ) - { - try - { - helper.wait(); - } - catch (InterruptedException e) - { - // expected - } - } - if ( logger.isDebugEnabled() ) - { - logger.debug( "Another thread finished our work for us. Using those results instead. (" - + getRegion() + ":" + aKey + ")." ); - } - } - } - // Do the work - try - { - if ( logger.isDebugEnabled() ) - { - logger.debug( getRegion() + " is doing the work." ); - } - - // Try to get the item from the cache - if ( aGroup != null ) - { - result = groupCache.getFromGroup( aKey, aGroup ); - } - else - { - result = cache.get( aKey ); - } - // If the cache dosn't have it, do the work. - if ( result == null ) - { - result = aHelper.doWork(); - if ( logger.isDebugEnabled() ) - { - logger.debug( "Work Done, caching: key:" + aKey + ", group:" + aGroup + ", result:" + result + "." ); - } - // Stick the result of the work in the cache. - if ( aGroup != null ) - { - groupCache.putInGroup( aKey, aGroup, result ); - } - else - { - cache.put( aKey, result ); - } - } - // return the result - return result; - } - finally - { - if ( logger.isDebugEnabled() ) - { - logger.debug( getRegion() + ":" + aKey + " entered finally." ); - } - - // Remove ourselves as the worker. - if ( helper == null ) - { - map.remove( getRegion() + aKey ); - } - synchronized ( aHelper ) - { - aHelper.setFinished( true ); - // Wake everyone waiting on us - aHelper.notifyAll(); - } - } - } -} diff --git a/src/org/apache/commons/jcs/utils/access/JCSWorkerHelper.java b/src/org/apache/commons/jcs/utils/access/JCSWorkerHelper.java deleted file mode 100644 index c20ed7b0718..00000000000 --- a/src/org/apache/commons/jcs/utils/access/JCSWorkerHelper.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.apache.commons.jcs.utils.access; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Interface for doing a piece of work which is expected to be cached. This is - * meant to be used in conjunction with JCSWorker. - *

- * Implement doWork() to return the work being done. isFinished() should return - * false until setFinished(true) is called, after which time it should return - * true. - *

- * @author tsavo - */ -public interface JCSWorkerHelper -{ - /** - * Tells us whether or not the work has been completed. This will be called - * automatically by JCSWorker. You should not call it yourself. - *

- * @return True if the work has already been done, otherwise false. - */ - boolean isFinished(); - - /** - * Sets whether or not the work has been done. - *

- * @param isFinished - * True if the work has already been done, otherwise false. - */ - void setFinished( boolean isFinished ); - - /** - * The method to implement to do the work that should be cached. JCSWorker - * will call this itself! You should not call this directly. - *

- * @return The result of doing the work to be cached. - * @throws Exception - * If anything goes wrong while doing the work, an Exception - * should be thrown. - */ - V doWork() throws Exception; -} diff --git a/src/org/apache/commons/jcs/utils/config/OptionConverter.java b/src/org/apache/commons/jcs/utils/config/OptionConverter.java deleted file mode 100644 index 79c309f902a..00000000000 --- a/src/org/apache/commons/jcs/utils/config/OptionConverter.java +++ /dev/null @@ -1,426 +0,0 @@ -package org.apache.commons.jcs.utils.config; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Properties; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class is based on the log4j class org.apache.log4j.helpers.OptionConverter that was made by - * Ceki Gülcü Simon Kitching; Avy Sharell (sharell@online.fr) Anders Kristensen Matthieu - * Verbert (mve@zurich.ibm.com) A convenience class to convert property values to specific types. - */ -public class OptionConverter -{ - /** The logger */ - private static final Log log = LogFactory.getLog( OptionConverter.class ); - - /** System property delimter */ - private static final String DELIM_START = "${"; - - /** System property delimter */ - private static final char DELIM_STOP = '}'; - - /** System property delimter start length */ - private static final int DELIM_START_LEN = 2; - - /** System property delimter end length */ - private static final int DELIM_STOP_LEN = 1; - - /** No instances please. */ - private OptionConverter() - { - super(); - } - - /** - * Combines two arrays. - * @param l - * @param r - * @return String[] - */ - public static String[] concatanateArrays( String[] l, String[] r ) - { - int len = l.length + r.length; - String[] a = new String[len]; - - System.arraycopy( l, 0, a, 0, l.length ); - System.arraycopy( r, 0, a, l.length, r.length ); - - return a; - } - - /** - * Escapes special characters. - * - * @param s - * @return String - */ - public static String convertSpecialChars( String s ) - { - char c; - int len = s.length(); - StringBuilder sb = new StringBuilder( len ); - - int i = 0; - while ( i < len ) - { - c = s.charAt( i++ ); - if ( c == '\\' ) - { - c = s.charAt( i++ ); - if ( c == 'n' ) - { - c = '\n'; - } - else if ( c == 'r' ) - { - c = '\r'; - } - else if ( c == 't' ) - { - c = '\t'; - } - else if ( c == 'f' ) - { - c = '\f'; - } - else if ( c == '\b' ) - { - c = '\b'; - } - else if ( c == '\"' ) - { - c = '\"'; - } - else if ( c == '\'' ) - { - c = '\''; - } - else if ( c == '\\' ) - { - c = '\\'; - } - } - sb.append( c ); - } - return sb.toString(); - } - - /** - * Very similar to System.getProperty except that the {@link SecurityException} is - * hidden. - * @param key The key to search for. - * @param def The default value to return. - * @return the string value of the system property, or the default value if there is no property - * with that key. - * @since 1.1 - */ - - public static String getSystemProperty( String key, String def ) - { - try - { - return System.getProperty( key, def ); - } - catch ( Throwable e ) - { - // MS-Java throws com.ms.security.SecurityExceptionEx - log.debug( "Was not allowed to read system property \"" + key + "\"." ); - return def; - } - } - - /** - * Creates an object for the className value of the key. - * - * @param props - * @param key - * @param defaultValue - * @return Object that was created - */ - public static T instantiateByKey( Properties props, String key, T defaultValue ) - { - - // Get the value of the property in string form - String className = findAndSubst( key, props ); - if ( className == null ) - { - if ( log.isTraceEnabled() ) - { - log.info( "Could not find value for key " + key ); - } - return defaultValue; - } - // Trim className to avoid trailing spaces that cause problems. - return OptionConverter.instantiateByClassName( className.trim(), defaultValue ); - } - - /** - * If value is "true", then true is returned. If value is - * "false", then true is returned. Otherwise, default is returned. - * - * Case of value is unimportant. - * @param value - * @param defaultValue - * @return Object - */ - public static boolean toBoolean( String value, boolean defaultValue ) - { - if ( value == null ) - { - return defaultValue; - } - String trimmedVal = value.trim(); - if ( "true".equalsIgnoreCase( trimmedVal ) ) - { - return true; - } - if ( "false".equalsIgnoreCase( trimmedVal ) ) - { - return false; - } - return defaultValue; - } - - /** - * Converts to int. - * - * @param value - * @param defaultValue - * @return int - */ - public static int toInt( String value, int defaultValue ) - { - if ( value != null ) - { - String s = value.trim(); - try - { - return Integer.parseInt(s); - } - catch ( NumberFormatException e ) - { - log.error( "[" + s + "] is not in proper int form." ); - e.printStackTrace(); - } - } - return defaultValue; - } - - /** - * @param value - * @param defaultValue - * @return long - */ - public static long toFileSize( String value, long defaultValue ) - { - if ( value == null ) - { - return defaultValue; - } - - String s = value.trim().toUpperCase(); - long multiplier = 1; - int index; - - if ( ( index = s.indexOf( "KB" ) ) != -1 ) - { - multiplier = 1024; - s = s.substring( 0, index ); - } - else if ( ( index = s.indexOf( "MB" ) ) != -1 ) - { - multiplier = 1024 * 1024; - s = s.substring( 0, index ); - } - else if ( ( index = s.indexOf( "GB" ) ) != -1 ) - { - multiplier = 1024 * 1024 * 1024; - s = s.substring( 0, index ); - } - if ( s != null ) - { - try - { - return Long.parseLong(s) * multiplier; - } - catch ( NumberFormatException e ) - { - log.error( "[" + s + "] is not in proper int form" ); - log.error( "[" + value + "] not in expected format", e ); - } - } - return defaultValue; - } - - /** - * Find the value corresponding to key in props. Then perform variable - * substitution on the found value. - * - * @param key - * @param props - * @return substituted string - */ - - public static String findAndSubst( String key, Properties props ) - { - String value = props.getProperty( key ); - if ( value == null ) - { - return null; - } - - try - { - return substVars( value, props ); - } - catch ( IllegalArgumentException e ) - { - log.error( "Bad option value [" + value + "]", e ); - return value; - } - } - - /** - * Instantiate an object given a class name. Check that the className is a subclass - * of superClass. If that test fails or the object could not be instantiated, then - * defaultValue is returned. - * - * @param className The fully qualified class name of the object to instantiate. - * @param defaultValue The object to return in case of non-fulfillment - * @return instantiated object - */ - - public static T instantiateByClassName( String className, T defaultValue ) - { - if ( className != null ) - { - try - { - Class classObj = Class.forName( className ); - Object o = classObj.newInstance(); - - try - { - @SuppressWarnings("unchecked") // CCE catched - T t = (T) o; - return t; - } - catch (ClassCastException e) - { - log.error( "A \"" + className + "\" object is not assignable to the generic variable." ); - return defaultValue; - } - } - catch ( Exception e ) - { - log.error( "Could not instantiate class [" + className + "]", e ); - } - } - return defaultValue; - } - - /** - * Perform variable substitution in string val from the values of keys found in the - * system properties. - * - * The variable substitution delimiters are ${ and } . - * - * For example, if the System properties contains "key=value", then the call - * - *

-     * String s = OptionConverter.substituteVars( "Value of key is ${key}." );
-     * 
- * - * will set the variable s to "Value of key is value.". - * - * If no value could be found for the specified key, then the props parameter is - * searched, if the value could not be found there, then substitution defaults to the empty - * string. - * - * For example, if system properties contains no value for the key "inexistentKey", then the call - * - *
-     * String s = OptionConverter.subsVars( "Value of inexistentKey is [${inexistentKey}]" );
-     * 
- * - * will set s to "Value of inexistentKey is []" - *

- * An {@link java.lang.IllegalArgumentException}is thrown if val contains a start - * delimiter "${" which is not balanced by a stop delimiter "}". - *

- *

- * Author Avy Sharell - *

- * @param val The string on which variable substitution is performed. - * @param props - * @return String - * @throws IllegalArgumentException if val is malformed. - */ - - public static String substVars( String val, Properties props ) - throws IllegalArgumentException - { - StringBuilder sbuf = new StringBuilder(); - - int i = 0; - int j; - int k; - - while ( true ) - { - j = val.indexOf( DELIM_START, i ); - if ( j == -1 ) - { - if ( i == 0 ) - { - return val; - } - sbuf.append( val.substring( i, val.length() ) ); - return sbuf.toString(); - } - sbuf.append( val.substring( i, j ) ); - k = val.indexOf( DELIM_STOP, j ); - if ( k == -1 ) - { - throw new IllegalArgumentException( '"' + val + "\" has no closing brace. Opening brace at position " - + j + '.' ); - } - j += DELIM_START_LEN; - String key = val.substring( j, k ); - // first try in System properties - String replacement = getSystemProperty( key, null ); - // then try props parameter - if ( replacement == null && props != null ) - { - replacement = props.getProperty( key ); - } - - if ( replacement != null ) - { - sbuf.append( replacement ); - } - i = k + DELIM_STOP_LEN; - } - } -} diff --git a/src/org/apache/commons/jcs/utils/config/PropertySetter.java b/src/org/apache/commons/jcs/utils/config/PropertySetter.java deleted file mode 100644 index c6502e4463e..00000000000 --- a/src/org/apache/commons/jcs/utils/config/PropertySetter.java +++ /dev/null @@ -1,299 +0,0 @@ -package org.apache.commons.jcs.utils.config; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.io.File; -import java.lang.reflect.Method; -import java.util.Enumeration; -import java.util.Properties; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class is based on the log4j class org.apache.log4j.config.PropertySetter that was made by - * Anders Kristensen - *

- * General purpose Object property setter. Clients repeatedly invokes {@link #setProperty - * setProperty(name,value)} in order to invoke setters on the Object specified in the constructor. - * This class relies on the JavaBeans {@link Introspector}to analyze the given Object Class using - * reflection. - *

- * Usage: - * - *

- * PropertySetter ps = new PropertySetter( anObject );
- * ps.set( "name", "Joe" );
- * ps.set( "age", "32" );
- * ps.set( "isMale", "true" );
- * 
- * - * will cause the invocations anObject.setName("Joe"), anObject.setAge(32), and setMale(true) if - * such methods exist with those signatures. Otherwise an {@link IntrospectionException}are thrown. - */ -public class PropertySetter -{ - /** Logger */ - private static final Log log = LogFactory.getLog( PropertySetter.class ); - - /** Description of the Field */ - private final Object obj; - - /** Description of the Field */ - private PropertyDescriptor[] props; - - /** - * Create a new PropertySetter for the specified Object. This is done in preparation for invoking - * {@link #setProperty}one or more times. - * @param obj the object for which to set properties - */ - public PropertySetter( Object obj ) - { - this.obj = obj; - } - - /** - * Uses JavaBeans {@link Introspector}to compute setters of object to be configured. - */ - protected void introspect() - { - try - { - BeanInfo bi = Introspector.getBeanInfo( obj.getClass() ); - props = bi.getPropertyDescriptors(); - } - catch ( IntrospectionException ex ) - { - log.error( "Failed to introspect " + obj + ": " + ex.getMessage() ); - props = new PropertyDescriptor[0]; - } - } - - /** - * Set the properties of an object passed as a parameter in one go. The properties - * are parsed relative to a prefix. - *

- * @param obj The object to configure. - * @param properties A java.util.Properties containing keys and values. - * @param prefix Only keys having the specified prefix will be set. - */ - public static void setProperties( Object obj, Properties properties, String prefix ) - { - new PropertySetter( obj ).setProperties( properties, prefix ); - } - - /** - * Set the properties for the object that match the prefix passed as parameter. - *

- * @param properties The new properties value - * @param prefix The new properties value - */ - public void setProperties( Properties properties, String prefix ) - { - int len = prefix.length(); - - for ( Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) - { - String key = (String) e.nextElement(); - - // handle only properties that start with the desired prefix. - if ( key.startsWith( prefix ) ) - { - - // ignore key if it contains dots after the prefix - if ( key.indexOf( '.', len + 1 ) > 0 ) - { - //System.err.println("----------Ignoring---["+key - // +"], prefix=["+prefix+"]."); - continue; - } - - String value = OptionConverter.findAndSubst( key, properties ); - key = key.substring( len ); - - setProperty( key, value ); - } - } - - } - - /** - * Set a property on this PropertySetter's Object. If successful, this method will invoke a - * setter method on the underlying Object. The setter is the one for the specified property name - * and the value is determined partly from the setter argument type and partly from the value - * specified in the call to this method. - *

- * If the setter expects a String no conversion is necessary. If it expects an int, then an - * attempt is made to convert 'value' to an int using Integer.valueOf(value). If the setter expects - * a boolean, the conversion is by Boolean.valueOf(value). - * @param name name of the property - * @param value String value of the property - */ - - public void setProperty( String name, String value ) - { - if ( value == null ) - { - return; - } - - name = Introspector.decapitalize( name ); - PropertyDescriptor prop = getPropertyDescriptor( name ); - - //log.debug("---------Key: "+name+", type="+prop.getPropertyType()); - - if ( prop == null ) - { - log.warn( "No such property [" + name + "] in " + obj.getClass().getName() + "." ); - } - else - { - try - { - setProperty( prop, name, value ); - } - catch ( PropertySetterException ex ) - { - log.warn( "Failed to set property " + name + " to value \"" + value + "\". " + ex.getMessage() ); - } - } - } - - /** - * Set the named property given a {@link PropertyDescriptor}. - * @param prop A PropertyDescriptor describing the characteristics of the property to set. - * @param name The named of the property to set. - * @param value The value of the property. - * @throws PropertySetterException - */ - - public void setProperty( PropertyDescriptor prop, String name, String value ) - throws PropertySetterException - { - Method setter = prop.getWriteMethod(); - if ( setter == null ) - { - throw new PropertySetterException( "No setter for property" ); - } - Class[] paramTypes = setter.getParameterTypes(); - if ( paramTypes.length != 1 ) - { - throw new PropertySetterException( "#params for setter != 1" ); - } - - Object arg; - try - { - arg = convertArg( value, paramTypes[0] ); - } - catch ( Throwable t ) - { - throw new PropertySetterException( "Conversion to type [" + paramTypes[0] + "] failed. Reason: " + t ); - } - if ( arg == null ) - { - throw new PropertySetterException( "Conversion to type [" + paramTypes[0] + "] failed." ); - } - log.debug( "Setting property [" + name + "] to [" + arg + "]." ); - try - { - setter.invoke( obj, new Object[] { arg } ); - } - catch ( Exception ex ) - { - throw new PropertySetterException( ex ); - } - } - - /** - * Convert val a String parameter to an object of a given type. - * @param val - * @param type - * @return Object - */ - protected Object convertArg( String val, Class type ) - { - if ( val == null ) - { - return null; - } - - String v = val.trim(); - if ( String.class.isAssignableFrom( type ) ) - { - return val; - } - else if ( Integer.TYPE.isAssignableFrom( type ) ) - { - return Integer.valueOf( v ); - } - else if ( Long.TYPE.isAssignableFrom( type ) ) - { - return Long.valueOf( v ); - } - else if ( Boolean.TYPE.isAssignableFrom( type ) ) - { - if ( "true".equalsIgnoreCase( v ) ) - { - return Boolean.TRUE; - } - else if ( "false".equalsIgnoreCase( v ) ) - { - return Boolean.FALSE; - } - } - else if( type.isEnum() ) - { - Enum en = Enum.valueOf(type.asSubclass(Enum.class), v ); - return en; - } - else if ( File.class.isAssignableFrom( type ) ) - { - return new File( v ); - } - return null; - } - - /** - * Gets the propertyDescriptor attribute of the PropertySetter object - * @param name - * @return The propertyDescriptor value - */ - protected PropertyDescriptor getPropertyDescriptor( String name ) - { - if ( props == null ) - { - introspect(); - } - - for ( int i = 0; i < props.length; i++ ) - { - if ( name.equals( props[i].getName() ) ) - { - return props[i]; - } - } - return null; - } -} diff --git a/src/org/apache/commons/jcs/utils/config/PropertySetterException.java b/src/org/apache/commons/jcs/utils/config/PropertySetterException.java deleted file mode 100644 index 0898a5474a7..00000000000 --- a/src/org/apache/commons/jcs/utils/config/PropertySetterException.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.apache.commons.jcs.utils.config; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This class is based on the log4j class org.apache.log4j.config.PropertySetter that was made by - * Anders Kristensen - *

- * Thrown when an error is encountered whilst attempting to set a property using the - * {@link PropertySetter}utility class. - */ -public class PropertySetterException - extends Exception -{ - /** DOn't change */ - private static final long serialVersionUID = -210271658004609028L; - - /** Description of the Field */ - private final Throwable rootCause; - - /** - * Constructor for the PropertySetterException object - *

- * @param msg - */ - public PropertySetterException( String msg ) - { - super( msg ); - this.rootCause = null; - } - - /** - * Constructor for the PropertySetterException object - *

- * @param rootCause - */ - public PropertySetterException( Throwable rootCause ) - { - super(); - this.rootCause = rootCause; - } - - /** - * Returns descriptive text on the cause of this exception. - *

- * @return The message value - */ - @Override - public String getMessage() - { - String msg = super.getMessage(); - if ( msg == null && rootCause != null ) - { - msg = rootCause.getMessage(); - } - return msg; - } -} diff --git a/src/org/apache/commons/jcs/utils/config/package.html b/src/org/apache/commons/jcs/utils/config/package.html deleted file mode 100644 index 1de5d405f05..00000000000 --- a/src/org/apache/commons/jcs/utils/config/package.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - This package contains utility classes that are used when configuring the - cache.
- NOTE: It is likely that these classes will be removed in the future in favor - of commons-configuration. - - diff --git a/src/org/apache/commons/jcs/utils/discovery/DiscoveredService.java b/src/org/apache/commons/jcs/utils/discovery/DiscoveredService.java deleted file mode 100644 index cbfd737cbc4..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/DiscoveredService.java +++ /dev/null @@ -1,183 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; -import java.util.ArrayList; - -/** - * This contains info about a discovered service. These objects are stored in a set in the - * UDPDiscoveryService. - *

- * @author Aaron Smuts - */ -public class DiscoveredService - implements Serializable -{ - /** For serialization. Don't change. */ - private static final long serialVersionUID = -7810164772089509751L; - - /** region names */ - private ArrayList cacheNames; - - /** service address */ - private String serviceAddress; - - /** service port */ - private int servicePort; - - /** last time we heard from this service? */ - private long lastHearFromTime = 0; - - /** - * @param cacheNames the cacheNames to set - */ - public void setCacheNames( ArrayList cacheNames ) - { - this.cacheNames = cacheNames; - } - - /** - * @return the cacheNames - */ - public ArrayList getCacheNames() - { - return cacheNames; - } - - /** - * @param serviceAddress The serviceAddress to set. - */ - public void setServiceAddress( String serviceAddress ) - { - this.serviceAddress = serviceAddress; - } - - /** - * @return Returns the serviceAddress. - */ - public String getServiceAddress() - { - return serviceAddress; - } - - /** - * @param servicePort The servicePort to set. - */ - public void setServicePort( int servicePort ) - { - this.servicePort = servicePort; - } - - /** - * @return Returns the servicePort. - */ - public int getServicePort() - { - return servicePort; - } - - /** - * @param lastHearFromTime The lastHearFromTime to set. - */ - public void setLastHearFromTime( long lastHearFromTime ) - { - this.lastHearFromTime = lastHearFromTime; - } - - /** - * @return Returns the lastHearFromTime. - */ - public long getLastHearFromTime() - { - return lastHearFromTime; - } - - /** @return hashcode based on address/port */ - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result - + ((serviceAddress == null) ? 0 : serviceAddress.hashCode()); - result = prime * result + servicePort; - return result; - } - - /** - * NOTE - this object is often put into sets, so equals needs to be overridden. - *

- * We can't use cache names as part of the equals unless we manually only use the address and - * port in a contains check. So that we can use normal set functionality, I've kept the cache - * names out. - *

- * @param otherArg other - * @return equality based on the address/port - */ - @Override - public boolean equals(Object otherArg) - { - if (this == otherArg) - { - return true; - } - if (otherArg == null) - { - return false; - } - if (!(otherArg instanceof DiscoveredService)) - { - return false; - } - DiscoveredService other = (DiscoveredService) otherArg; - if (serviceAddress == null) - { - if (other.serviceAddress != null) - { - return false; - } - } else if (!serviceAddress.equals(other.serviceAddress)) - { - return false; - } - if (servicePort != other.servicePort) - { - return false; - } - - return true; - } - - /** - * @return string for debugging purposes. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n DiscoveredService" ); - buf.append( "\n CacheNames = [" + getCacheNames() + "]" ); - buf.append( "\n ServiceAddress = [" + getServiceAddress() + "]" ); - buf.append( "\n ServicePort = [" + getServicePort() + "]" ); - buf.append( "\n LastHearFromTime = [" + getLastHearFromTime() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPCleanupRunner.java b/src/org/apache/commons/jcs/utils/discovery/UDPCleanupRunner.java deleted file mode 100644 index d000f20bd6f..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPCleanupRunner.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.HashSet; -import java.util.Set; - -/** - * This class periodically check the lastHeardFrom time on the services. - *

- * If they exceed the configurable limit, it removes them from the set. - *

- * @author Aaron Smuts - */ -public class UDPCleanupRunner - implements Runnable -{ - /** log instance */ - private static final Log log = LogFactory.getLog( UDPCleanupRunner.class ); - - /** UDP discovery service */ - private final UDPDiscoveryService discoveryService; - - /** default for max idle time, in seconds */ - private static final long DEFAULT_MAX_IDLE_TIME_SECONDS = 180; - - /** The configured max idle time, in seconds */ - private final long maxIdleTimeSeconds = DEFAULT_MAX_IDLE_TIME_SECONDS; - - /** - * @param service UDPDiscoveryService - */ - public UDPCleanupRunner( UDPDiscoveryService service ) - { - this.discoveryService = service; - } - - /** - * This goes through the list of services and removes those that we haven't heard from in longer - * than the max idle time. - *

- * @see java.lang.Runnable#run() - */ - @Override - public void run() - { - long now = System.currentTimeMillis(); - - // iterate through the set - // it is thread safe - // http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/CopyOnWriteArraySet. - // html - // TODO this should get a copy. you can't simply remove from this. - // the listeners need to be notified. - Set toRemove = new HashSet(); - // can't remove via the iterator. must remove directly - for (DiscoveredService service : discoveryService.getDiscoveredServices()) - { - if ( ( now - service.getLastHearFromTime() ) > ( maxIdleTimeSeconds * 1000 ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Removing service, since we haven't heard from it in " + maxIdleTimeSeconds - + " seconds. service = " + service ); - } - toRemove.add( service ); - } - } - - // remove the bad ones - for (DiscoveredService service : toRemove) - { - // call this so the listeners get notified - discoveryService.removeDiscoveredService( service ); - } - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryAttributes.java b/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryAttributes.java deleted file mode 100644 index e89664e9ba8..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryAttributes.java +++ /dev/null @@ -1,231 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Configuration properties for UDP discover service. - *

- * The service will allow out applications to find each other. - *

- * @author Aaron Smuts - */ -public final class UDPDiscoveryAttributes - implements Cloneable -{ - /** service name */ - private String serviceName; - - /** service address */ - private String serviceAddress; - - /** service port */ - private int servicePort; - - /** - * false -> this service instance is not ready to receive requests. true -> ready for use - */ - private boolean isDark; - - /** default udp discovery address */ - private static final String DEFAULT_UDP_DISCOVERY_ADDRESS = "228.4.5.6"; - - /** default udp discovery port */ - private static final int DEFAULT_UDP_DISCOVERY_PORT = 5678; - - /** udp discovery address */ - private String udpDiscoveryAddr = DEFAULT_UDP_DISCOVERY_ADDRESS; - - /** udp discovery port */ - private int udpDiscoveryPort = DEFAULT_UDP_DISCOVERY_PORT; - - /** default delay between sending passive broadcasts */ - private static final int DEFAULT_SEND_DELAY_SEC = 60; - - /** delay between sending passive broadcasts */ - private int sendDelaySec = DEFAULT_SEND_DELAY_SEC; - - /** default amount of time before we remove services that we haven't heard from */ - private static final int DEFAULT_MAX_IDLE_TIME_SEC = 180; - - /** amount of time before we remove services that we haven't heard from */ - private int maxIdleTimeSec = DEFAULT_MAX_IDLE_TIME_SEC; - - /** - * @param serviceName The serviceName to set. - */ - public void setServiceName( String serviceName ) - { - this.serviceName = serviceName; - } - - /** - * @return Returns the serviceName. - */ - public String getServiceName() - { - return serviceName; - } - - /** - * @param serviceAddress The serviceAddress to set. - */ - public void setServiceAddress( String serviceAddress ) - { - this.serviceAddress = serviceAddress; - } - - /** - * @return Returns the serviceAddress. - */ - public String getServiceAddress() - { - return serviceAddress; - } - - /** - * @param servicePort The servicePort to set. - */ - public void setServicePort( int servicePort ) - { - this.servicePort = servicePort; - } - - /** - * @return Returns the servicePort. - */ - public int getServicePort() - { - return servicePort; - } - - /** - * @param udpDiscoveryAddr The udpDiscoveryAddr to set. - */ - public void setUdpDiscoveryAddr( String udpDiscoveryAddr ) - { - this.udpDiscoveryAddr = udpDiscoveryAddr; - } - - /** - * @return Returns the udpDiscoveryAddr. - */ - public String getUdpDiscoveryAddr() - { - return udpDiscoveryAddr; - } - - /** - * @param udpDiscoveryPort The udpDiscoveryPort to set. - */ - public void setUdpDiscoveryPort( int udpDiscoveryPort ) - { - this.udpDiscoveryPort = udpDiscoveryPort; - } - - /** - * @return Returns the udpDiscoveryPort. - */ - public int getUdpDiscoveryPort() - { - return udpDiscoveryPort; - } - - /** - * @param sendDelaySec The sendDelaySec to set. - */ - public void setSendDelaySec( int sendDelaySec ) - { - this.sendDelaySec = sendDelaySec; - } - - /** - * @return Returns the sendDelaySec. - */ - public int getSendDelaySec() - { - return sendDelaySec; - } - - /** - * @param maxIdleTimeSec The maxIdleTimeSec to set. - */ - public void setMaxIdleTimeSec( int maxIdleTimeSec ) - { - this.maxIdleTimeSec = maxIdleTimeSec; - } - - /** - * @return Returns the maxIdleTimeSec. - */ - public int getMaxIdleTimeSec() - { - return maxIdleTimeSec; - } - - /** - * @return Returns the isDark. - */ - public boolean isDark() - { - return isDark; - } - - /** - * @param isDark The isDark to set. - */ - public void setDark( boolean isDark ) - { - this.isDark = isDark; - } - - /** @return a clone of this object */ - @Override - public UDPDiscoveryAttributes clone() - { - UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes(); - attributes.setSendDelaySec( this.getSendDelaySec() ); - attributes.setMaxIdleTimeSec( this.getMaxIdleTimeSec() ); - attributes.setServiceName( this.getServiceName() ); - attributes.setServicePort( this.getServicePort() ); - attributes.setUdpDiscoveryAddr( this.getUdpDiscoveryAddr() ); - attributes.setUdpDiscoveryPort( this.getUdpDiscoveryPort() ); - attributes.setDark( this.isDark() ); - return attributes; - } - - /** - * @return string for debugging purposes. - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n UDPDiscoveryAttributes" ); - buf.append( "\n ServiceName = [" + getServiceName() + "]" ); - buf.append( "\n ServiceAddress = [" + getServiceAddress() + "]" ); - buf.append( "\n ServicePort = [" + getServicePort() + "]" ); - buf.append( "\n UdpDiscoveryAddr = [" + getUdpDiscoveryAddr() + "]" ); - buf.append( "\n UdpDiscoveryPort = [" + getUdpDiscoveryPort() + "]" ); - buf.append( "\n SendDelaySec = [" + getSendDelaySec() + "]" ); - buf.append( "\n MaxIdleTimeSec = [" + getMaxIdleTimeSec() + "]" ); - buf.append( "\n IsDark = [" + isDark() + "]" ); - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryManager.java b/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryManager.java deleted file mode 100644 index 79300fa2789..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryManager.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; -import org.apache.commons.jcs.engine.behavior.IProvideScheduler; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This manages UDPDiscovery Services. We should end up with one service per Lateral Cache Manager - * Instance. One service works for multiple regions. We don't want a connection for each region. - *

- * @author Aaron Smuts - */ -public class UDPDiscoveryManager -{ - /** The logger */ - private static final Log log = LogFactory.getLog( UDPDiscoveryManager.class ); - - /** Singleton instance */ - private static UDPDiscoveryManager INSTANCE = new UDPDiscoveryManager(); - - /** Known services */ - private final Map services = new HashMap(); - - /** private for singleton */ - private UDPDiscoveryManager() - { - // noopt - } - - /** - * Singleton - *

- * @return UDPDiscoveryManager - */ - public static UDPDiscoveryManager getInstance() - { - return INSTANCE; - } - - /** - * Creates a service for the address and port if one doesn't exist already. - *

- * We need to key this using the listener port too. TODO think of making one discovery service - * work for multiple types of clients. - *

- * @param discoveryAddress - * @param discoveryPort - * @param servicePort - * @param cacheMgr - * @return UDPDiscoveryService - */ - public synchronized UDPDiscoveryService getService( String discoveryAddress, int discoveryPort, int servicePort, - ICompositeCacheManager cacheMgr ) - { - String key = discoveryAddress + ":" + discoveryPort + ":" + servicePort; - - UDPDiscoveryService service = services.get( key ); - if ( service == null ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Creating service for address:port:servicePort [" + key + "]" ); - } - - UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes(); - attributes.setUdpDiscoveryAddr( discoveryAddress ); - attributes.setUdpDiscoveryPort( discoveryPort ); - attributes.setServicePort( servicePort ); - - service = new UDPDiscoveryService( attributes ); - - // register for shutdown notification - cacheMgr.registerShutdownObserver( service ); - - // inject scheduler - if ( cacheMgr instanceof IProvideScheduler) - { - service.setScheduledExecutorService(((IProvideScheduler)cacheMgr).getScheduledExecutorService()); - } - - service.startup(); - services.put( key, service ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "Returning service [" + service + "] for key [" + key + "]" ); - } - - return service; - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryMessage.java b/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryMessage.java deleted file mode 100644 index efe424cad4d..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryMessage.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; -import java.util.ArrayList; - -/** - * The message sent by the discovery mechanism. - */ -public class UDPDiscoveryMessage - implements Serializable -{ - /** Don't change */ - private static final long serialVersionUID = -5332377899560951793L; - - public enum BroadcastType - { - /** - * This is the periodic broadcast of a servers location. This type of message is also sent in - * response to a REQUEST_BROADCAST. - */ - PASSIVE, - - /** - * This asks recipients to broadcast their location. This is used on startup. - */ - REQUEST, - - /** - * This message instructs the receiver to remove this service from its list. - */ - REMOVE - } - - /** The message type */ - private BroadcastType messageType = BroadcastType.PASSIVE; - - /** udp port */ - private int port = 6789; - - /** UDP host */ - private String host = "228.5.6.7"; - - /** Id of the requester, allows self-filtration */ - private long requesterId; - - /** Names of regions */ - private ArrayList cacheNames = new ArrayList(); - - /** - * @param port The port to set. - */ - public void setPort( int port ) - { - this.port = port; - } - - /** - * @return Returns the port. - */ - public int getPort() - { - return port; - } - - /** - * @param host The host to set. - */ - public void setHost( String host ) - { - this.host = host; - } - - /** - * @return Returns the host. - */ - public String getHost() - { - return host; - } - - /** - * @param requesterId The requesterId to set. - */ - public void setRequesterId( long requesterId ) - { - this.requesterId = requesterId; - } - - /** - * @return Returns the requesterId. - */ - public long getRequesterId() - { - return requesterId; - } - - /** - * @param messageType The messageType to set. - */ - public void setMessageType( BroadcastType messageType ) - { - this.messageType = messageType; - } - - /** - * @return Returns the messageType. - */ - public BroadcastType getMessageType() - { - return messageType; - } - - /** - * @param cacheNames The cacheNames to set. - */ - public void setCacheNames( ArrayList cacheNames ) - { - this.cacheNames = cacheNames; - } - - /** - * @return Returns the cacheNames. - */ - public ArrayList getCacheNames() - { - return cacheNames; - } - - /** - * @return debugging string - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "\n host = [" + host + "]" ); - buf.append( "\n port = [" + port + "]" ); - buf.append( "\n requesterId = [" + requesterId + "]" ); - buf.append( "\n messageType = [" + messageType + "]" ); - buf.append( "\n Cache Names" ); - for (String name : cacheNames) - { - buf.append( " cacheName = [" + name + "]" ); - } - return buf.toString(); - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java b/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java deleted file mode 100644 index 07a6687034a..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java +++ /dev/null @@ -1,394 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.net.DatagramPacket; -import java.net.InetAddress; -import java.net.MulticastSocket; -import java.util.concurrent.ExecutorService; - -import org.apache.commons.jcs.engine.CacheInfo; -import org.apache.commons.jcs.engine.behavior.IShutdownObserver; -import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware; -import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType; -import org.apache.commons.jcs.utils.threadpool.PoolConfiguration; -import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy; -import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** Receives UDP Discovery messages. */ -public class UDPDiscoveryReceiver - implements Runnable, IShutdownObserver -{ - /** The log factory */ - private static final Log log = LogFactory.getLog( UDPDiscoveryReceiver.class ); - - /** buffer */ - private final byte[] mBuffer = new byte[65536]; - - /** The socket used for communication. */ - private MulticastSocket mSocket; - - /** - * TODO: Consider using the threadpool manager to get this thread pool. For now place a tight - * restriction on the pool size - */ - private static final int maxPoolSize = 2; - - /** The processor */ - private ExecutorService pooledExecutor = null; - - /** number of messages received. For debugging and testing. */ - private int cnt = 0; - - /** Service to get cache names and handle request broadcasts */ - private UDPDiscoveryService service = null; - - /** Address */ - private String multicastAddressString = ""; - - /** The port */ - private int multicastPort = 0; - - /** Is it shutdown. */ - private boolean shutdown = false; - - /** - * Constructor for the LateralUDPReceiver object. - *

- * We determine out own host using InetAddress - *

- * @param service - * @param multicastAddressString - * @param multicastPort - * @throws IOException - */ - public UDPDiscoveryReceiver( UDPDiscoveryService service, String multicastAddressString, int multicastPort ) - throws IOException - { - this.service = service; - this.multicastAddressString = multicastAddressString; - this.multicastPort = multicastPort; - - // create a small thread pool to handle a barrage - pooledExecutor = ThreadPoolManager.getInstance().createPool( - new PoolConfiguration(false, 0, maxPoolSize, maxPoolSize, 0, WhenBlockedPolicy.DISCARDOLDEST, maxPoolSize), - "JCS-UDPDiscoveryReceiver-", Thread.MIN_PRIORITY); - - if ( log.isInfoEnabled() ) - { - log.info( "Constructing listener, [" + this.multicastAddressString + ":" + this.multicastPort + "]" ); - } - - try - { - createSocket( this.multicastAddressString, this.multicastPort ); - } - catch ( IOException ioe ) - { - // consider eating this so we can go on, or constructing the socket - // later - throw ioe; - } - } - - /** - * Creates the socket for this class. - *

- * @param multicastAddressString - * @param multicastPort - * @throws IOException - */ - private void createSocket( String multicastAddressString, int multicastPort ) - throws IOException - { - try - { - mSocket = new MulticastSocket( multicastPort ); - if ( log.isInfoEnabled() ) - { - log.info( "Joining Group: [" + InetAddress.getByName( multicastAddressString ) + "]" ); - } - mSocket.joinGroup( InetAddress.getByName( multicastAddressString ) ); - } - catch ( IOException e ) - { - log.error( "Could not bind to multicast address [" + InetAddress.getByName( multicastAddressString ) + ":" + multicastPort + "]", e ); - throw e; - } - } - - /** - * Highly unreliable. If it is processing one message while another comes in, the second - * message is lost. This is for low concurrency peppering. - *

- * @return the object message - * @throws IOException - */ - public Object waitForMessage() - throws IOException - { - final DatagramPacket packet = new DatagramPacket( mBuffer, mBuffer.length ); - ObjectInputStream objectStream = null; - Object obj = null; - try - { - if ( log.isDebugEnabled() ) - { - log.debug( "Waiting for message." ); - } - - mSocket.receive( packet ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Received packet from address [" + packet.getSocketAddress() + "]" ); - } - - final ByteArrayInputStream byteStream = new ByteArrayInputStream( mBuffer, 0, packet.getLength() ); - objectStream = new ObjectInputStreamClassLoaderAware( byteStream, null ); - obj = objectStream.readObject(); - - if ( obj instanceof UDPDiscoveryMessage ) - { - // Ensure that the address we're supposed to send to is, indeed, the address - // of the machine on the other end of this connection. This guards against - // instances where we don't exactly get the right local host address - UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj; - msg.setHost(packet.getAddress().getHostAddress()); - - if ( log.isDebugEnabled() ) - { - log.debug( "Read object from address [" + packet.getSocketAddress() + "], object=[" + obj + "]" ); - } - } - } - catch ( Exception e ) - { - log.error( "Error receiving multicast packet", e ); - } - finally - { - if (objectStream != null) - { - try - { - objectStream.close(); - } - catch (IOException e) - { - log.error( "Error closing object stream", e ); - } - } - } - return obj; - } - - /** Main processing method for the LateralUDPReceiver object */ - @Override - public void run() - { - try - { - while ( !shutdown ) - { - Object obj = waitForMessage(); - - // not thread safe, but just for debugging - cnt++; - - if ( log.isDebugEnabled() ) - { - log.debug( getCnt() + " messages received." ); - } - - UDPDiscoveryMessage message = null; - - try - { - message = (UDPDiscoveryMessage) obj; - // check for null - if ( message != null ) - { - MessageHandler handler = new MessageHandler( message ); - - pooledExecutor.execute( handler ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Passed handler to executor." ); - } - } - else - { - log.warn( "message is null" ); - } - } - catch ( ClassCastException cce ) - { - log.warn( "Received unknown message type " + cce.getMessage() ); - } - } // end while - } - catch ( Exception e ) - { - log.error( "Unexpected exception in UDP receiver.", e ); - try - { - Thread.sleep( 100 ); - // TODO consider some failure count so we don't do this - // forever. - } - catch ( Exception e2 ) - { - log.error( "Problem sleeping", e2 ); - } - } - } - - /** - * @param cnt The cnt to set. - */ - public void setCnt( int cnt ) - { - this.cnt = cnt; - } - - /** - * @return Returns the cnt. - */ - public int getCnt() - { - return cnt; - } - - /** - * Separate thread run when a command comes into the UDPDiscoveryReceiver. - */ - public class MessageHandler - implements Runnable - { - /** The message to handle. Passed in during construction. */ - private UDPDiscoveryMessage message = null; - - /** - * @param message - */ - public MessageHandler( UDPDiscoveryMessage message ) - { - this.message = message; - } - - /** - * Process the message. - */ - @SuppressWarnings("synthetic-access") - @Override - public void run() - { - // consider comparing ports here instead. - if ( message.getRequesterId() == CacheInfo.listenerId ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Ignoring message sent from self" ); - } - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Process message sent from another" ); - log.debug( "Message = " + message ); - } - - if ( message.getHost() == null || message.getCacheNames() == null || message.getCacheNames().isEmpty() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Ignoring invalid message: " + message ); - } - } - else - { - processMessage(); - } - } - } - - /** - * Process the incoming message. - */ - @SuppressWarnings("synthetic-access") - private void processMessage() - { - DiscoveredService discoveredService = new DiscoveredService(); - discoveredService.setServiceAddress( message.getHost() ); - discoveredService.setCacheNames( message.getCacheNames() ); - discoveredService.setServicePort( message.getPort() ); - discoveredService.setLastHearFromTime( System.currentTimeMillis() ); - - // if this is a request message, have the service handle it and - // return - if ( message.getMessageType() == BroadcastType.REQUEST ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Message is a Request Broadcast, will have the service handle it." ); - } - service.serviceRequestBroadcast(); - return; - } - else if ( message.getMessageType() == BroadcastType.REMOVE ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Removing service from set " + discoveredService ); - } - service.removeDiscoveredService( discoveredService ); - } - else - { - service.addOrUpdateService( discoveredService ); - } - } - } - - /** Shuts down the socket. */ - @Override - public void shutdown() - { - try - { - shutdown = true; - mSocket.leaveGroup( InetAddress.getByName( multicastAddressString ) ); - mSocket.close(); - pooledExecutor.shutdownNow(); - } - catch ( IOException e ) - { - log.error( "Problem closing socket" ); - } - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoverySender.java b/src/org/apache/commons/jcs/utils/discovery/UDPDiscoverySender.java deleted file mode 100644 index 6b8c9e71531..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoverySender.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.CacheInfo; -import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType; -import org.apache.commons.jcs.utils.serialization.StandardSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; -import java.net.MulticastSocket; -import java.util.ArrayList; - -/** - * This is a generic sender for the UDPDiscovery process. - *

- * @author Aaron Smuts - */ -public class UDPDiscoverySender -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( UDPDiscoverySender.class ); - - /** The socket */ - private MulticastSocket localSocket; - - /** The address */ - private InetAddress multicastAddress; - - /** The port */ - private final int multicastPort; - - /** Used to serialize messages */ - private final StandardSerializer serializer = new StandardSerializer(); - - /** - * Constructor for the UDPDiscoverySender object - *

- * This sender can be used to send multiple messages. - *

- * When you are done sending, you should destroy the socket sender. - *

- * @param host - * @param port - * @throws IOException - */ - public UDPDiscoverySender( String host, int port ) - throws IOException - { - try - { - if ( log.isDebugEnabled() ) - { - log.debug( "Constructing socket for sender on port [" + port + "]" ); - } - localSocket = new MulticastSocket( port ); - - // Remote address. - multicastAddress = InetAddress.getByName( host ); - } - catch ( IOException e ) - { - log.error( "Could not bind to multicast address [" + host + "]", e ); - - throw e; - } - - multicastPort = port; - } - - /** - * Closes the socket connection. - */ - public void destroy() - { - try - { - if ( this.localSocket != null && !this.localSocket.isClosed() ) - { - this.localSocket.close(); - } - } - catch ( Exception e ) - { - log.error( "Problem destrying sender", e ); - } - } - - /** - * Just being careful about closing the socket. - *

- * @throws Throwable - */ - @Override - protected void finalize() - throws Throwable - { - super.finalize(); - destroy(); - } - - /** - * Send messages. - *

- * @param message - * @throws IOException - */ - public void send( UDPDiscoveryMessage message ) - throws IOException - { - if ( this.localSocket == null ) - { - throw new IOException( "Socket is null, cannot send message." ); - } - - if ( this.localSocket.isClosed() ) - { - throw new IOException( "Socket is closed, cannot send message." ); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "sending UDPDiscoveryMessage, address [" + multicastAddress + "], port [" + multicastPort - + "], message = " + message ); - } - - try - { - final byte[] bytes = serializer.serialize( message ); - - // put the byte array in a packet - final DatagramPacket packet = new DatagramPacket( bytes, bytes.length, multicastAddress, multicastPort ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Sending DatagramPacket. bytes.length [" + bytes.length + "] to " + multicastAddress + ":" - + multicastPort ); - } - - localSocket.send( packet ); - } - catch ( IOException e ) - { - log.error( "Error sending message", e ); - throw e; - } - } - - /** - * Ask other to broadcast their info the the multicast address. If a lateral is non receiving it - * can use this. This is also called on startup so we can get info. - *

- * @throws IOException - */ - public void requestBroadcast() - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "sending requestBroadcast " ); - } - - UDPDiscoveryMessage message = new UDPDiscoveryMessage(); - message.setRequesterId( CacheInfo.listenerId ); - message.setMessageType( BroadcastType.REQUEST ); - send( message ); - } - - /** - * This sends a message broadcasting out that the host and port is available for connections. - *

- * It uses the vmid as the requesterDI - * @param host - * @param port - * @param cacheNames - * @throws IOException - */ - public void passiveBroadcast( String host, int port, ArrayList cacheNames ) - throws IOException - { - passiveBroadcast( host, port, cacheNames, CacheInfo.listenerId ); - } - - /** - * This allows you to set the sender id. This is mainly for testing. - *

- * @param host - * @param port - * @param cacheNames names of the cache regions - * @param listenerId - * @throws IOException - */ - protected void passiveBroadcast( String host, int port, ArrayList cacheNames, long listenerId ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "sending passiveBroadcast " ); - } - - UDPDiscoveryMessage message = new UDPDiscoveryMessage(); - message.setHost( host ); - message.setPort( port ); - message.setCacheNames( cacheNames ); - message.setRequesterId( listenerId ); - message.setMessageType( BroadcastType.PASSIVE ); - send( message ); - } - - /** - * This sends a message broadcasting our that the host and port is no longer available. - *

- * It uses the vmid as the requesterID - *

- * @param host host - * @param port port - * @param cacheNames names of the cache regions - * @throws IOException on error - */ - public void removeBroadcast( String host, int port, ArrayList cacheNames ) - throws IOException - { - removeBroadcast( host, port, cacheNames, CacheInfo.listenerId ); - } - - /** - * This allows you to set the sender id. This is mainly for testing. - *

- * @param host host - * @param port port - * @param cacheNames names of the cache regions - * @param listenerId listener ID - * @throws IOException on error - */ - protected void removeBroadcast( String host, int port, ArrayList cacheNames, long listenerId ) - throws IOException - { - if ( log.isDebugEnabled() ) - { - log.debug( "sending removeBroadcast " ); - } - - UDPDiscoveryMessage message = new UDPDiscoveryMessage(); - message.setHost( host ); - message.setPort( port ); - message.setCacheNames( cacheNames ); - message.setRequesterId( listenerId ); - message.setMessageType( BroadcastType.REMOVE ); - send( message ); - } -} - -/** - * This allows us to get the byte array from an output stream. - *

- * @author asmuts - * @created January 15, 2002 - */ - -class MyByteArrayOutputStream - extends ByteArrayOutputStream -{ - /** - * Gets the bytes attribute of the MyByteArrayOutputStream object - * @return The bytes value - */ - public byte[] getBytes() - { - return buf; - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderThread.java b/src/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderThread.java deleted file mode 100644 index 1332f3b009d..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderThread.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.util.ArrayList; - -/** - * Used to periodically broadcast our location to other caches that might be listening. - */ -public class UDPDiscoverySenderThread - implements Runnable -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( UDPDiscoverySenderThread.class ); - - /** - * details of the host, port, and service being advertised to listen for TCP socket connections - */ - private final UDPDiscoveryAttributes attributes; - - /** List of known regions. */ - private ArrayList cacheNames = new ArrayList(); - - /** - * @param cacheNames The cacheNames to set. - */ - protected void setCacheNames( ArrayList cacheNames ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Resetting cacheNames = [" + cacheNames + "]" ); - } - this.cacheNames = cacheNames; - } - - /** - * @return Returns the cacheNames. - */ - protected ArrayList getCacheNames() - { - return cacheNames; - } - - /** - * Constructs the sender with the port to tell others to connect to. - *

- * On construction the sender will request that the other caches let it know their addresses. - * @param attributes host, port, etc. - * @param cacheNames List of strings of the names of the region participating. - */ - public UDPDiscoverySenderThread( UDPDiscoveryAttributes attributes, ArrayList cacheNames ) - { - this.attributes = attributes; - - this.cacheNames = cacheNames; - - if ( log.isDebugEnabled() ) - { - log.debug( "Creating sender thread for discoveryAddress = [" + attributes.getUdpDiscoveryAddr() - + "] and discoveryPort = [" + attributes.getUdpDiscoveryPort() + "] myHostName = [" - + attributes.getServiceAddress() + "] and port = [" + attributes.getServicePort() + "]" ); - } - - UDPDiscoverySender sender = null; - try - { - // move this to the run method and determine how often to call it. - sender = new UDPDiscoverySender( attributes.getUdpDiscoveryAddr(), attributes.getUdpDiscoveryPort() ); - sender.requestBroadcast(); - - if ( log.isDebugEnabled() ) - { - log.debug( "Sent a request broadcast to the group" ); - } - } - catch ( Exception e ) - { - log.error( "Problem sending a Request Broadcast", e ); - } - finally - { - try - { - if ( sender != null ) - { - sender.destroy(); - } - } - catch ( Exception e ) - { - log.error( "Problem closing Request Broadcast sender", e ); - } - } - } - - /** - * Send a message. - */ - @Override - public void run() - { - UDPDiscoverySender sender = null; - try - { - // create this connection each time. - // more robust - sender = new UDPDiscoverySender( attributes.getUdpDiscoveryAddr(), attributes.getUdpDiscoveryPort() ); - - sender.passiveBroadcast( attributes.getServiceAddress(), attributes.getServicePort(), cacheNames ); - - // todo we should consider sending a request broadcast every so - // often. - - if ( log.isDebugEnabled() ) - { - log.debug( "Called sender to issue a passive broadcast" ); - } - - } - catch ( Exception e ) - { - log.error( "Problem calling the UDP Discovery Sender [" + attributes.getUdpDiscoveryAddr() + ":" - + attributes.getUdpDiscoveryPort() + "]", e ); - } - finally - { - if (sender != null) - { - try - { - sender.destroy(); - } - catch ( Exception e ) - { - log.error( "Problem closing Passive Broadcast sender", e ); - } - } - } - } - - /** - * Issues a remove broadcast to the others. - */ - protected void shutdown() - { - UDPDiscoverySender sender = null; - try - { - // create this connection each time. - // more robust - sender = new UDPDiscoverySender( attributes.getUdpDiscoveryAddr(), attributes.getUdpDiscoveryPort() ); - - sender.removeBroadcast( attributes.getServiceAddress(), attributes.getServicePort(), cacheNames ); - - if ( log.isDebugEnabled() ) - { - log.debug( "Called sender to issue a remove broadcast in shudown." ); - } - } - catch ( Exception e ) - { - log.error( "Problem calling the UDP Discovery Sender", e ); - } - finally - { - try - { - if ( sender != null ) - { - sender.destroy(); - } - } - catch ( Exception e ) - { - log.error( "Problem closing Remote Broadcast sender", e ); - } - } - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryService.java b/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryService.java deleted file mode 100644 index c802b99f731..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/UDPDiscoveryService.java +++ /dev/null @@ -1,423 +0,0 @@ -package org.apache.commons.jcs.utils.discovery; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.jcs.engine.behavior.IRequireScheduler; -import org.apache.commons.jcs.engine.behavior.IShutdownObserver; -import org.apache.commons.jcs.utils.discovery.behavior.IDiscoveryListener; -import org.apache.commons.jcs.utils.net.HostNameUtil; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This service creates a listener that can create lateral caches and add them to the no wait list. - *

- * It also creates a sender that periodically broadcasts its availability. - *

- * The sender also broadcasts a request for other caches to broadcast their addresses. - *

- * @author Aaron Smuts - */ -public class UDPDiscoveryService - implements IShutdownObserver, IRequireScheduler -{ - /** The logger */ - private static final Log log = LogFactory.getLog( UDPDiscoveryService.class ); - - /** thread that listens for messages */ - private Thread udpReceiverThread; - - /** the runnable that the receiver thread runs */ - private UDPDiscoveryReceiver receiver; - - /** the runnable that sends messages via the clock daemon */ - private UDPDiscoverySenderThread sender = null; - - /** attributes */ - private UDPDiscoveryAttributes udpDiscoveryAttributes = null; - - /** is this shut down? */ - private boolean shutdown = false; - - /** This is a set of services that have been discovered. */ - private Set discoveredServices = new CopyOnWriteArraySet(); - - /** This a list of regions that are configured to use discovery. */ - private final Set cacheNames = new CopyOnWriteArraySet(); - - /** Set of listeners. */ - private final Set discoveryListeners = new CopyOnWriteArraySet(); - - /** - * @param attributes - */ - public UDPDiscoveryService( UDPDiscoveryAttributes attributes) - { - udpDiscoveryAttributes = (UDPDiscoveryAttributes) attributes.clone(); - - try - { - // todo, you should be able to set this - udpDiscoveryAttributes.setServiceAddress( HostNameUtil.getLocalHostAddress() ); - } - catch ( UnknownHostException e ) - { - log.error( "Couldn't get localhost address", e ); - } - - try - { - // todo need some kind of recovery here. - receiver = new UDPDiscoveryReceiver( this, getUdpDiscoveryAttributes().getUdpDiscoveryAddr(), - getUdpDiscoveryAttributes().getUdpDiscoveryPort() ); - } - catch ( IOException e ) - { - log.error( "Problem creating UDPDiscoveryReceiver, address [" - + getUdpDiscoveryAttributes().getUdpDiscoveryAddr() + "] port [" - + getUdpDiscoveryAttributes().getUdpDiscoveryPort() + "] we won't be able to find any other caches", e ); - } - - // create a sender thread - sender = new UDPDiscoverySenderThread( getUdpDiscoveryAttributes(), getCacheNames() ); - } - - /** - * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) - */ - @Override - public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor) - { - if (sender != null) - { - scheduledExecutor.scheduleAtFixedRate(sender, 0, 15, TimeUnit.SECONDS); - } - - /** removes things that have been idle for too long */ - UDPCleanupRunner cleanup = new UDPCleanupRunner( this ); - // I'm going to use this as both, but it could happen - // that something could hang around twice the time using this as the - // delay and the idle time. - scheduledExecutor.scheduleAtFixedRate(cleanup, 0, getUdpDiscoveryAttributes().getMaxIdleTimeSec(), TimeUnit.SECONDS); - } - - /** - * Send a passive broadcast in response to a request broadcast. Never send a request for a - * request. We can respond to our own requests, since a request broadcast is not intended as a - * connection request. We might want to only send messages, so we would send a request, but - * never a passive broadcast. - */ - protected void serviceRequestBroadcast() - { - UDPDiscoverySender sender1 = null; - try - { - // create this connection each time. - // more robust - sender1 = new UDPDiscoverySender( getUdpDiscoveryAttributes().getUdpDiscoveryAddr(), - getUdpDiscoveryAttributes().getUdpDiscoveryPort() ); - - sender1.passiveBroadcast( getUdpDiscoveryAttributes().getServiceAddress(), getUdpDiscoveryAttributes() - .getServicePort(), this.getCacheNames() ); - - // todo we should consider sending a request broadcast every so - // often. - - if ( log.isDebugEnabled() ) - { - log.debug( "Called sender to issue a passive broadcast" ); - } - } - catch ( Exception e ) - { - log.error( "Problem calling the UDP Discovery Sender. address [" - + getUdpDiscoveryAttributes().getUdpDiscoveryAddr() + "] port [" - + getUdpDiscoveryAttributes().getUdpDiscoveryPort() + "]", e ); - } - finally - { - try - { - if ( sender1 != null ) - { - sender1.destroy(); - } - } - catch ( Exception e ) - { - log.error( "Problem closing Passive Broadcast sender, while servicing a request broadcast.", e ); - } - } - } - - /** - * Adds a region to the list that is participating in discovery. - *

- * @param cacheName - */ - public void addParticipatingCacheName( String cacheName ) - { - cacheNames.add( cacheName ); - sender.setCacheNames( getCacheNames() ); - } - - /** - * Removes the discovered service from the list and calls the discovery listener. - *

- * @param service - */ - public void removeDiscoveredService( DiscoveredService service ) - { - boolean contained = getDiscoveredServices().remove( service ); - - if ( contained ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Removing " + service ); - } - } - - for (IDiscoveryListener listener : getDiscoveryListeners()) - { - listener.removeDiscoveredService( service ); - } - } - - /** - * Add a service to the list. Update the held copy if we already know about it. - *

- * @param discoveredService discovered service - */ - protected void addOrUpdateService( DiscoveredService discoveredService ) - { - synchronized ( getDiscoveredServices() ) - { - // Since this is a set we can add it over an over. - // We want to replace the old one, since we may add info that is not part of the equals. - // The equals method on the object being added is intentionally restricted. - if ( !getDiscoveredServices().contains( discoveredService ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "Set does not contain service. I discovered " + discoveredService ); - } - if ( log.isDebugEnabled() ) - { - log.debug( "Adding service in the set " + discoveredService ); - } - getDiscoveredServices().add( discoveredService ); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Set contains service." ); - } - if ( log.isDebugEnabled() ) - { - log.debug( "Updating service in the set " + discoveredService ); - } - - // Update the list of cache names if it has changed. - DiscoveredService theOldServiceInformation = null; - // need to update the time this sucks. add has no effect convert to a map - for (DiscoveredService service1 : getDiscoveredServices()) - { - if ( discoveredService.equals( service1 ) ) - { - theOldServiceInformation = service1; - break; - } - } - if ( theOldServiceInformation != null ) - { - if ( !theOldServiceInformation.getCacheNames().equals( discoveredService.getCacheNames() ) ) - { - if ( log.isInfoEnabled() ) - { - log.info( "List of cache names changed for service: " + discoveredService ); - } - } - } - - // replace it, we want to reset the payload and the last heard from time. - getDiscoveredServices().remove( discoveredService ); - getDiscoveredServices().add( discoveredService ); - } - } - // Always Notify the listeners - // If we don't do this, then if a region using the default config is initialized after notification, - // it will never get the service in it's no wait list. - // Leave it to the listeners to decide what to do. - for (IDiscoveryListener listener : getDiscoveryListeners()) - { - listener.addDiscoveredService( discoveredService ); - } - - } - - /** - * Get all the cache names we have facades for. - *

- * @return ArrayList - */ - protected ArrayList getCacheNames() - { - ArrayList names = new ArrayList(); - names.addAll( cacheNames ); - return names; - } - - /** - * @param attr The UDPDiscoveryAttributes to set. - */ - public void setUdpDiscoveryAttributes( UDPDiscoveryAttributes attr ) - { - this.udpDiscoveryAttributes = attr; - } - - /** - * @return Returns the lca. - */ - public UDPDiscoveryAttributes getUdpDiscoveryAttributes() - { - return this.udpDiscoveryAttributes; - } - - /** - * Start necessary receiver thread - */ - public void startup() - { - udpReceiverThread = new Thread( receiver ); - udpReceiverThread.setDaemon( true ); - // udpReceiverThread.setName( t.getName() + "--UDPReceiver" ); - udpReceiverThread.start(); - } - - /** - * Shuts down the receiver. - */ - @Override - public void shutdown() - { - if ( !shutdown ) - { - shutdown = true; - - if ( log.isInfoEnabled() ) - { - log.info( "Shutting down UDP discovery service receiver." ); - } - - try - { - // no good way to do this right now. - receiver.shutdown(); - udpReceiverThread.interrupt(); - } - catch ( Exception e ) - { - log.error( "Problem interrupting UDP receiver thread." ); - } - - if ( log.isInfoEnabled() ) - { - log.info( "Shutting down UDP discovery service sender." ); - } - - // also call the shutdown on the sender thread itself, which - // will result in a remove command. - try - { - sender.shutdown(); - } - catch ( Exception e ) - { - log.error( "Problem issuing remove broadcast via UDP sender." ); - } - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Shutdown already called." ); - } - } - } - - /** - * @return Returns the discoveredServices. - */ - public synchronized Set getDiscoveredServices() - { - return discoveredServices; - } - - /** - * @return the discoveryListeners - */ - private Set getDiscoveryListeners() - { - return discoveryListeners; - } - - /** - * @return the discoveryListeners - */ - public Set getCopyOfDiscoveryListeners() - { - Set copy = new HashSet(); - copy.addAll( getDiscoveryListeners() ); - return copy; - } - - /** - * Adds a listener. - *

- * @param listener - * @return true if it wasn't already in the set - */ - public boolean addDiscoveryListener( IDiscoveryListener listener ) - { - return getDiscoveryListeners().add( listener ); - } - - /** - * Removes a listener. - *

- * @param listener - * @return true if it was in the set - */ - public boolean removeDiscoveryListener( IDiscoveryListener listener ) - { - return getDiscoveryListeners().remove( listener ); - } -} diff --git a/src/org/apache/commons/jcs/utils/discovery/behavior/IDiscoveryListener.java b/src/org/apache/commons/jcs/utils/discovery/behavior/IDiscoveryListener.java deleted file mode 100644 index 8a0d9d9e5ea..00000000000 --- a/src/org/apache/commons/jcs/utils/discovery/behavior/IDiscoveryListener.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.apache.commons.jcs.utils.discovery.behavior; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.utils.discovery.DiscoveredService; - -/** - * Interface for things that want to listen to discovery events. This will allow discovery to be - * used outside of the TCP lateral. - */ -public interface IDiscoveryListener -{ - /** - * Add the service if needed. This does not necessarily mean that the service is not already - * added. This can be called if there is a change in service information, such as the cacheNames. - *

- * @param service the service to add - */ - void addDiscoveredService( DiscoveredService service ); - - /** - * Remove the service from the list. - *

- * @param service the service to remove - */ - void removeDiscoveredService( DiscoveredService service ); -} diff --git a/src/org/apache/commons/jcs/utils/net/HostNameUtil.java b/src/org/apache/commons/jcs/utils/net/HostNameUtil.java deleted file mode 100644 index fbf02a2d3aa..00000000000 --- a/src/org/apache/commons/jcs/utils/net/HostNameUtil.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.apache.commons.jcs.utils.net; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.UnknownHostException; -import java.util.Enumeration; - -/** - * Simple utility for getting the local host name. - *

- * @author Aaron Smuts - */ -public class HostNameUtil -{ - /** The logger. */ - private static final Log log = LogFactory.getLog( HostNameUtil.class ); - - /** - * Gets the address for the local machine. - *

- * @return InetAddress.getLocalHost().getHostAddress() - * @throws UnknownHostException - */ - public static String getLocalHostAddress() throws UnknownHostException - { - try - { - String hostAddress = getLocalHostLANAddress().getHostAddress(); - if ( log.isDebugEnabled() ) - { - log.debug( "hostAddress = [" + hostAddress + "]" ); - } - return hostAddress; - } - catch ( UnknownHostException e1 ) - { - log.error( "Couldn't get localhost address", e1 ); - throw e1; - } - } - - /** - * Returns an InetAddress object encapsulating what is most likely the machine's - * LAN IP address. - *

- * This method is intended for use as a replacement of JDK method - * InetAddress.getLocalHost, because that method is ambiguous on Linux systems. - * Linux systems enumerate the loopback network interface the same way as regular LAN network - * interfaces, but the JDK InetAddress.getLocalHost method does not specify the - * algorithm used to select the address returned under such circumstances, and will often return - * the loopback address, which is not valid for network communication. Details here. - *

- * This method will scan all IP addresses on all network interfaces on the host machine to - * determine the IP address most likely to be the machine's LAN address. If the machine has - * multiple IP addresses, this method will prefer a site-local IP address (e.g. 192.168.x.x or - * 10.10.x.x, usually IPv4) if the machine has one (and will return the first site-local address - * if the machine has more than one), but if the machine does not hold a site-local address, - * this method will return simply the first non-loopback address found (IPv4 or IPv6).

- *

- * If this method cannot find a non-loopback address using this selection algorithm, it will - * fall back to calling and returning the result of JDK method - * InetAddress.getLocalHost. - *

- * JIR ISSUE JCS-40 - *

- * @return InetAddress - * @throws UnknownHostException If the LAN address of the machine cannot be found. - */ - public static InetAddress getLocalHostLANAddress() - throws UnknownHostException - { - try - { - InetAddress candidateAddress = null; - // Iterate all NICs (network interface cards)... - for ( Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) - { - NetworkInterface iface = ifaces.nextElement(); - // Iterate all IP addresses assigned to each card... - for ( Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) - { - InetAddress inetAddr = inetAddrs.nextElement(); - if ( !inetAddr.isLoopbackAddress() ) - { - if ( inetAddr.isSiteLocalAddress() ) - { - // Found non-loopback site-local address. Return it immediately... - return inetAddr; - } - else if ( candidateAddress == null ) - { - // Found non-loopback address, but not necessarily site-local. - // Store it as a candidate to be returned if site-local address is not subsequently found... - candidateAddress = inetAddr; - // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates, - // only the first. For subsequent iterations, candidate will be non-null. - } - } - } - } - if ( candidateAddress != null ) - { - // We did not find a site-local address, but we found some other non-loopback address. - // Server might have a non-site-local address assigned to its NIC (or it might be running - // IPv6 which deprecates the "site-local" concept). - // Return this non-loopback candidate address... - return candidateAddress; - } - // At this point, we did not find a non-loopback address. - // Fall back to returning whatever InetAddress.getLocalHost() returns... - InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); - if ( jdkSuppliedAddress == null ) - { - throw new UnknownHostException( "The JDK InetAddress.getLocalHost() method unexpectedly returned null." ); - } - return jdkSuppliedAddress; - } - catch ( Exception e ) - { - UnknownHostException unknownHostException = new UnknownHostException( "Failed to determine LAN address: " - + e ); - unknownHostException.initCause( e ); - throw unknownHostException; - } - } -} diff --git a/src/org/apache/commons/jcs/utils/props/AbstractPropertyContainer.java b/src/org/apache/commons/jcs/utils/props/AbstractPropertyContainer.java deleted file mode 100644 index 0c5f293c4ed..00000000000 --- a/src/org/apache/commons/jcs/utils/props/AbstractPropertyContainer.java +++ /dev/null @@ -1,190 +0,0 @@ -package org.apache.commons.jcs.utils.props; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.access.exception.ConfigurationException; - -import java.util.Properties; - -/** - * Provides a mechanism to load properties into objects. - *

- * Functions that depend on properties should call ensureProperties() before it uses any properties. - */ -public abstract class AbstractPropertyContainer -{ - /** File, db, etc */ - private static final PropertiesFactory DEFAULT_PROPERTIES_FACTORY = new PropertiesFactoryFileImpl(); - - /** - * A property group is a subsection of properties. It's sent to the properties factory to - * specify which group of properties to pull back. This will probably mean different things to - * different property factories. For PropertiesFactoryFileImpl, the propertiesGroup maps to a - * filename. - */ - private String propertiesGroup; - - /** - * The property heading is used to specify a starting point in the properties object. This is - * used so that settings can be relative to this propertiesHeading, as opposed to being - * statically coded. There's no enforcement of this, but users are encouraged to call - * getProperties().get( getPropertiesHeading() + ".foo" ); - */ - private String propertiesHeading; - - /** The factory to use. */ - private PropertiesFactory propertiesFactory; - - /** The loaded properties. */ - private Properties properties; - - /** - * Makes sure an AbstractPropertyClass has all the properties it needs. - *

- * Synchronized mutators so multiple threads cannot cause problems. We wouldn't want the - * properties heading to get changed as we were processing the properties. - *

- * @throws ConfigurationException on configuration failure - */ - public synchronized void ensureProperties() - throws ConfigurationException - { - if ( getProperties() == null ) - { - initializeProperties(); - } - } - - /** - * Loads the properties and then calls handleProperties. Typically, you don't need to call this. - * This is primarily intended for reinitialization. - *

- * If the properties object is null, when you call ensureProperties initialize will be called. - *

- * @throws ConfigurationException on configuration failure - */ - public synchronized void initializeProperties() - throws ConfigurationException - { - loadProperties(); - - handleProperties(); - } - - /** - * This loads the properties regardless of whether or not they have already been loaded. - *

- * @throws ConfigurationException on configuration failure - */ - private void loadProperties() - throws ConfigurationException - { - if ( getPropertiesGroup() == null ) - { - throw new ConfigurationException( "Properties group is null and it shouldn't be" ); - } - - if ( getPropertiesHeading() == null ) - { - throw new ConfigurationException( "Properties heading is null and it shouldn't be" ); - } - - if ( getPropertiesFactory() == null ) - { - setProperties( DEFAULT_PROPERTIES_FACTORY.getProperties( getPropertiesGroup() ) ); - } - else - { - setProperties( getPropertiesFactory().getProperties( getPropertiesGroup() ) ); - } - } - - /** - * Sets fields for properties, and verifies that all necessary properties are there. - *

- * @throws ConfigurationException on configuration failure - */ - protected abstract void handleProperties() - throws ConfigurationException; - - /** - * @return Returns the properties. - */ - public synchronized Properties getProperties() - { - return properties; - } - - /** - * @param properties The properties to set. - */ - public synchronized void setProperties( Properties properties ) - { - this.properties = properties; - } - - /** - * @return Returns the propertiesHeading. - */ - public synchronized String getPropertiesHeading() - { - return propertiesHeading; - } - - /** - * @param propertiesHeading The propertiesHeading to set. - */ - public synchronized void setPropertiesHeading( String propertiesHeading ) - { - this.propertiesHeading = propertiesHeading; - } - - /** - * @return Returns the propertiesFactory. - */ - public PropertiesFactory getPropertiesFactory() - { - return propertiesFactory; - } - - /** - * @param propertiesFactory The propertiesFactory to set. - */ - public void setPropertiesFactory( PropertiesFactory propertiesFactory ) - { - this.propertiesFactory = propertiesFactory; - } - - /** - * @return Returns the propertiesGroup. - */ - public String getPropertiesGroup() - { - return propertiesGroup; - } - - /** - * @param propertiesGroup The propertiesGroup to set. - */ - public void setPropertiesGroup( String propertiesGroup ) - { - this.propertiesGroup = propertiesGroup; - } -} diff --git a/src/org/apache/commons/jcs/utils/props/PropertiesFactory.java b/src/org/apache/commons/jcs/utils/props/PropertiesFactory.java deleted file mode 100644 index 96e40de6ff0..00000000000 --- a/src/org/apache/commons/jcs/utils/props/PropertiesFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.apache.commons.jcs.utils.props; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Properties; - -/** - * Retrieves properties from a configurable source. - */ -public interface PropertiesFactory -{ - /** - * Fetches a set of properties for the specified group. - *

- * @param groupName the group to pull properties from. - * @return a properties object. - */ - Properties getProperties( String groupName ); -} diff --git a/src/org/apache/commons/jcs/utils/props/PropertiesFactoryFileImpl.java b/src/org/apache/commons/jcs/utils/props/PropertiesFactoryFileImpl.java deleted file mode 100644 index 5630ca47d0c..00000000000 --- a/src/org/apache/commons/jcs/utils/props/PropertiesFactoryFileImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.apache.commons.jcs.utils.props; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.Properties; - -/** - * Goes to the file system to load a properties file. - */ -public class PropertiesFactoryFileImpl - implements PropertiesFactory -{ - /** - * Loads the properties using the property loader. - * @param groupName property group name - * @return Properties - */ - @Override - public Properties getProperties( String groupName ) - { - return PropertyLoader.loadProperties( groupName ); - } -} diff --git a/src/org/apache/commons/jcs/utils/props/PropertyLoader.java b/src/org/apache/commons/jcs/utils/props/PropertyLoader.java deleted file mode 100644 index 1baaf0a6cb2..00000000000 --- a/src/org/apache/commons/jcs/utils/props/PropertyLoader.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.apache.commons.jcs.utils.props; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.InputStream; -import java.util.Properties; - -/** - * I modified this class to work with .ccf files in particular. I also removed - * the resource bundle functionality. - *

- * A simple class for loading java.util.Properties backed by .ccf files deployed - * as classpath resources. See individual methods for details. - *

- * The original source is from: - *

- * @author (C) Vlad - * Roubtsov , 2003 - */ -public abstract class PropertyLoader -{ - /** throw an error if we can load the file */ - private static final boolean THROW_ON_LOAD_FAILURE = true; - - /** File suffix. */ - private static final String SUFFIX = ".ccf"; - - /** property suffix */ - private static final String SUFFIX_PROPERTIES = ".properties"; - - /** - * Looks up a resource named 'name' in the classpath. The resource must map - * to a file with .ccf extention. The name is assumed to be absolute and can - * use either "/" or "." for package segment separation with an optional - * leading "/" and optional ".ccf" suffix. - *

- * The suffix ".ccf" will be appended if it is not set. This can also handle - * .properties files - *

- * Thus, the following names refer to the same resource: - * - *

-     *
-     *       some.pkg.Resource
-     *       some.pkg.Resource.ccf
-     *       some/pkg/Resource
-     *       some/pkg/Resource.ccf
-     *       /some/pkg/Resource
-     *       /some/pkg/Resource.ccf
-     * 
- * - * @param name - * classpath resource name [may not be null] - * @param loader - * classloader through which to load the resource [null is - * equivalent to the application loader] - * @return resource converted to java.util.properties [may be null if the - * resource was not found and THROW_ON_LOAD_FAILURE is false] - * @throws IllegalArgumentException - * if the resource was not found and THROW_ON_LOAD_FAILURE is - * true - */ - public static Properties loadProperties( String name, ClassLoader loader ) - { - boolean isCCFSuffix = true; - - if ( name == null ) - throw new IllegalArgumentException( "null input: name" ); - - ClassLoader classLoader = ( loader == null ) ? ClassLoader.getSystemClassLoader() : loader; - - String fileName = name.startsWith( "/" ) ? name.substring( 1 ) : name; - - if ( fileName.endsWith( SUFFIX ) ) - { - fileName = fileName.substring( 0, fileName.length() - SUFFIX.length() ); - } - - if ( fileName.endsWith( SUFFIX_PROPERTIES ) ) - { - fileName = fileName.substring( 0, fileName.length() - SUFFIX_PROPERTIES.length() ); - isCCFSuffix = false; - } - - Properties result = null; - - InputStream in = null; - try - { - fileName = fileName.replace( '.', '/' ); - - if ( !fileName.endsWith( SUFFIX ) && isCCFSuffix ) - { - fileName = fileName.concat( SUFFIX ); - } - else if ( !fileName.endsWith( SUFFIX_PROPERTIES ) && !isCCFSuffix ) - { - fileName = fileName.concat( SUFFIX_PROPERTIES ); - } - - // returns null on lookup failures: - in = classLoader.getResourceAsStream( fileName ); - if ( in != null ) - { - result = new Properties(); - result.load( in ); // can throw IOException - } - } - catch ( Exception e ) - { - result = null; - } - finally - { - if ( in != null ) - try - { - in.close(); - } - catch ( Throwable ignore ) - { - // swallow - } - } - - if ( THROW_ON_LOAD_FAILURE && result == null ) - { - throw new IllegalArgumentException( "could not load [" + fileName + "]" + " as " + "a classloader resource" ); - } - - return result; - } - - /** - * A convenience overload of {@link #loadProperties(String, ClassLoader)} - * that uses the current thread's context classloader. A better strategy - * would be to use techniques shown in - * http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html - *

- * @param name - * @return Properties - */ - public static Properties loadProperties( final String name ) - { - return loadProperties( name, Thread.currentThread().getContextClassLoader() ); - } - - /** - * Can't use this one. - */ - private PropertyLoader() - { - super(); - } // this class is not extentible - -} diff --git a/src/org/apache/commons/jcs/utils/serialization/CompressingSerializer.java b/src/org/apache/commons/jcs/utils/serialization/CompressingSerializer.java deleted file mode 100644 index e9f6af685f1..00000000000 --- a/src/org/apache/commons/jcs/utils/serialization/CompressingSerializer.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.apache.commons.jcs.utils.serialization; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware; -import org.apache.commons.jcs.utils.zip.CompressionUtil; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * Performs default serialization and de-serialization. It gzips the value. - */ -public class CompressingSerializer - implements IElementSerializer -{ - /** - * Serializes an object using default serialization. Compresses the byte array. - *

- * @param obj object - * @return byte[] - * @throws IOException on i/o problem - */ - @Override - public byte[] serialize( T obj ) - throws IOException - { - byte[] uncompressed = serializeObject( obj ); - byte[] compressed = CompressionUtil.compressByteArray( uncompressed ); - return compressed; - } - - /** - * Does the basic serialization. - *

- * @param obj object - * @return byte[] - * @throws IOException on i/o problem - */ - protected byte[] serializeObject( T obj ) - throws IOException - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream( baos ); - try - { - oos.writeObject( obj ); - } - finally - { - oos.close(); - } - byte[] uncompressed = baos.toByteArray(); - return uncompressed; - } - - /** - * Uses default de-serialization to turn a byte array into an object. Decompresses the value - * first. All exceptions are converted into IOExceptions. - *

- * @param data bytes of data - * @return Object - * @throws IOException on i/o problem - * @throws ClassNotFoundException if class is not found during deserialization - */ - @Override - public T deSerialize( byte[] data, ClassLoader loader ) - throws IOException, ClassNotFoundException - { - if ( data == null ) - { - return null; - } - byte[] decompressedByteArray = CompressionUtil.decompressByteArray( data ); - return deserializeObject( decompressedByteArray ); - } - - /** - * Does the standard deserialization. - *

- * @param decompressedByteArray array of decompressed bytes - * @return Object - * @throws IOException on i/o error - * @throws ClassNotFoundException if class is not found during deserialization - */ - protected T deserializeObject( byte[] decompressedByteArray ) - throws IOException, ClassNotFoundException - { - ByteArrayInputStream bais = new ByteArrayInputStream( decompressedByteArray ); - BufferedInputStream bis = new BufferedInputStream( bais ); - ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( bis, null ); - - try - { - @SuppressWarnings("unchecked") // Need to cast from Object - T readObject = (T) ois.readObject(); - return readObject; - } - finally - { - ois.close(); - } - } -} diff --git a/src/org/apache/commons/jcs/utils/serialization/SerializationConversionUtil.java b/src/org/apache/commons/jcs/utils/serialization/SerializationConversionUtil.java deleted file mode 100644 index 35c945ce695..00000000000 --- a/src/org/apache/commons/jcs/utils/serialization/SerializationConversionUtil.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.apache.commons.jcs.utils.serialization; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.CacheElement; -import org.apache.commons.jcs.engine.CacheElementSerialized; -import org.apache.commons.jcs.engine.behavior.ICacheElement; -import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized; -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.IOException; - -/** - * This uses a supplied Serializer to convert to and from cache elements. - *

- * @author Aaron Smuts - */ -public class SerializationConversionUtil -{ - /** The logger */ - private static final Log log = LogFactory.getLog( SerializationConversionUtil.class ); - - /** - * This returns a wrapper that has a serialized version of the value instead - * of the value. - *

- * @param element - * @param elementSerializer - * the serializer to be used. - * @return null for null; - * @throws IOException - */ - public static ICacheElementSerialized getSerializedCacheElement( ICacheElement element, - IElementSerializer elementSerializer ) - throws IOException - { - if ( element == null ) - { - return null; - } - - byte[] serializedValue = null; - - // if it has already been serialized, don't do it again. - if ( element instanceof ICacheElementSerialized ) - { - serializedValue = ( (ICacheElementSerialized) element ).getSerializedValue(); - } - else - { - if ( elementSerializer != null ) - { - try - { - serializedValue = elementSerializer.serialize( element.getVal() ); - } - catch ( IOException e ) - { - log.error( "Problem serializing object.", e ); - throw e; - } - } - else - { - // we could just use the default. - log.warn( "ElementSerializer is null. Could not serialize object." ); - throw new IOException( "Could not serialize object. The ElementSerializer is null." ); - } - } - ICacheElementSerialized serialized = new CacheElementSerialized( - element.getCacheName(), element.getKey(), serializedValue, element.getElementAttributes() ); - - return serialized; - } - - /** - * This returns a wrapper that has a de-serialized version of the value - * instead of the serialized value. - *

- * @param serialized - * @param elementSerializer - * the serializer to be used. - * @return null for null; - * @throws IOException - * @throws ClassNotFoundException - */ - public static ICacheElement getDeSerializedCacheElement( ICacheElementSerialized serialized, - IElementSerializer elementSerializer ) - throws IOException, ClassNotFoundException - { - if ( serialized == null ) - { - return null; - } - - V deSerializedValue = null; - - if ( elementSerializer != null ) - { - try - { - try - { - deSerializedValue = elementSerializer.deSerialize( serialized.getSerializedValue(), null ); - } - catch ( ClassNotFoundException e ) - { - log.error( "Problem de-serializing object.", e ); - throw e; - } - } - catch ( IOException e ) - { - log.error( "Problem de-serializing object.", e ); - throw e; - } - } - else - { - // we could just use the default. - log.warn( "ElementSerializer is null. Could not serialize object." ); - } - ICacheElement deSerialized = new CacheElement( serialized.getCacheName(), serialized.getKey(), deSerializedValue ); - deSerialized.setElementAttributes( serialized.getElementAttributes() ); - - return deSerialized; - } -} diff --git a/src/org/apache/commons/jcs/utils/serialization/StandardSerializer.java b/src/org/apache/commons/jcs/utils/serialization/StandardSerializer.java deleted file mode 100644 index 455b9626efe..00000000000 --- a/src/org/apache/commons/jcs/utils/serialization/StandardSerializer.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.apache.commons.jcs.utils.serialization; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.jcs.engine.behavior.IElementSerializer; -import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * Performs default serialization and de-serialization. - *

- * @author Aaron Smuts - */ -public class StandardSerializer - implements IElementSerializer -{ - /** - * Serializes an object using default serialization. - *

- * @param obj - * @return byte[] - * @throws IOException - */ - @Override - public byte[] serialize( T obj ) - throws IOException - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream( baos ); - try - { - oos.writeObject( obj ); - } - finally - { - oos.close(); - } - return baos.toByteArray(); - } - - /** - * Uses default de-serialization to turn a byte array into an object. All exceptions are - * converted into IOExceptions. - *

- * @param data - * @return Object - * @throws IOException - * @throws ClassNotFoundException - */ - @Override - public T deSerialize( byte[] data, ClassLoader loader ) - throws IOException, ClassNotFoundException - { - ByteArrayInputStream bais = new ByteArrayInputStream( data ); - BufferedInputStream bis = new BufferedInputStream( bais ); - ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( bis, loader ); - try - { - @SuppressWarnings("unchecked") // Need to cast from Object - T readObject = (T) ois.readObject(); - return readObject; - } - finally - { - ois.close(); - } - } -} diff --git a/src/org/apache/commons/jcs/utils/servlet/JCSServletContextListener.java b/src/org/apache/commons/jcs/utils/servlet/JCSServletContextListener.java deleted file mode 100644 index 67c9b86f477..00000000000 --- a/src/org/apache/commons/jcs/utils/servlet/JCSServletContextListener.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.apache.commons.jcs.utils.servlet; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.apache.commons.jcs.JCS; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * If you add this to the context listeners section of your web.xml file, this will shutdown JCS - * gracefully. - *

- * Add the following to the top of your web.xml file. - * - *

- *  <listener>
- *  <listener-class>
- *  org.apache.commons.jcs.utils.servlet.JCSServletContextListener
- *  </listener-class>
- *  </listener>
- * 
- * @author Aaron Smuts - */ -public class JCSServletContextListener - implements ServletContextListener -{ - /** The logger */ - private static final Log log = LogFactory.getLog( JCSServletContextListener.class ); - - /** - * This does nothing. We don't want to initialize the cache here. - *

- * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) - */ - @Override - public void contextInitialized( ServletContextEvent arg0 ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "contextInitialized" ); - } - } - - /** - * Shutdown JCS. - *

- * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) - */ - @Override - public void contextDestroyed( ServletContextEvent arg0 ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "contextDestroyed, shutting down JCS." ); - } - - JCS.shutdown(); - } -} diff --git a/src/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java b/src/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java deleted file mode 100644 index 9effd978216..00000000000 --- a/src/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java +++ /dev/null @@ -1,592 +0,0 @@ -package org.apache.commons.jcs.utils.struct; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.apache.commons.jcs.engine.control.group.GroupAttrName; -import org.apache.commons.jcs.engine.stats.StatElement; -import org.apache.commons.jcs.engine.stats.Stats; -import org.apache.commons.jcs.engine.stats.behavior.IStatElement; -import org.apache.commons.jcs.engine.stats.behavior.IStats; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This is a simple LRUMap. It implements most of the map methods. It is not recommended that you - * use any but put, get, remove, and clear. - *

- * Children can implement the processRemovedLRU method if they want to handle the removal of the - * lest recently used item. - *

- * This class was abstracted out of the LRU Memory cache. Put, remove, and get should be thread - * safe. It uses a hashtable and our own double linked list. - *

- * Locking is done on the instance. - *

- * @author aaron smuts - */ -public abstract class AbstractLRUMap - implements Map -{ - /** The logger */ - private static final Log log = LogFactory.getLog( AbstractLRUMap.class ); - - /** double linked list for lru */ - private final DoubleLinkedList> list; - - /** Map where items are stored by key. */ - private final Map> map; - - /** lock to keep map and list synchronous */ - private final Lock lock = new ReentrantLock(); - - /** stats */ - private long hitCnt = 0; - - /** stats */ - private long missCnt = 0; - - /** stats */ - private long putCnt = 0; - - /** - * This creates an unbounded version. Setting the max objects will result in spooling on - * subsequent puts. - */ - public AbstractLRUMap() - { - list = new DoubleLinkedList>(); - - // normal hashtable is faster for - // sequential keys. - map = new ConcurrentHashMap>(); - } - - - /** - * This simply returns the number of elements in the map. - *

- * @see java.util.Map#size() - */ - @Override - public int size() - { - return map.size(); - } - - /** - * This removes all the items. It clears the map and the double linked list. - *

- * @see java.util.Map#clear() - */ - @Override - public void clear() - { - lock.lock(); - try - { - map.clear(); - list.removeAll(); - } - finally - { - lock.unlock(); - } - } - - /** - * Returns true if the map is empty. - *

- * @see java.util.Map#isEmpty() - */ - @Override - public boolean isEmpty() - { - return map.isEmpty(); - } - - /** - * Returns true if the map contains an element for the supplied key. - *

- * @see java.util.Map#containsKey(java.lang.Object) - */ - @Override - public boolean containsKey( Object key ) - { - return map.containsKey( key ); - } - - /** - * This is an expensive operation that determines if the object supplied is mapped to any key. - *

- * @see java.util.Map#containsValue(java.lang.Object) - */ - @Override - public boolean containsValue( Object value ) - { - return map.containsValue( value ); - } - - /** - * @return map.values(); - */ - @Override - public Collection values() - { - List valueList = new ArrayList(map.size()); - - for (LRUElementDescriptor value : map.values()) - { - valueList.add(value.getPayload()); - } - - return valueList; - } - - /** - * @param source - */ - @Override - public void putAll( Map source ) - { - if ( source != null ) - { - for (Map.Entry entry : source.entrySet()) - { - this.put( entry.getKey(), entry.getValue() ); - } - } - } - - /** - * @param key - * @return Object - */ - @Override - public V get( Object key ) - { - V retVal; - - if ( log.isDebugEnabled() ) - { - log.debug( "getting item for key " + key ); - } - - LRUElementDescriptor me = map.get( key ); - - if ( me == null ) - { - missCnt++; - retVal = null; - } - else - { - hitCnt++; - retVal = me.getPayload(); - list.makeFirst( me ); - } - - if ( log.isDebugEnabled() ) - { - if ( me == null ) - { - log.debug( "LRUMap miss for " + key ); - } - else - { - log.debug( "LRUMap hit for " + key ); - } - } - - // verifyCache(); - return retVal; - } - - /** - * This gets an element out of the map without adjusting it's position in the LRU. In other - * words, this does not count as being used. If the element is the last item in the list, it - * will still be the last time in the list. - *

- * @param key - * @return Object - */ - public V getQuiet( Object key ) - { - V ce = null; - LRUElementDescriptor me = map.get( key ); - - if ( me != null ) - { - ce = me.getPayload(); - } - - if ( log.isDebugEnabled() ) - { - if ( me == null ) - { - log.debug( "LRUMap quiet miss for " + key ); - } - else - { - log.debug( "LRUMap quiet hit for " + key ); - } - } - - return ce; - } - - /** - * @param key - * @return Object removed - */ - @Override - public V remove( Object key ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "removing item for key: " + key ); - } - - // remove single item. - lock.lock(); - try - { - LRUElementDescriptor me = map.remove(key); - - if (me != null) - { - list.remove(me); - return me.getPayload(); - } - } - finally - { - lock.unlock(); - } - - return null; - } - - /** - * @param key - * @param value - * @return Object - */ - @Override - public V put(K key, V value) - { - putCnt++; - - LRUElementDescriptor old = null; - LRUElementDescriptor me = new LRUElementDescriptor(key, value); - - lock.lock(); - try - { - list.addFirst( me ); - old = map.put(key, me); - - // If the node was the same as an existing node, remove it. - if ( old != null && key.equals(old.getKey())) - { - list.remove( old ); - } - } - finally - { - lock.unlock(); - } - - // If the element limit is reached, we need to spool - if (shouldRemove()) - { - if (log.isDebugEnabled()) - { - log.debug( "In memory limit reached, removing least recently used." ); - } - - // The spool will put them in a disk event queue, so there is no - // need to pre-queue the queuing. This would be a bit wasteful - // and wouldn't save much time in this synchronous call. - while ( shouldRemove() ) - { - lock.lock(); - try - { - LRUElementDescriptor last = list.getLast(); - if (last != null) - { - processRemovedLRU(last.getKey(), last.getPayload()); - if (map.remove(last.getKey()) == null) - { - log.warn("update: remove failed for key: " - + last.getKey()); - verifyCache(); - } - list.removeLast(); - } - else - { - verifyCache(); - throw new Error("update: last is null!"); - } - } - finally - { - lock.unlock(); - } - } - - if ( log.isDebugEnabled() ) - { - log.debug( "update: After spool map size: " + map.size() ); - } - if ( map.size() != list.size() ) - { - log.error("update: After spool, size mismatch: map.size() = " + map.size() + - ", linked list size = " + list.size()); - } - } - - if ( old != null ) - { - return old.getPayload(); - } - return null; - } - - protected abstract boolean shouldRemove(); - - /** - * Dump the cache entries from first to list for debugging. - */ - @SuppressWarnings("unchecked") // No generics for public fields - public void dumpCacheEntries() - { - log.debug( "dumpingCacheEntries" ); - for ( LRUElementDescriptor me = list.getFirst(); me != null; me = (LRUElementDescriptor) me.next ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "dumpCacheEntries> key=" + me.getKey() + ", val=" + me.getPayload() ); - } - } - } - - /** - * Dump the cache map for debugging. - */ - public void dumpMap() - { - log.debug( "dumpingMap" ); - for (Map.Entry> e : map.entrySet()) - { - LRUElementDescriptor me = e.getValue(); - if ( log.isDebugEnabled() ) - { - log.debug( "dumpMap> key=" + e.getKey() + ", val=" + me.getPayload() ); - } - } - } - - /** - * Checks to see if all the items that should be in the cache are. Checks consistency between - * List and map. - */ - @SuppressWarnings("unchecked") // No generics for public fields - protected void verifyCache() - { - if ( !log.isDebugEnabled() ) - { - return; - } - - boolean found = false; - log.debug( "verifycache: mapContains " + map.size() + - " elements, linked list contains " + list.size() + " elements" ); - log.debug( "verifycache: checking linked list by key " ); - for (LRUElementDescriptor li = list.getFirst(); li != null; li = (LRUElementDescriptor) li.next ) - { - K key = li.getKey(); - if ( !map.containsKey( key ) ) - { - log.error( "verifycache: map does not contain key : " + li.getKey() ); - log.error( "li.hashcode=" + li.getKey().hashCode() ); - log.error( "key class=" + key.getClass() ); - log.error( "key hashcode=" + key.hashCode() ); - log.error( "key toString=" + key.toString() ); - if ( key instanceof GroupAttrName ) - { - GroupAttrName name = (GroupAttrName) key; - log.error( "GroupID hashcode=" + name.groupId.hashCode() ); - log.error( "GroupID.class=" + name.groupId.getClass() ); - log.error( "AttrName hashcode=" + name.attrName.hashCode() ); - log.error( "AttrName.class=" + name.attrName.getClass() ); - } - dumpMap(); - } - else if ( map.get( li.getKey() ) == null ) - { - log.error( "verifycache: linked list retrieval returned null for key: " + li.getKey() ); - } - } - - log.debug( "verifycache: checking linked list by value " ); - for (LRUElementDescriptor li3 = list.getFirst(); li3 != null; li3 = (LRUElementDescriptor) li3.next ) - { - if ( map.containsValue( li3 ) == false ) - { - log.error( "verifycache: map does not contain value : " + li3 ); - dumpMap(); - } - } - - log.debug( "verifycache: checking via keysets!" ); - for (Iterator itr2 = map.keySet().iterator(); itr2.hasNext(); ) - { - found = false; - Serializable val = null; - try - { - val = (Serializable) itr2.next(); - } - catch ( NoSuchElementException nse ) - { - log.error( "verifycache: no such element exception" ); - continue; - } - - for (LRUElementDescriptor li2 = list.getFirst(); li2 != null; li2 = (LRUElementDescriptor) li2.next ) - { - if ( val.equals( li2.getKey() ) ) - { - found = true; - break; - } - } - if ( !found ) - { - log.error( "verifycache: key not found in list : " + val ); - dumpCacheEntries(); - if ( map.containsKey( val ) ) - { - log.error( "verifycache: map contains key" ); - } - else - { - log.error( "verifycache: map does NOT contain key, what the HECK!" ); - } - } - } - } - - /** - * This is called when an item is removed from the LRU. We just log some information. - *

- * Children can implement this method for special behavior. - * @param key - * @param value - */ - protected void processRemovedLRU(K key, V value ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Removing key: [" + key + "] from LRUMap store, value = [" + value + "]" ); - log.debug( "LRUMap store size: '" + this.size() + "'." ); - } - } - - /** - * @return IStats - */ - public IStats getStatistics() - { - IStats stats = new Stats(); - stats.setTypeName( "LRUMap" ); - - ArrayList> elems = new ArrayList>(); - - elems.add(new StatElement( "List Size", Integer.valueOf(list.size()) ) ); - elems.add(new StatElement( "Map Size", Integer.valueOf(map.size()) ) ); - elems.add(new StatElement( "Put Count", Long.valueOf(putCnt) ) ); - elems.add(new StatElement( "Hit Count", Long.valueOf(hitCnt) ) ); - elems.add(new StatElement( "Miss Count", Long.valueOf(missCnt) ) ); - - stats.setStatElements( elems ); - - return stats; - } - - /** - * This returns a set of entries. Our LRUMapEntry is used since the value stored in the - * underlying map is a node in the double linked list. We wouldn't want to return this to the - * client, so we construct a new entry with the payload of the node. - *

- * TODO we should return out own set wrapper, so we can avoid the extra object creation if it - * isn't necessary. - *

- * @see java.util.Map#entrySet() - */ - @Override - public Set> entrySet() - { - lock.lock(); - try - { - // TODO we should return a defensive copy - Set>> entries = map.entrySet(); - Set> unWrapped = new HashSet>(); - - for (Map.Entry> pre : entries) { - Map.Entry post = new LRUMapEntry(pre.getKey(), pre.getValue().getPayload()); - unWrapped.add(post); - } - - return unWrapped; - } - finally - { - lock.unlock(); - } - } - - /** - * @return map.keySet(); - */ - @Override - public Set keySet() - { - // TODO fix this, it needs to return the keys inside the wrappers. - return map.keySet(); - } - -} diff --git a/src/org/apache/commons/jcs/utils/struct/DoubleLinkedList.java b/src/org/apache/commons/jcs/utils/struct/DoubleLinkedList.java deleted file mode 100644 index e83a82cd1bc..00000000000 --- a/src/org/apache/commons/jcs/utils/struct/DoubleLinkedList.java +++ /dev/null @@ -1,303 +0,0 @@ -package org.apache.commons.jcs.utils.struct; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This is a generic thread safe double linked list. It's very simple and all the operations are so - * quick that course grained synchronization is more than acceptable. - */ -@SuppressWarnings({ "unchecked", "rawtypes" }) // Don't know how to resolve this with generics -public class DoubleLinkedList -{ - /** record size to avoid having to iterate */ - private int size = 0; - - /** The logger */ - private static final Log log = LogFactory.getLog( DoubleLinkedList.class ); - - /** LRU double linked list head node */ - private T first; - - /** LRU double linked list tail node */ - private T last; - - /** - * Default constructor. - */ - public DoubleLinkedList() - { - super(); - } - - /** - * Adds a new node to the end of the link list. - *

- * @param me The feature to be added to the Last - */ - public synchronized void addLast(T me) - { - if ( first == null ) - { - // empty list. - first = me; - } - else - { - last.next = me; - me.prev = last; - } - last = me; - size++; - } - - /** - * Adds a new node to the start of the link list. - *

- * @param me The feature to be added to the First - */ - public synchronized void addFirst(T me) - { - if ( last == null ) - { - // empty list. - last = me; - } - else - { - first.prev = me; - me.next = first; - } - first = me; - size++; - } - - /** - * Returns the last node from the link list, if there are any nodes. - *

- * @return The last node. - */ - public synchronized T getLast() - { - if ( log.isDebugEnabled() ) - { - log.debug( "returning last node" ); - } - return last; - } - - /** - * Removes the specified node from the link list. - *

- * @return DoubleLinkedListNode, the first node. - */ - public synchronized T getFirst() - { - if ( log.isDebugEnabled() ) - { - log.debug( "returning first node" ); - } - return first; - } - - /** - * Moves an existing node to the start of the link list. - *

- * @param ln The node to set as the head. - */ - public synchronized void makeFirst(T ln) - { - if ( ln.prev == null ) - { - // already the first node. or not a node - return; - } - // splice: remove it from the list - ln.prev.next = ln.next; - - if ( ln.next == null ) - { - // last but not the first. - last = (T) ln.prev; - last.next = null; - } - else - { - // neither the last nor the first. - ln.next.prev = ln.prev; - } - first.prev = ln; - ln.next = first; - ln.prev = null; - first = ln; - } - - /** - * Moves an existing node to the end of the link list. - *

- * @param ln The node to set as the head. - */ - public synchronized void makeLast(T ln) - { - if ( ln.next == null ) - { - // already the last node. or not a node - return; - } - // splice: remove it from the list - if ( ln.prev != null ) - { - ln.prev.next = ln.next; - } - else - { - // first - first = last; - } - - if ( last != null ) - { - last.next = ln; - } - ln.prev = last; - ln.next = null; - last = ln; - } - - /** - * Remove all of the elements from the linked list implementation. - */ - public synchronized void removeAll() - { - for (T me = first; me != null; ) - { - if ( me.prev != null ) - { - me.prev = null; - } - T next = (T) me.next; - me = next; - } - first = last = null; - // make sure this will work, could be add while this is happening. - size = 0; - } - - /** - * Removes the specified node from the link list. - *

- * @param me Description of the Parameter - * @return true if an element was removed. - */ - public synchronized boolean remove(T me) - { - if ( log.isDebugEnabled() ) - { - log.debug( "removing node" ); - } - - if ( me.next == null ) - { - if ( me.prev == null ) - { - // Make sure it really is the only node before setting head and - // tail to null. It is possible that we will be passed a node - // which has already been removed from the list, in which case - // we should ignore it - - if ( me == first && me == last ) - { - first = last = null; - } - } - else - { - // last but not the first. - last = (T) me.prev; - last.next = null; - me.prev = null; - } - } - else if ( me.prev == null ) - { - // first but not the last. - first = (T) me.next; - first.prev = null; - me.next = null; - } - else - { - // neither the first nor the last. - me.prev.next = me.next; - me.next.prev = me.prev; - me.prev = me.next = null; - } - size--; - - return true; - } - - /** - * Removes the specified node from the link list. - *

- * @return The last node if there was one to remove. - */ - public synchronized T removeLast() - { - if ( log.isDebugEnabled() ) - { - log.debug( "removing last node" ); - } - T temp = last; - if ( last != null ) - { - remove( last ); - } - return temp; - } - - /** - * Returns the size of the list. - *

- * @return int - */ - public synchronized int size() - { - return size; - } - - // /////////////////////////////////////////////////////////////////// - /** - * Dump the cache entries from first to list for debugging. - */ - public synchronized void debugDumpEntries() - { - if ( log.isDebugEnabled() ) - { - log.debug( "dumping Entries" ); - for (T me = first; me != null; me = (T) me.next) - { - log.debug( "dump Entries> payload= '" + me.getPayload() + "'" ); - } - } - } -} diff --git a/src/org/apache/commons/jcs/utils/struct/DoubleLinkedListNode.java b/src/org/apache/commons/jcs/utils/struct/DoubleLinkedListNode.java deleted file mode 100644 index 26d080e2d85..00000000000 --- a/src/org/apache/commons/jcs/utils/struct/DoubleLinkedListNode.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.apache.commons.jcs.utils.struct; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; - -/** - * This serves as a placeholder in a double linked list. You can extend this to - * add functionality. This allows you to remove in constant time from a linked - * list. - *

- * It simply holds the payload and a reference to the items before and after it - * in the list. - */ -public class DoubleLinkedListNode - implements Serializable -{ - /** Dont' change. */ - private static final long serialVersionUID = -1114934407695836097L; - - /** The object in the node. */ - private final T payload; - - /** Double Linked list references */ - public DoubleLinkedListNode prev; - - /** Double Linked list references */ - public DoubleLinkedListNode next; - - /** - * @param payloadP - */ - public DoubleLinkedListNode(T payloadP) - { - payload = payloadP; - } - - /** - * @return Object - */ - public T getPayload() - { - return payload; - } -} diff --git a/src/org/apache/commons/jcs/utils/struct/LRUElementDescriptor.java b/src/org/apache/commons/jcs/utils/struct/LRUElementDescriptor.java deleted file mode 100644 index f728466566b..00000000000 --- a/src/org/apache/commons/jcs/utils/struct/LRUElementDescriptor.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.apache.commons.jcs.utils.struct; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This is a node in the double linked list. It is stored as the value in the underlying map used by - * the LRUMap class. - */ -public class LRUElementDescriptor - extends DoubleLinkedListNode -{ - /** Don't change. */ - private static final long serialVersionUID = 8249555756363020156L; - - /** The key value */ - private K key; - - /** - * @param key - * @param payloadP - */ - public LRUElementDescriptor(K key, V payloadP) - { - super(payloadP); - this.setKey(key); - } - - /** - * @param key The key to set. - */ - public void setKey(K key) - { - this.key = key; - } - - /** - * @return Returns the key. - */ - public K getKey() - { - return key; - } -} diff --git a/src/org/apache/commons/jcs/utils/struct/LRUMap.java b/src/org/apache/commons/jcs/utils/struct/LRUMap.java deleted file mode 100644 index 84ff231fc41..00000000000 --- a/src/org/apache/commons/jcs/utils/struct/LRUMap.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.apache.commons.jcs.utils.struct; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * - * @author Wiktor Niesiobędzki - * - * Simple LRUMap implementation that keeps the number of the objects below or equal maxObjects - * - * @param - * @param - */ -public class LRUMap extends AbstractLRUMap -{ - /** if the max is less than 0, there is no limit! */ - private int maxObjects = -1; - - public LRUMap() - { - super(); - } - - /** - * - * @param maxObjects - * maximum number to keep in the map - */ - public LRUMap(int maxObjects) - { - this(); - this.maxObjects = maxObjects; - } - - @Override - public boolean shouldRemove() - { - return maxObjects > 0 && this.size() > maxObjects; - } -} diff --git a/src/org/apache/commons/jcs/utils/struct/LRUMapEntry.java b/src/org/apache/commons/jcs/utils/struct/LRUMapEntry.java deleted file mode 100644 index 57472443595..00000000000 --- a/src/org/apache/commons/jcs/utils/struct/LRUMapEntry.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.apache.commons.jcs.utils.struct; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.Serializable; -import java.util.Map.Entry; - -/** - * Entry for the LRUMap. - *

- * @author Aaron Smuts - */ -public class LRUMapEntry - implements Entry, Serializable -{ - /** Don't change */ - private static final long serialVersionUID = -8176116317739129331L; - - /** key */ - private final K key; - - /** value */ - private V value; - - /** - * S - * @param key - * @param value - */ - public LRUMapEntry(K key, V value) - { - this.key = key; - this.value = value; - } - - /** - * @return key - */ - @Override - public K getKey() - { - return this.key; - } - - /** - * @return value - */ - @Override - public V getValue() - { - return this.value; - } - - /** - * @param valueArg - * @return the old value - */ - @Override - public V setValue(V valueArg) - { - V old = this.value; - this.value = valueArg; - return old; - } -} diff --git a/src/org/apache/commons/jcs/utils/threadpool/DaemonThreadFactory.java b/src/org/apache/commons/jcs/utils/threadpool/DaemonThreadFactory.java deleted file mode 100644 index e1ec271dd7d..00000000000 --- a/src/org/apache/commons/jcs/utils/threadpool/DaemonThreadFactory.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.apache.commons.jcs.utils.threadpool; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.concurrent.ThreadFactory; - -/** - * Allows us to set the daemon status on the threads. - *

- * @author aaronsm - */ -public class DaemonThreadFactory - implements ThreadFactory -{ - private String prefix; - private boolean threadIsDaemon = true; - private int threadPriority = Thread.NORM_PRIORITY; - - /** - * Constructor - * - * @param prefix thread name prefix - */ - public DaemonThreadFactory(String prefix) - { - this(prefix, Thread.NORM_PRIORITY); - } - - /** - * Constructor - * - * @param prefix thread name prefix - * @param threadPriority set thread priority - */ - public DaemonThreadFactory(String prefix, int threadPriority) - { - this.prefix = prefix; - this.threadPriority = threadPriority; - } - - /** - * Sets the thread to daemon. - *

- * @param runner - * @return a daemon thread - */ - @Override - public Thread newThread( Runnable runner ) - { - Thread t = new Thread( runner ); - String oldName = t.getName(); - t.setName( prefix + oldName ); - t.setDaemon(threadIsDaemon); - t.setPriority(threadPriority); - return t; - } -} \ No newline at end of file diff --git a/src/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java b/src/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java deleted file mode 100644 index f4e886df770..00000000000 --- a/src/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java +++ /dev/null @@ -1,293 +0,0 @@ -package org.apache.commons.jcs.utils.threadpool; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This object holds configuration data for a thread pool. - *

- * @author Aaron Smuts - */ -public final class PoolConfiguration - implements Cloneable -{ - /** - * DEFAULT SETTINGS - */ - private static final boolean DEFAULT_USE_BOUNDARY = true; - - /** Default queue size limit */ - private static final int DEFAULT_BOUNDARY_SIZE = 2000; - - /** Default max size */ - private static final int DEFAULT_MAXIMUM_POOL_SIZE = 150; - - /** Default min */ - private static final int DEFAULT_MINIMUM_POOL_SIZE = Runtime.getRuntime().availableProcessors(); - - /** Default keep alive */ - private static final int DEFAULT_KEEPALIVE_TIME = 1000 * 60 * 5; - - /** Default when blocked */ - private static final WhenBlockedPolicy DEFAULT_WHEN_BLOCKED_POLICY = WhenBlockedPolicy.RUN; - - /** Default startup size */ - private static final int DEFAULT_STARTUP_SIZE = DEFAULT_MINIMUM_POOL_SIZE; - - /** Should we bound the queue */ - private boolean useBoundary = DEFAULT_USE_BOUNDARY; - - /** If the queue is bounded, how big can it get */ - private int boundarySize = DEFAULT_BOUNDARY_SIZE; - - /** only has meaning if a boundary is used */ - private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE; - - /** - * the exact number that will be used in a boundless queue. If the queue has a boundary, more - * will be created if the queue fills. - */ - private int minimumPoolSize = DEFAULT_MINIMUM_POOL_SIZE; - - /** How long idle threads above the minimum should be kept alive. */ - private int keepAliveTime = DEFAULT_KEEPALIVE_TIME; - - public enum WhenBlockedPolicy { - /** abort when queue is full and max threads is reached. */ - ABORT, - - /** block when queue is full and max threads is reached. */ - BLOCK, - - /** run in current thread when queue is full and max threads is reached. */ - RUN, - - /** wait when queue is full and max threads is reached. */ - WAIT, - - /** discard oldest when queue is full and max threads is reached. */ - DISCARDOLDEST - } - - /** should be ABORT, BLOCK, RUN, WAIT, DISCARDOLDEST, */ - private WhenBlockedPolicy whenBlockedPolicy = DEFAULT_WHEN_BLOCKED_POLICY; - - /** The number of threads to create on startup */ - private int startUpSize = DEFAULT_MINIMUM_POOL_SIZE; - - /** - * @param useBoundary The useBoundary to set. - */ - public void setUseBoundary( boolean useBoundary ) - { - this.useBoundary = useBoundary; - } - - /** - * @return Returns the useBoundary. - */ - public boolean isUseBoundary() - { - return useBoundary; - } - - /** - * Default - */ - public PoolConfiguration() - { - this( DEFAULT_USE_BOUNDARY, DEFAULT_BOUNDARY_SIZE, DEFAULT_MAXIMUM_POOL_SIZE, - DEFAULT_MINIMUM_POOL_SIZE, DEFAULT_KEEPALIVE_TIME, - DEFAULT_WHEN_BLOCKED_POLICY, DEFAULT_STARTUP_SIZE ); - } - - /** - * Construct a completely configured instance. - *

- * @param useBoundary - * @param boundarySize - * @param maximumPoolSize - * @param minimumPoolSize - * @param keepAliveTime - * @param whenBlockedPolicy - * @param startUpSize - */ - public PoolConfiguration( boolean useBoundary, int boundarySize, int maximumPoolSize, int minimumPoolSize, - int keepAliveTime, WhenBlockedPolicy whenBlockedPolicy, int startUpSize ) - { - setUseBoundary( useBoundary ); - setBoundarySize( boundarySize ); - setMaximumPoolSize( maximumPoolSize ); - setMinimumPoolSize( minimumPoolSize ); - setKeepAliveTime( keepAliveTime ); - setWhenBlockedPolicy( whenBlockedPolicy ); - setStartUpSize( startUpSize ); - } - - /** - * @param boundarySize The boundarySize to set. - */ - public void setBoundarySize( int boundarySize ) - { - this.boundarySize = boundarySize; - } - - /** - * @return Returns the boundarySize. - */ - public int getBoundarySize() - { - return boundarySize; - } - - /** - * @param maximumPoolSize The maximumPoolSize to set. - */ - public void setMaximumPoolSize( int maximumPoolSize ) - { - this.maximumPoolSize = maximumPoolSize; - } - - /** - * @return Returns the maximumPoolSize. - */ - public int getMaximumPoolSize() - { - return maximumPoolSize; - } - - /** - * @param minimumPoolSize The minimumPoolSize to set. - */ - public void setMinimumPoolSize( int minimumPoolSize ) - { - this.minimumPoolSize = minimumPoolSize; - } - - /** - * @return Returns the minimumPoolSize. - */ - public int getMinimumPoolSize() - { - return minimumPoolSize; - } - - /** - * @param keepAliveTime The keepAliveTime to set. - */ - public void setKeepAliveTime( int keepAliveTime ) - { - this.keepAliveTime = keepAliveTime; - } - - /** - * @return Returns the keepAliveTime. - */ - public int getKeepAliveTime() - { - return keepAliveTime; - } - - /** - * @param whenBlockedPolicy The whenBlockedPolicy to set. - */ - public void setWhenBlockedPolicy( String whenBlockedPolicy ) - { - if ( whenBlockedPolicy != null ) - { - WhenBlockedPolicy policy = WhenBlockedPolicy.valueOf(whenBlockedPolicy.trim().toUpperCase()); - setWhenBlockedPolicy(policy); - } - else - { - // the value is null, default to RUN - this.whenBlockedPolicy = WhenBlockedPolicy.RUN; - } - } - - /** - * @param whenBlockedPolicy The whenBlockedPolicy to set. - */ - public void setWhenBlockedPolicy( WhenBlockedPolicy whenBlockedPolicy ) - { - if ( whenBlockedPolicy != null ) - { - this.whenBlockedPolicy = whenBlockedPolicy; - } - else - { - // the value is null, default to RUN - this.whenBlockedPolicy = WhenBlockedPolicy.RUN; - } - } - - /** - * @return Returns the whenBlockedPolicy. - */ - public WhenBlockedPolicy getWhenBlockedPolicy() - { - return whenBlockedPolicy; - } - - /** - * @param startUpSize The startUpSize to set. - */ - public void setStartUpSize( int startUpSize ) - { - this.startUpSize = startUpSize; - } - - /** - * @return Returns the startUpSize. - */ - public int getStartUpSize() - { - return startUpSize; - } - - /** - * To string for debugging purposes. - * @return String - */ - @Override - public String toString() - { - StringBuilder buf = new StringBuilder(); - buf.append( "useBoundary = [" + isUseBoundary() + "] " ); - buf.append( "boundarySize = [" + boundarySize + "] " ); - buf.append( "maximumPoolSize = [" + maximumPoolSize + "] " ); - buf.append( "minimumPoolSize = [" + minimumPoolSize + "] " ); - buf.append( "keepAliveTime = [" + keepAliveTime + "] " ); - buf.append( "whenBlockedPolicy = [" + getWhenBlockedPolicy() + "] " ); - buf.append( "startUpSize = [" + startUpSize + "]" ); - return buf.toString(); - } - - /** - * Copies the instance variables to another instance. - *

- * @return PoolConfiguration - */ - @Override - public PoolConfiguration clone() - { - return new PoolConfiguration( isUseBoundary(), boundarySize, maximumPoolSize, minimumPoolSize, keepAliveTime, - getWhenBlockedPolicy(), startUpSize ); - } -} diff --git a/src/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java b/src/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java deleted file mode 100644 index 44a73bb14fc..00000000000 --- a/src/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java +++ /dev/null @@ -1,395 +0,0 @@ -package org.apache.commons.jcs.utils.threadpool; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.util.ArrayList; -import java.util.Properties; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.jcs.utils.config.PropertySetter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This manages threadpools for an application - *

- * It is a singleton since threads need to be managed vm wide. - *

- * This manager forces you to use a bounded queue. By default it uses the current thread for - * execution when the buffer is full and no free threads can be created. - *

- * You can specify the props file to use or pass in a properties object prior to configuration. - *

- * If set, the Properties object will take precedence. - *

- * If a value is not set for a particular pool, the hard coded defaults in PoolConfiguration will be used. - * You can configure default settings by specifying thread_pool.default in the properties, ie "cache.ccf" - *

- * @author Aaron Smuts - */ -public class ThreadPoolManager -{ - /** The logger */ - private static final Log log = LogFactory.getLog( ThreadPoolManager.class ); - - /** The default config, created using property defaults if present, else those above. */ - private PoolConfiguration defaultConfig; - - /** the root property name */ - private static final String PROP_NAME_ROOT = "thread_pool"; - - /** default property file name */ - private static final String DEFAULT_PROP_NAME_ROOT = "thread_pool.default"; - - /** the scheduler root property name */ - private static final String PROP_NAME_SCHEDULER_ROOT = "scheduler_pool"; - - /** default scheduler property file name */ - private static final String DEFAULT_PROP_NAME_SCHEDULER_ROOT = "scheduler_pool.default"; - - /** - * You can specify the properties to be used to configure the thread pool. Setting this post - * initialization will have no effect. - */ - private static volatile Properties props = null; - - /** singleton instance */ - private static ThreadPoolManager INSTANCE = null; - - /** Map of names to pools. */ - private ConcurrentHashMap pools; - - /** Map of names to scheduler pools. */ - private ConcurrentHashMap schedulerPools; - - /** - * No instances please. This is a singleton. - */ - private ThreadPoolManager() - { - this.pools = new ConcurrentHashMap(); - this.schedulerPools = new ConcurrentHashMap(); - configure(); - } - - /** - * Creates a pool based on the configuration info. - *

- * @param config the pool configuration - * @param threadNamePrefix prefix for the thread names of the pool - * @return A ThreadPool wrapper - */ - public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix) - { - return createPool(config, threadNamePrefix, Thread.NORM_PRIORITY); - } - - /** - * Creates a pool based on the configuration info. - *

- * @param config the pool configuration - * @param threadNamePrefix prefix for the thread names of the pool - * @param threadPriority the priority of the created threads - * @return A ThreadPool wrapper - */ - public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix, int threadPriority ) - { - BlockingQueue queue = null; - if ( config.isUseBoundary() ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Creating a Bounded Buffer to use for the pool" ); - } - - queue = new LinkedBlockingQueue(config.getBoundarySize()); - } - else - { - if ( log.isDebugEnabled() ) - { - log.debug( "Creating a non bounded Linked Queue to use for the pool" ); - } - queue = new LinkedBlockingQueue(); - } - - ThreadPoolExecutor pool = new ThreadPoolExecutor( - config.getStartUpSize(), - config.getMaximumPoolSize(), - config.getKeepAliveTime(), - TimeUnit.MILLISECONDS, - queue, - new DaemonThreadFactory(threadNamePrefix, threadPriority)); - - // when blocked policy - switch (config.getWhenBlockedPolicy()) - { - case ABORT: - pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); - break; - - case RUN: - pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); - break; - - case WAIT: - throw new RuntimeException("POLICY_WAIT no longer supported"); - - case DISCARDOLDEST: - pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); - break; - - default: - break; - } - - pool.prestartAllCoreThreads(); - - return pool; - } - - /** - * Creates a scheduler pool based on the configuration info. - *

- * @param config the pool configuration - * @param threadNamePrefix prefix for the thread names of the pool - * @param threadPriority the priority of the created threads - * @return A ScheduledExecutorService - */ - public ScheduledExecutorService createSchedulerPool( PoolConfiguration config, String threadNamePrefix, int threadPriority ) - { - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( - config.getMaximumPoolSize(), - new DaemonThreadFactory(threadNamePrefix, threadPriority)); - - return scheduler; - } - - /** - * Returns a configured instance of the ThreadPoolManger To specify a configuration file or - * Properties object to use call the appropriate setter prior to calling getInstance. - *

- * @return The single instance of the ThreadPoolManager - */ - public static synchronized ThreadPoolManager getInstance() - { - if ( INSTANCE == null ) - { - INSTANCE = new ThreadPoolManager(); - } - return INSTANCE; - } - - /** - * Dispose of the instance of the ThreadPoolManger and shut down all thread pools - */ - public static synchronized void dispose() - { - if ( INSTANCE != null ) - { - for ( ExecutorService pool : INSTANCE.pools.values() ) - { - try - { - pool.shutdownNow(); - } - catch (Throwable t) - { - log.warn("Failed to close pool " + pool, t); - } - } - - for ( ScheduledExecutorService pool : INSTANCE.schedulerPools.values() ) - { - try - { - pool.shutdownNow(); - } - catch (Throwable t) - { - log.warn("Failed to close pool " + pool, t); - } - } - - INSTANCE = null; - } - } - - /** - * Returns an executor service by name. If a service by this name does not exist in the configuration file or - * properties, one will be created using the default values. - *

- * Services are lazily created. - *

- * @param name - * @return The executor service configured for the name. - */ - public ExecutorService getExecutorService( String name ) - { - ExecutorService pool = pools.get( name ); - - if ( pool == null ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Creating pool for name [" + name + "]" ); - } - - PoolConfiguration config = loadConfig( PROP_NAME_ROOT + "." + name ); - ExecutorService _pool = createPool( config, "JCS-ThreadPoolManager-" + name + "-" ); - pool = pools.putIfAbsent( name, _pool ); - if (pool == null) - { - pool = _pool; - } - else - { - // already created in another thread - _pool.shutdownNow(); - } - - if ( log.isDebugEnabled() ) - { - log.debug( "PoolName = " + getPoolNames() ); - } - } - - return pool; - } - - /** - * Returns a scheduler pool by name. If a pool by this name does not exist in the configuration file or - * properties, one will be created using the default values. - *

- * Pools are lazily created. - *

- * @param name - * @return The scheduler pool configured for the name. - */ - public ScheduledExecutorService getSchedulerPool( String name ) - { - ScheduledExecutorService pool = schedulerPools.get( name ); - - if ( pool == null ) - { - if ( log.isDebugEnabled() ) - { - log.debug( "Creating scheduler pool for name [" + name + "]" ); - } - - PoolConfiguration defaultSchedulerConfig = loadConfig( DEFAULT_PROP_NAME_SCHEDULER_ROOT ); - PoolConfiguration config = loadConfig( PROP_NAME_SCHEDULER_ROOT + "." + name, defaultSchedulerConfig ); - ScheduledExecutorService _pool = createSchedulerPool( config, "JCS-ThreadPoolManager-" + name + "-", Thread.NORM_PRIORITY ); - pool = schedulerPools.putIfAbsent( name, _pool ); - if (pool == null) - { - pool = _pool; - } - else - { - // already created in another thread - _pool.shutdownNow(); - } - } - - return pool; - } - - /** - * Returns the names of all configured pools. - *

- * @return ArrayList of string names - */ - public ArrayList getPoolNames() - { - return new ArrayList(pools.keySet()); - } - - /** - * This will be used if it is not null on initialization. Setting this post initialization will - * have no effect. - *

- * @param props The props to set. - */ - public static void setProps( Properties props ) - { - ThreadPoolManager.props = props; - } - - /** - * Initialize the ThreadPoolManager and create all the pools defined in the configuration. - */ - private void configure() - { - if ( log.isDebugEnabled() ) - { - log.debug( "Initializing ThreadPoolManager" ); - } - - if ( props == null ) - { - log.warn( "No configuration settings found. Using hardcoded default values for all pools." ); - props = new Properties(); - } - - // set intial default and then override if new - // settings are available - defaultConfig = new PoolConfiguration(); - defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT ); - } - - /** - * Configures the PoolConfiguration settings. - *

- * @param root the configuration key prefix - * @return PoolConfiguration - */ - private PoolConfiguration loadConfig( String root ) - { - return loadConfig(root, defaultConfig); - } - - /** - * Configures the PoolConfiguration settings. - *

- * @param root the configuration key prefix - * @param defaultPoolConfiguration the default configuration - * @return PoolConfiguration - */ - private PoolConfiguration loadConfig( String root, PoolConfiguration defaultPoolConfiguration ) - { - PoolConfiguration config = defaultPoolConfiguration.clone(); - PropertySetter.setProperties( config, props, root + "." ); - - if ( log.isDebugEnabled() ) - { - log.debug( root + " PoolConfiguration = " + config ); - } - - return config; - } -} diff --git a/src/org/apache/commons/jcs/utils/timing/ElapsedTimer.java b/src/org/apache/commons/jcs/utils/timing/ElapsedTimer.java deleted file mode 100644 index bd728e90fe5..00000000000 --- a/src/org/apache/commons/jcs/utils/timing/ElapsedTimer.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.apache.commons.jcs.utils.timing; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This is a simple timer utility. - */ -public class ElapsedTimer -{ - /** display suffix describing the unit of measure. */ - private static final String SUFFIX = "ms."; - - /** - * Sets the start time when created. - */ - private long timeStamp = System.currentTimeMillis(); - - /** - * Gets the time elapsed between the start time and now. The start time is reset to now. - * Subsequent calls will get the time between then and now. - *

- * @return the elapsed time - */ - public long getElapsedTime() - { - long now = System.currentTimeMillis(); - long elapsed = now - timeStamp; - timeStamp = now; - return elapsed; - } - - /** - * Returns the elapsed time with the display suffix. - *

- * @return formatted elapsed Time - */ - public String getElapsedTimeString() - { - return String.valueOf( getElapsedTime() ) + SUFFIX; - } -} diff --git a/src/org/apache/commons/jcs/utils/zip/CompressionUtil.java b/src/org/apache/commons/jcs/utils/zip/CompressionUtil.java deleted file mode 100644 index 93f05fa3428..00000000000 --- a/src/org/apache/commons/jcs/utils/zip/CompressionUtil.java +++ /dev/null @@ -1,203 +0,0 @@ -package org.apache.commons.jcs.utils.zip; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.zip.DataFormatException; -import java.util.zip.Deflater; -import java.util.zip.GZIPInputStream; -import java.util.zip.Inflater; - -/** Compress / Decompress. */ -public final class CompressionUtil -{ - /** The logger */ - private static final Log log = LogFactory.getLog( CompressionUtil.class ); - - /** - * no instances. - */ - private CompressionUtil() - { - // NO OP - } - - /** - * Decompress the byte array passed using a default buffer length of 1024. - *

- * @param input compressed byte array webservice response - * @return uncompressed byte array - */ - public static byte[] decompressByteArray( final byte[] input ) - { - return decompressByteArray( input, 1024 ); - } - - /** - * Decompress the byte array passed - *

- * @param input compressed byte array webservice response - * @param bufferLength buffer length - * @return uncompressed byte array - */ - public static byte[] decompressByteArray( final byte[] input, final int bufferLength ) - { - if ( null == input ) - { - throw new IllegalArgumentException( "Input was null" ); - } - - // Create the decompressor and give it the data to compress - final Inflater decompressor = new Inflater(); - - decompressor.setInput( input ); - - // Create an expandable byte array to hold the decompressed data - final ByteArrayOutputStream baos = new ByteArrayOutputStream( input.length ); - - // Decompress the data - final byte[] buf = new byte[bufferLength]; - - try - { - while ( !decompressor.finished() ) - { - int count = decompressor.inflate( buf ); - baos.write( buf, 0, count ); - } - } - catch ( DataFormatException ex ) - { - log.error( "Problem decompressing.", ex ); - } - - decompressor.end(); - - try - { - baos.close(); - } - catch ( IOException ex ) - { - log.error( "Problem closing stream.", ex ); - } - - return baos.toByteArray(); - } - - /** - * Compress the byte array passed - *

- * @param input byte array - * @return compressed byte array - * @throws IOException thrown if we can't close the output stream - */ - public static byte[] compressByteArray( byte[] input ) - throws IOException - { - return compressByteArray( input, 1024 ); - } - - /** - * Compress the byte array passed - *

- * @param input byte array - * @param bufferLength buffer length - * @return compressed byte array - * @throws IOException thrown if we can't close the output stream - */ - public static byte[] compressByteArray( byte[] input, int bufferLength ) - throws IOException - { - // Compressor with highest level of compression - Deflater compressor = new Deflater(); - compressor.setLevel( Deflater.BEST_COMPRESSION ); - - // Give the compressor the data to compress - compressor.setInput( input ); - compressor.finish(); - - // Create an expandable byte array to hold the compressed data. - // It is not necessary that the compressed data will be smaller than - // the uncompressed data. - ByteArrayOutputStream bos = new ByteArrayOutputStream( input.length ); - - // Compress the data - byte[] buf = new byte[bufferLength]; - while ( !compressor.finished() ) - { - int count = compressor.deflate( buf ); - bos.write( buf, 0, count ); - } - - // JCS-136 ( Details here : http://www.devguli.com/blog/eng/java-deflater-and-outofmemoryerror/ ) - compressor.end(); - bos.close(); - - // Get the compressed data - return bos.toByteArray(); - - } - - /** - * decompress a gzip byte array, using a default buffer length of 1024 - *

- * @param compressedByteArray gzip-compressed byte array - * @return decompressed byte array - * @throws IOException thrown if there was a failure to construct the GzipInputStream - */ - public static byte[] decompressGzipByteArray( byte[] compressedByteArray ) - throws IOException - { - return decompressGzipByteArray( compressedByteArray, 1024 ); - } - - /** - * decompress a gzip byte array, using a default buffer length of 1024 - *

- * @param compressedByteArray gzip-compressed byte array - * @param bufferlength size of the buffer in bytes - * @return decompressed byte array - * @throws IOException thrown if there was a failure to construct the GzipInputStream - */ - public static byte[] decompressGzipByteArray( byte[] compressedByteArray, int bufferlength ) - throws IOException - { - ByteArrayOutputStream uncompressedStream = new ByteArrayOutputStream(); - - GZIPInputStream compressedStream = new GZIPInputStream( new ByteArrayInputStream( compressedByteArray ) ); - - byte[] buffer = new byte[bufferlength]; - - int index = -1; - - while ( ( index = compressedStream.read( buffer ) ) != -1 ) - { - uncompressedStream.write( buffer, 0, index ); - } - - return uncompressedStream.toByteArray(); - } -} diff --git a/src/org/apache/commons/logging/Log.java b/src/org/apache/commons/logging/Log.java deleted file mode 100644 index 5c5523d5a19..00000000000 --- a/src/org/apache/commons/logging/Log.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging; - -/** - * A simple logging interface abstracting logging APIs. In order to be - * instantiated successfully by {@link LogFactory}, classes that implement - * this interface must have a constructor that takes a single String - * parameter representing the "name" of this Log. - *

- * The six logging levels used by Log are (in order): - *

    - *
  1. trace (the least serious)
  2. - *
  3. debug
  4. - *
  5. info
  6. - *
  7. warn
  8. - *
  9. error
  10. - *
  11. fatal (the most serious)
  12. - *
- * The mapping of these log levels to the concepts used by the underlying - * logging system is implementation dependent. - * The implementation should ensure, though, that this ordering behaves - * as expected. - *

- * Performance is often a logging concern. - * By examining the appropriate property, - * a component can avoid expensive operations (producing information - * to be logged). - *

- * For example, - *

- *    if (log.isDebugEnabled()) {
- *        ... do something expensive ...
- *        log.debug(theResult);
- *    }
- * 
- *

- * Configuration of the underlying logging system will generally be done - * external to the Logging APIs, through whatever mechanism is supported by - * that system. - * - * @version $Id: Log.java 1606045 2014-06-27 12:11:56Z tn $ - */ -public interface Log { - - /** - * Logs a message with debug log level. - * - * @param message log this message - */ - void debug(Object message); - - /** - * Logs an error with debug log level. - * - * @param message log this message - * @param t log this cause - */ - void debug(Object message, Throwable t); - - /** - * Logs a message with error log level. - * - * @param message log this message - */ - void error(Object message); - - /** - * Logs an error with error log level. - * - * @param message log this message - * @param t log this cause - */ - void error(Object message, Throwable t); - - /** - * Logs a message with fatal log level. - * - * @param message log this message - */ - void fatal(Object message); - - /** - * Logs an error with fatal log level. - * - * @param message log this message - * @param t log this cause - */ - void fatal(Object message, Throwable t); - - /** - * Logs a message with info log level. - * - * @param message log this message - */ - void info(Object message); - - /** - * Logs an error with info log level. - * - * @param message log this message - * @param t log this cause - */ - void info(Object message, Throwable t); - - /** - * Is debug logging currently enabled? - *

- * Call this method to prevent having to perform expensive operations - * (for example, String concatenation) - * when the log level is more than debug. - * - * @return true if debug is enabled in the underlying logger. - */ - boolean isDebugEnabled(); - - /** - * Is error logging currently enabled? - *

- * Call this method to prevent having to perform expensive operations - * (for example, String concatenation) - * when the log level is more than error. - * - * @return true if error is enabled in the underlying logger. - */ - boolean isErrorEnabled(); - - /** - * Is fatal logging currently enabled? - *

- * Call this method to prevent having to perform expensive operations - * (for example, String concatenation) - * when the log level is more than fatal. - * - * @return true if fatal is enabled in the underlying logger. - */ - boolean isFatalEnabled(); - - /** - * Is info logging currently enabled? - *

- * Call this method to prevent having to perform expensive operations - * (for example, String concatenation) - * when the log level is more than info. - * - * @return true if info is enabled in the underlying logger. - */ - boolean isInfoEnabled(); - - /** - * Is trace logging currently enabled? - *

- * Call this method to prevent having to perform expensive operations - * (for example, String concatenation) - * when the log level is more than trace. - * - * @return true if trace is enabled in the underlying logger. - */ - boolean isTraceEnabled(); - - /** - * Is warn logging currently enabled? - *

- * Call this method to prevent having to perform expensive operations - * (for example, String concatenation) - * when the log level is more than warn. - * - * @return true if warn is enabled in the underlying logger. - */ - boolean isWarnEnabled(); - - /** - * Logs a message with trace log level. - * - * @param message log this message - */ - void trace(Object message); - - /** - * Logs an error with trace log level. - * - * @param message log this message - * @param t log this cause - */ - void trace(Object message, Throwable t); - - /** - * Logs a message with warn log level. - * - * @param message log this message - */ - void warn(Object message); - - /** - * Logs an error with warn log level. - * - * @param message log this message - * @param t log this cause - */ - void warn(Object message, Throwable t); -} diff --git a/src/org/apache/commons/logging/LogConfigurationException.java b/src/org/apache/commons/logging/LogConfigurationException.java deleted file mode 100644 index e612e9b77f6..00000000000 --- a/src/org/apache/commons/logging/LogConfigurationException.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging; - -/** - * An exception that is thrown only if a suitable LogFactory - * or Log instance cannot be created by the corresponding - * factory methods. - * - * @version $Id: LogConfigurationException.java 1432663 2013-01-13 17:24:18Z tn $ - */ -public class LogConfigurationException extends RuntimeException { - - /** Serializable version identifier. */ - private static final long serialVersionUID = 8486587136871052495L; - - /** - * Construct a new exception with null as its detail message. - */ - public LogConfigurationException() { - super(); - } - - /** - * Construct a new exception with the specified detail message. - * - * @param message The detail message - */ - public LogConfigurationException(String message) { - super(message); - } - - /** - * Construct a new exception with the specified cause and a derived - * detail message. - * - * @param cause The underlying cause - */ - public LogConfigurationException(Throwable cause) { - this(cause == null ? null : cause.toString(), cause); - } - - /** - * Construct a new exception with the specified detail message and cause. - * - * @param message The detail message - * @param cause The underlying cause - */ - public LogConfigurationException(String message, Throwable cause) { - super(message + " (Caused by " + cause + ")"); - this.cause = cause; // Two-argument version requires JDK 1.4 or later - } - - /** - * The underlying cause of this exception. - */ - protected Throwable cause = null; - - /** - * Return the underlying cause of this exception (if any). - */ - public Throwable getCause() { - return this.cause; - } -} diff --git a/src/org/apache/commons/logging/LogFactory.java b/src/org/apache/commons/logging/LogFactory.java deleted file mode 100644 index 23caf28cd0a..00000000000 --- a/src/org/apache/commons/logging/LogFactory.java +++ /dev/null @@ -1,1707 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging; - -import java.io.BufferedReader; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.URL; -import java.net.URLConnection; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Properties; - -/** - * Factory for creating {@link Log} instances, with discovery and - * configuration features similar to that employed by standard Java APIs - * such as JAXP. - *

- * IMPLEMENTATION NOTE - This implementation is heavily - * based on the SAXParserFactory and DocumentBuilderFactory implementations - * (corresponding to the JAXP pluggability APIs) found in Apache Xerces. - * - * @version $Id: LogFactory.java 1765341 2016-10-17 16:56:41Z ggregory $ - */ -public abstract class LogFactory { - // Implementation note re AccessController usage - // - // It is important to keep code invoked via an AccessController to small - // auditable blocks. Such code must carefully evaluate all user input - // (parameters, system properties, config file contents, etc). As an - // example, a Log implementation should not write to its logfile - // with an AccessController anywhere in the call stack, otherwise an - // insecure application could configure the log implementation to write - // to a protected file using the privileges granted to JCL rather than - // to the calling application. - // - // Under no circumstance should a non-private method return data that is - // retrieved via an AccessController. That would allow an insecure app - // to invoke that method and obtain data that it is not permitted to have. - // - // Invoking user-supplied code with an AccessController set is not a major - // issue (eg invoking the constructor of the class specified by - // HASHTABLE_IMPLEMENTATION_PROPERTY). That class will be in a different - // trust domain, and therefore must have permissions to do whatever it - // is trying to do regardless of the permissions granted to JCL. There is - // a slight issue in that untrusted code may point that environment var - // to another trusted library, in which case the code runs if both that - // lib and JCL have the necessary permissions even when the untrusted - // caller does not. That's a pretty hard route to exploit though. - - // ----------------------------------------------------- Manifest Constants - - /** - * The name (priority) of the key in the config file used to - * specify the priority of that particular config file. The associated value - * is a floating-point number; higher values take priority over lower values. - */ - public static final String PRIORITY_KEY = "priority"; - - /** - * The name (use_tccl) of the key in the config file used - * to specify whether logging classes should be loaded via the thread - * context class loader (TCCL), or not. By default, the TCCL is used. - */ - public static final String TCCL_KEY = "use_tccl"; - - /** - * The name (org.apache.commons.logging.LogFactory) of the property - * used to identify the LogFactory implementation - * class name. This can be used as a system property, or as an entry in a - * configuration properties file. - */ - public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory"; - - /** - * The fully qualified class name of the fallback LogFactory - * implementation class to use, if no other can be found. - */ - public static final String FACTORY_DEFAULT = "org.apache.commons.logging.impl.LogFactoryImpl"; - - /** - * The name (commons-logging.properties) of the properties file to search for. - */ - public static final String FACTORY_PROPERTIES = "commons-logging.properties"; - - /** - * JDK1.3+ - * 'Service Provider' specification. - */ - protected static final String SERVICE_ID = - "META-INF/services/org.apache.commons.logging.LogFactory"; - - /** - * The name (org.apache.commons.logging.diagnostics.dest) - * of the property used to enable internal commons-logging - * diagnostic output, in order to get information on what logging - * implementations are being discovered, what classloaders they - * are loaded through, etc. - *

- * If a system property of this name is set then the value is - * assumed to be the name of a file. The special strings - * STDOUT or STDERR (case-sensitive) indicate output to - * System.out and System.err respectively. - *

- * Diagnostic logging should be used only to debug problematic - * configurations and should not be set in normal production use. - */ - public static final String DIAGNOSTICS_DEST_PROPERTY = - "org.apache.commons.logging.diagnostics.dest"; - - /** - * When null (the usual case), no diagnostic output will be - * generated by LogFactory or LogFactoryImpl. When non-null, - * interesting events will be written to the specified object. - */ - private static PrintStream diagnosticsStream = null; - - /** - * A string that gets prefixed to every message output by the - * logDiagnostic method, so that users can clearly see which - * LogFactory class is generating the output. - */ - private static final String diagnosticPrefix; - - /** - * Setting this system property - * (org.apache.commons.logging.LogFactory.HashtableImpl) - * value allows the Hashtable used to store - * classloaders to be substituted by an alternative implementation. - *

- * Note: LogFactory will print: - *

-     * [ERROR] LogFactory: Load of custom hashtable failed
-     * 
- * to system error and then continue using a standard Hashtable. - *

- * Usage: Set this property when Java is invoked - * and LogFactory will attempt to load a new instance - * of the given implementation class. - * For example, running the following ant scriplet: - *

-     *  <java classname="${test.runner}" fork="yes" failonerror="${test.failonerror}">
-     *     ...
-     *     <sysproperty
-     *        key="org.apache.commons.logging.LogFactory.HashtableImpl"
-     *        value="org.apache.commons.logging.AltHashtable"/>
-     *  </java>
-     * 
- * will mean that LogFactory will load an instance of - * org.apache.commons.logging.AltHashtable. - *

- * A typical use case is to allow a custom - * Hashtable implementation using weak references to be substituted. - * This will allow classloaders to be garbage collected without - * the need to release them (on 1.3+ JVMs only, of course ;). - */ - public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = - "org.apache.commons.logging.LogFactory.HashtableImpl"; - - /** Name used to load the weak hashtable implementation by names. */ - private static final String WEAK_HASHTABLE_CLASSNAME = - "org.apache.commons.logging.impl.WeakHashtable"; - - /** - * A reference to the classloader that loaded this class. This is the - * same as LogFactory.class.getClassLoader(). However computing this - * value isn't quite as simple as that, as we potentially need to use - * AccessControllers etc. It's more efficient to compute it once and - * cache it here. - */ - private static final ClassLoader thisClassLoader; - - // ----------------------------------------------------------- Constructors - - /** - * Protected constructor that is not available for public use. - */ - protected LogFactory() { - } - - // --------------------------------------------------------- Public Methods - - /** - * Return the configuration attribute with the specified name (if any), - * or null if there is no such attribute. - * - * @param name Name of the attribute to return - */ - public abstract Object getAttribute(String name); - - /** - * Return an array containing the names of all currently defined - * configuration attributes. If there are no such attributes, a zero - * length array is returned. - */ - public abstract String[] getAttributeNames(); - - /** - * Convenience method to derive a name from the specified class and - * call getInstance(String) with it. - * - * @param clazz Class for which a suitable Log name will be derived - * @throws LogConfigurationException if a suitable Log - * instance cannot be returned - */ - public abstract Log getInstance(Class clazz) - throws LogConfigurationException; - - /** - * Construct (if necessary) and return a Log instance, - * using the factory's current set of configuration attributes. - *

- * NOTE - Depending upon the implementation of - * the LogFactory you are using, the Log - * instance you are returned may or may not be local to the current - * application, and may or may not be returned again on a subsequent - * call with the same name argument. - * - * @param name Logical name of the Log instance to be - * returned (the meaning of this name is only known to the underlying - * logging implementation that is being wrapped) - * @throws LogConfigurationException if a suitable Log - * instance cannot be returned - */ - public abstract Log getInstance(String name) - throws LogConfigurationException; - - /** - * Release any internal references to previously created {@link Log} - * instances returned by this factory. This is useful in environments - * like servlet containers, which implement application reloading by - * throwing away a ClassLoader. Dangling references to objects in that - * class loader would prevent garbage collection. - */ - public abstract void release(); - - /** - * Remove any configuration attribute associated with the specified name. - * If there is no such attribute, no action is taken. - * - * @param name Name of the attribute to remove - */ - public abstract void removeAttribute(String name); - - /** - * Set the configuration attribute with the specified name. Calling - * this with a null value is equivalent to calling - * removeAttribute(name). - * - * @param name Name of the attribute to set - * @param value Value of the attribute to set, or null - * to remove any setting for this attribute - */ - public abstract void setAttribute(String name, Object value); - - // ------------------------------------------------------- Static Variables - - /** - * The previously constructed LogFactory instances, keyed by - * the ClassLoader with which it was created. - */ - protected static Hashtable factories = null; - - /** - * Previously constructed LogFactory instance as in the - * factories map, but for the case where - * getClassLoader returns null. - * This can happen when: - *

    - *
  • using JDK1.1 and the calling code is loaded via the system - * classloader (very common)
  • - *
  • using JDK1.2+ and the calling code is loaded via the boot - * classloader (only likely for embedded systems work).
  • - *
- * Note that factories is a Hashtable (not a HashMap), - * and hashtables don't allow null as a key. - * @deprecated since 1.1.2 - */ - protected static volatile LogFactory nullClassLoaderFactory = null; - - /** - * Create the hashtable which will be used to store a map of - * (context-classloader -> logfactory-object). Version 1.2+ of Java - * supports "weak references", allowing a custom Hashtable class - * to be used which uses only weak references to its keys. Using weak - * references can fix memory leaks on webapp unload in some cases (though - * not all). Version 1.1 of Java does not support weak references, so we - * must dynamically determine which we are using. And just for fun, this - * code also supports the ability for a system property to specify an - * arbitrary Hashtable implementation name. - *

- * Note that the correct way to ensure no memory leaks occur is to ensure - * that LogFactory.release(contextClassLoader) is called whenever a - * webapp is undeployed. - */ - private static final Hashtable createFactoryStore() { - Hashtable result = null; - String storeImplementationClass; - try { - storeImplementationClass = getSystemProperty(HASHTABLE_IMPLEMENTATION_PROPERTY, null); - } catch (SecurityException ex) { - // Permissions don't allow this to be accessed. Default to the "modern" - // weak hashtable implementation if it is available. - storeImplementationClass = null; - } - - if (storeImplementationClass == null) { - storeImplementationClass = WEAK_HASHTABLE_CLASSNAME; - } - try { - Class implementationClass = Class.forName(storeImplementationClass); - result = (Hashtable) implementationClass.newInstance(); - } catch (Throwable t) { - handleThrowable(t); // may re-throw t - - // ignore - if (!WEAK_HASHTABLE_CLASSNAME.equals(storeImplementationClass)) { - // if the user's trying to set up a custom implementation, give a clue - if (isDiagnosticsEnabled()) { - // use internal logging to issue the warning - logDiagnostic("[ERROR] LogFactory: Load of custom hashtable failed"); - } else { - // we *really* want this output, even if diagnostics weren't - // explicitly enabled by the user. - System.err.println("[ERROR] LogFactory: Load of custom hashtable failed"); - } - } - } - if (result == null) { - result = new Hashtable(); - } - return result; - } - - // --------------------------------------------------------- Static Methods - - /** Utility method to safely trim a string. */ - private static String trim(String src) { - if (src == null) { - return null; - } - return src.trim(); - } - - /** - * Checks whether the supplied Throwable is one that needs to be - * re-thrown and ignores all others. - * - * The following errors are re-thrown: - *

    - *
  • ThreadDeath
  • - *
  • VirtualMachineError
  • - *
- * - * @param t the Throwable to check - */ - protected static void handleThrowable(Throwable t) { - if (t instanceof ThreadDeath) { - throw (ThreadDeath) t; - } - if (t instanceof VirtualMachineError) { - throw (VirtualMachineError) t; - } - // All other instances of Throwable will be silently ignored - } - - /** - * Construct (if necessary) and return a LogFactory - * instance, using the following ordered lookup procedure to determine - * the name of the implementation class to be loaded. - *

- *

    - *
  • The org.apache.commons.logging.LogFactory system - * property.
  • - *
  • The JDK 1.3 Service Discovery mechanism
  • - *
  • Use the properties file commons-logging.properties - * file, if found in the class path of this class. The configuration - * file is in standard java.util.Properties format and - * contains the fully qualified name of the implementation class - * with the key being the system property defined above.
  • - *
  • Fall back to a default implementation class - * (org.apache.commons.logging.impl.LogFactoryImpl).
  • - *
- *

- * NOTE - If the properties file method of identifying the - * LogFactory implementation class is utilized, all of the - * properties defined in this file will be set as configuration attributes - * on the corresponding LogFactory instance. - *

- * NOTE - In a multi-threaded environment it is possible - * that two different instances will be returned for the same - * classloader environment. - * - * @throws LogConfigurationException if the implementation class is not - * available or cannot be instantiated. - */ - public static LogFactory getFactory() throws LogConfigurationException { - // Identify the class loader we will be using - ClassLoader contextClassLoader = getContextClassLoaderInternal(); - - if (contextClassLoader == null) { - // This is an odd enough situation to report about. This - // output will be a nuisance on JDK1.1, as the system - // classloader is null in that environment. - if (isDiagnosticsEnabled()) { - logDiagnostic("Context classloader is null."); - } - } - - // Return any previously registered factory for this class loader - LogFactory factory = getCachedFactory(contextClassLoader); - if (factory != null) { - return factory; - } - - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] LogFactory implementation requested for the first time for context classloader " + - objectId(contextClassLoader)); - logHierarchy("[LOOKUP] ", contextClassLoader); - } - - // Load properties file. - // - // If the properties file exists, then its contents are used as - // "attributes" on the LogFactory implementation class. One particular - // property may also control which LogFactory concrete subclass is - // used, but only if other discovery mechanisms fail.. - // - // As the properties file (if it exists) will be used one way or - // another in the end we may as well look for it first. - - Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES); - - // Determine whether we will be using the thread context class loader to - // load logging classes or not by checking the loaded properties file (if any). - ClassLoader baseClassLoader = contextClassLoader; - if (props != null) { - String useTCCLStr = props.getProperty(TCCL_KEY); - if (useTCCLStr != null) { - // The Boolean.valueOf(useTCCLStr).booleanValue() formulation - // is required for Java 1.2 compatibility. - if (Boolean.valueOf(useTCCLStr).booleanValue() == false) { - // Don't use current context classloader when locating any - // LogFactory or Log classes, just use the class that loaded - // this abstract class. When this class is deployed in a shared - // classpath of a container, it means webapps cannot deploy their - // own logging implementations. It also means that it is up to the - // implementation whether to load library-specific config files - // from the TCCL or not. - baseClassLoader = thisClassLoader; - } - } - } - - // Determine which concrete LogFactory subclass to use. - // First, try a global system property - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Looking for system property [" + FACTORY_PROPERTY + - "] to define the LogFactory subclass to use..."); - } - - try { - String factoryClass = getSystemProperty(FACTORY_PROPERTY, null); - if (factoryClass != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Creating an instance of LogFactory class '" + factoryClass + - "' as specified by system property " + FACTORY_PROPERTY); - } - factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] No system property [" + FACTORY_PROPERTY + "] defined."); - } - } - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] A security exception occurred while trying to create an" + - " instance of the custom factory class" + ": [" + trim(e.getMessage()) + - "]. Trying alternative implementations..."); - } - // ignore - } catch (RuntimeException e) { - // This is not consistent with the behaviour when a bad LogFactory class is - // specified in a services file. - // - // One possible exception that can occur here is a ClassCastException when - // the specified class wasn't castable to this LogFactory type. - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] An exception occurred while trying to create an" + - " instance of the custom factory class" + ": [" + - trim(e.getMessage()) + - "] as specified by a system property."); - } - throw e; - } - - // Second, try to find a service by using the JDK1.3 class - // discovery mechanism, which involves putting a file with the name - // of an interface class in the META-INF/services directory, where the - // contents of the file is a single line specifying a concrete class - // that implements the desired interface. - - if (factory == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Looking for a resource file of name [" + SERVICE_ID + - "] to define the LogFactory subclass to use..."); - } - try { - final InputStream is = getResourceAsStream(contextClassLoader, SERVICE_ID); - - if( is != null ) { - // This code is needed by EBCDIC and other strange systems. - // It's a fix for bugs reported in xerces - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName; - try { - factoryClassName = rd.readLine(); - } finally { - rd.close(); - } - - if (factoryClassName != null && ! "".equals(factoryClassName)) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Creating an instance of LogFactory class " + - factoryClassName + - " as specified by file '" + SERVICE_ID + - "' which was present in the path of the context classloader."); - } - factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader ); - } - } else { - // is == null - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] No resource file with name '" + SERVICE_ID + "' found."); - } - } - } catch (Exception ex) { - // note: if the specified LogFactory class wasn't compatible with LogFactory - // for some reason, a ClassCastException will be caught here, and attempts will - // continue to find a compatible class. - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] A security exception occurred while trying to create an" + - " instance of the custom factory class" + - ": [" + trim(ex.getMessage()) + - "]. Trying alternative implementations..."); - } - // ignore - } - } - - // Third try looking into the properties file read earlier (if found) - - if (factory == null) { - if (props != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Looking in properties file for entry with key '" + FACTORY_PROPERTY + - "' to define the LogFactory subclass to use..."); - } - String factoryClass = props.getProperty(FACTORY_PROPERTY); - if (factoryClass != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Properties file specifies LogFactory subclass '" + factoryClass + "'"); - } - factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); - - // TODO: think about whether we need to handle exceptions from newFactory - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Properties file has no entry specifying LogFactory subclass."); - } - } - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] No properties file available to determine" + " LogFactory subclass from.."); - } - } - } - - // Fourth, try the fallback implementation class - - if (factory == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT + - "' via the same classloader that loaded this LogFactory" + - " class (ie not looking in the context classloader)."); - } - - // Note: unlike the above code which can try to load custom LogFactory - // implementations via the TCCL, we don't try to load the default LogFactory - // implementation via the context classloader because: - // * that can cause problems (see comments in newFactory method) - // * no-one should be customising the code of the default class - // Yes, we do give up the ability for the child to ship a newer - // version of the LogFactoryImpl class and have it used dynamically - // by an old LogFactory class in the parent, but that isn't - // necessarily a good idea anyway. - factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader); - } - - if (factory != null) { - /** - * Always cache using context class loader. - */ - cacheFactory(contextClassLoader, factory); - - if (props != null) { - Enumeration names = props.propertyNames(); - while (names.hasMoreElements()) { - String name = (String) names.nextElement(); - String value = props.getProperty(name); - factory.setAttribute(name, value); - } - } - } - - return factory; - } - - /** - * Convenience method to return a named logger, without the application - * having to care about factories. - * - * @param clazz Class from which a log name will be derived - * @throws LogConfigurationException if a suitable Log - * instance cannot be returned - */ - public static Log getLog(Class clazz) throws LogConfigurationException { - return getFactory().getInstance(clazz); - } - - /** - * Convenience method to return a named logger, without the application - * having to care about factories. - * - * @param name Logical name of the Log instance to be - * returned (the meaning of this name is only known to the underlying - * logging implementation that is being wrapped) - * @throws LogConfigurationException if a suitable Log - * instance cannot be returned - */ - public static Log getLog(String name) throws LogConfigurationException { - return getFactory().getInstance(name); - } - - /** - * Release any internal references to previously created {@link LogFactory} - * instances that have been associated with the specified class loader - * (if any), after calling the instance method release() on - * each of them. - * - * @param classLoader ClassLoader for which to release the LogFactory - */ - public static void release(ClassLoader classLoader) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Releasing factory for classloader " + objectId(classLoader)); - } - // factories is not final and could be replaced in this block. - final Hashtable factories = LogFactory.factories; - synchronized (factories) { - if (classLoader == null) { - if (nullClassLoaderFactory != null) { - nullClassLoaderFactory.release(); - nullClassLoaderFactory = null; - } - } else { - final LogFactory factory = (LogFactory) factories.get(classLoader); - if (factory != null) { - factory.release(); - factories.remove(classLoader); - } - } - } - } - - /** - * Release any internal references to previously created {@link LogFactory} - * instances, after calling the instance method release() on - * each of them. This is useful in environments like servlet containers, - * which implement application reloading by throwing away a ClassLoader. - * Dangling references to objects in that class loader would prevent - * garbage collection. - */ - public static void releaseAll() { - if (isDiagnosticsEnabled()) { - logDiagnostic("Releasing factory for all classloaders."); - } - // factories is not final and could be replaced in this block. - final Hashtable factories = LogFactory.factories; - synchronized (factories) { - final Enumeration elements = factories.elements(); - while (elements.hasMoreElements()) { - LogFactory element = (LogFactory) elements.nextElement(); - element.release(); - } - factories.clear(); - - if (nullClassLoaderFactory != null) { - nullClassLoaderFactory.release(); - nullClassLoaderFactory = null; - } - } - } - - // ------------------------------------------------------ Protected Methods - - /** - * Safely get access to the classloader for the specified class. - *

- * Theoretically, calling getClassLoader can throw a security exception, - * and so should be done under an AccessController in order to provide - * maximum flexibility. However in practice people don't appear to use - * security policies that forbid getClassLoader calls. So for the moment - * all code is written to call this method rather than Class.getClassLoader, - * so that we could put AccessController stuff in this method without any - * disruption later if we need to. - *

- * Even when using an AccessController, however, this method can still - * throw SecurityException. Commons-logging basically relies on the - * ability to access classloaders, ie a policy that forbids all - * classloader access will also prevent commons-logging from working: - * currently this method will throw an exception preventing the entire app - * from starting up. Maybe it would be good to detect this situation and - * just disable all commons-logging? Not high priority though - as stated - * above, security policies that prevent classloader access aren't common. - *

- * Note that returning an object fetched via an AccessController would - * technically be a security flaw anyway; untrusted code that has access - * to a trusted JCL library could use it to fetch the classloader for - * a class even when forbidden to do so directly. - * - * @since 1.1 - */ - protected static ClassLoader getClassLoader(Class clazz) { - try { - return clazz.getClassLoader(); - } catch (SecurityException ex) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to get classloader for class '" + clazz + - "' due to security restrictions - " + ex.getMessage()); - } - throw ex; - } - } - - /** - * Returns the current context classloader. - *

- * In versions prior to 1.1, this method did not use an AccessController. - * In version 1.1, an AccessController wrapper was incorrectly added to - * this method, causing a minor security flaw. - *

- * In version 1.1.1 this change was reverted; this method no longer uses - * an AccessController. User code wishing to obtain the context classloader - * must invoke this method via AccessController.doPrivileged if it needs - * support for that. - * - * @return the context classloader associated with the current thread, - * or null if security doesn't allow it. - * @throws LogConfigurationException if there was some weird error while - * attempting to get the context classloader. - */ - protected static ClassLoader getContextClassLoader() throws LogConfigurationException { - return directGetContextClassLoader(); - } - - /** - * Calls LogFactory.directGetContextClassLoader under the control of an - * AccessController class. This means that java code running under a - * security manager that forbids access to ClassLoaders will still work - * if this class is given appropriate privileges, even when the caller - * doesn't have such privileges. Without using an AccessController, the - * the entire call stack must have the privilege before the call is - * allowed. - * - * @return the context classloader associated with the current thread, - * or null if security doesn't allow it. - * @throws LogConfigurationException if there was some weird error while - * attempting to get the context classloader. - */ - private static ClassLoader getContextClassLoaderInternal() throws LogConfigurationException { - return (ClassLoader)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return directGetContextClassLoader(); - } - }); - } - - /** - * Return the thread context class loader if available; otherwise return null. - *

- * Most/all code should call getContextClassLoaderInternal rather than - * calling this method directly. - *

- * The thread context class loader is available for JDK 1.2 - * or later, if certain security conditions are met. - *

- * Note that no internal logging is done within this method because - * this method is called every time LogFactory.getLogger() is called, - * and we don't want too much output generated here. - * - * @throws LogConfigurationException if a suitable class loader - * cannot be identified. - * @return the thread's context classloader or {@code null} if the java security - * policy forbids access to the context classloader from one of the classes - * in the current call stack. - * @since 1.1 - */ - protected static ClassLoader directGetContextClassLoader() throws LogConfigurationException { - ClassLoader classLoader = null; - - try { - classLoader = Thread.currentThread().getContextClassLoader(); - } catch (SecurityException ex) { - /** - * getContextClassLoader() throws SecurityException when - * the context class loader isn't an ancestor of the - * calling class's class loader, or if security - * permissions are restricted. - * - * We ignore this exception to be consistent with the previous - * behavior (e.g. 1.1.3 and earlier). - */ - // ignore - } - - // Return the selected class loader - return classLoader; - } - - /** - * Check cached factories (keyed by contextClassLoader) - * - * @param contextClassLoader is the context classloader associated - * with the current thread. This allows separate LogFactory objects - * per component within a container, provided each component has - * a distinct context classloader set. This parameter may be null - * in JDK1.1, and in embedded systems where jcl-using code is - * placed in the bootclasspath. - * - * @return the factory associated with the specified classloader if - * one has previously been created, or null if this is the first time - * we have seen this particular classloader. - */ - private static LogFactory getCachedFactory(ClassLoader contextClassLoader) { - if (contextClassLoader == null) { - // We have to handle this specially, as factories is a Hashtable - // and those don't accept null as a key value. - // - // nb: nullClassLoaderFactory might be null. That's ok. - return nullClassLoaderFactory; - } else { - return (LogFactory) factories.get(contextClassLoader); - } - } - - /** - * Remember this factory, so later calls to LogFactory.getCachedFactory - * can return the previously created object (together with all its - * cached Log objects). - * - * @param classLoader should be the current context classloader. Note that - * this can be null under some circumstances; this is ok. - * @param factory should be the factory to cache. This should never be null. - */ - private static void cacheFactory(ClassLoader classLoader, LogFactory factory) { - // Ideally we would assert(factory != null) here. However reporting - // errors from within a logging implementation is a little tricky! - - if (factory != null) { - if (classLoader == null) { - nullClassLoaderFactory = factory; - } else { - factories.put(classLoader, factory); - } - } - } - - /** - * Return a new instance of the specified LogFactory - * implementation class, loaded by the specified class loader. - * If that fails, try the class loader used to load this - * (abstract) LogFactory. - *

ClassLoader conflicts

- *

- * Note that there can be problems if the specified ClassLoader is not the - * same as the classloader that loaded this class, ie when loading a - * concrete LogFactory subclass via a context classloader. - *

- * The problem is the same one that can occur when loading a concrete Log - * subclass via a context classloader. - *

- * The problem occurs when code running in the context classloader calls - * class X which was loaded via a parent classloader, and class X then calls - * LogFactory.getFactory (either directly or via LogFactory.getLog). Because - * class X was loaded via the parent, it binds to LogFactory loaded via - * the parent. When the code in this method finds some LogFactoryYYYY - * class in the child (context) classloader, and there also happens to be a - * LogFactory class defined in the child classloader, then LogFactoryYYYY - * will be bound to LogFactory@childloader. It cannot be cast to - * LogFactory@parentloader, ie this method cannot return the object as - * the desired type. Note that it doesn't matter if the LogFactory class - * in the child classloader is identical to the LogFactory class in the - * parent classloader, they are not compatible. - *

- * The solution taken here is to simply print out an error message when - * this occurs then throw an exception. The deployer of the application - * must ensure they remove all occurrences of the LogFactory class from - * the child classloader in order to resolve the issue. Note that they - * do not have to move the custom LogFactory subclass; that is ok as - * long as the only LogFactory class it can find to bind to is in the - * parent classloader. - * - * @param factoryClass Fully qualified name of the LogFactory - * implementation class - * @param classLoader ClassLoader from which to load this class - * @param contextClassLoader is the context that this new factory will - * manage logging for. - * @throws LogConfigurationException if a suitable instance - * cannot be created - * @since 1.1 - */ - protected static LogFactory newFactory(final String factoryClass, - final ClassLoader classLoader, - final ClassLoader contextClassLoader) - throws LogConfigurationException { - // Note that any unchecked exceptions thrown by the createFactory - // method will propagate out of this method; in particular a - // ClassCastException can be thrown. - Object result = AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return createFactory(factoryClass, classLoader); - } - }); - - if (result instanceof LogConfigurationException) { - LogConfigurationException ex = (LogConfigurationException) result; - if (isDiagnosticsEnabled()) { - logDiagnostic("An error occurred while loading the factory class:" + ex.getMessage()); - } - throw ex; - } - if (isDiagnosticsEnabled()) { - logDiagnostic("Created object " + objectId(result) + " to manage classloader " + - objectId(contextClassLoader)); - } - return (LogFactory)result; - } - - /** - * Method provided for backwards compatibility; see newFactory version that - * takes 3 parameters. - *

- * This method would only ever be called in some rather odd situation. - * Note that this method is static, so overriding in a subclass doesn't - * have any effect unless this method is called from a method in that - * subclass. However this method only makes sense to use from the - * getFactory method, and as that is almost always invoked via - * LogFactory.getFactory, any custom definition in a subclass would be - * pointless. Only a class with a custom getFactory method, then invoked - * directly via CustomFactoryImpl.getFactory or similar would ever call - * this. Anyway, it's here just in case, though the "managed class loader" - * value output to the diagnostics will not report the correct value. - */ - protected static LogFactory newFactory(final String factoryClass, - final ClassLoader classLoader) { - return newFactory(factoryClass, classLoader, null); - } - - /** - * Implements the operations described in the javadoc for newFactory. - * - * @param factoryClass - * @param classLoader used to load the specified factory class. This is - * expected to be either the TCCL or the classloader which loaded this - * class. Note that the classloader which loaded this class might be - * "null" (ie the bootloader) for embedded systems. - * @return either a LogFactory object or a LogConfigurationException object. - * @since 1.1 - */ - protected static Object createFactory(String factoryClass, ClassLoader classLoader) { - // This will be used to diagnose bad configurations - // and allow a useful message to be sent to the user - Class logFactoryClass = null; - try { - if (classLoader != null) { - try { - // First the given class loader param (thread class loader) - - // Warning: must typecast here & allow exception - // to be generated/caught & recast properly. - logFactoryClass = classLoader.loadClass(factoryClass); - if (LogFactory.class.isAssignableFrom(logFactoryClass)) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Loaded class " + logFactoryClass.getName() + - " from classloader " + objectId(classLoader)); - } - } else { - // - // This indicates a problem with the ClassLoader tree. - // An incompatible ClassLoader was used to load the - // implementation. - // As the same classes - // must be available in multiple class loaders, - // it is very likely that multiple JCL jars are present. - // The most likely fix for this - // problem is to remove the extra JCL jars from the - // ClassLoader hierarchy. - // - if (isDiagnosticsEnabled()) { - logDiagnostic("Factory class " + logFactoryClass.getName() + - " loaded from classloader " + objectId(logFactoryClass.getClassLoader()) + - " does not extend '" + LogFactory.class.getName() + - "' as loaded by this classloader."); - logHierarchy("[BAD CL TREE] ", classLoader); - } - } - - return (LogFactory) logFactoryClass.newInstance(); - - } catch (ClassNotFoundException ex) { - if (classLoader == thisClassLoader) { - // Nothing more to try, onwards. - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to locate any class called '" + factoryClass + - "' via classloader " + objectId(classLoader)); - } - throw ex; - } - // ignore exception, continue - } catch (NoClassDefFoundError e) { - if (classLoader == thisClassLoader) { - // Nothing more to try, onwards. - if (isDiagnosticsEnabled()) { - logDiagnostic("Class '" + factoryClass + "' cannot be loaded" + - " via classloader " + objectId(classLoader) + - " - it depends on some other class that cannot be found."); - } - throw e; - } - // ignore exception, continue - } catch (ClassCastException e) { - if (classLoader == thisClassLoader) { - // There's no point in falling through to the code below that - // tries again with thisClassLoader, because we've just tried - // loading with that loader (not the TCCL). Just throw an - // appropriate exception here. - - final boolean implementsLogFactory = implementsLogFactory(logFactoryClass); - - // - // Construct a good message: users may not actual expect that a custom implementation - // has been specified. Several well known containers use this mechanism to adapt JCL - // to their native logging system. - // - final StringBuffer msg = new StringBuffer(); - msg.append("The application has specified that a custom LogFactory implementation "); - msg.append("should be used but Class '"); - msg.append(factoryClass); - msg.append("' cannot be converted to '"); - msg.append(LogFactory.class.getName()); - msg.append("'. "); - if (implementsLogFactory) { - msg.append("The conflict is caused by the presence of multiple LogFactory classes "); - msg.append("in incompatible classloaders. "); - msg.append("Background can be found in http://commons.apache.org/logging/tech.html. "); - msg.append("If you have not explicitly specified a custom LogFactory then it is likely "); - msg.append("that the container has set one without your knowledge. "); - msg.append("In this case, consider using the commons-logging-adapters.jar file or "); - msg.append("specifying the standard LogFactory from the command line. "); - } else { - msg.append("Please check the custom implementation. "); - } - msg.append("Help can be found @http://commons.apache.org/logging/troubleshooting.html."); - - if (isDiagnosticsEnabled()) { - logDiagnostic(msg.toString()); - } - - throw new ClassCastException(msg.toString()); - } - - // Ignore exception, continue. Presumably the classloader was the - // TCCL; the code below will try to load the class via thisClassLoader. - // This will handle the case where the original calling class is in - // a shared classpath but the TCCL has a copy of LogFactory and the - // specified LogFactory implementation; we will fall back to using the - // LogFactory implementation from the same classloader as this class. - // - // Issue: this doesn't handle the reverse case, where this LogFactory - // is in the webapp, and the specified LogFactory implementation is - // in a shared classpath. In that case: - // (a) the class really does implement LogFactory (bad log msg above) - // (b) the fallback code will result in exactly the same problem. - } - } - - /* At this point, either classLoader == null, OR - * classLoader was unable to load factoryClass. - * - * In either case, we call Class.forName, which is equivalent - * to LogFactory.class.getClassLoader().load(name), ie we ignore - * the classloader parameter the caller passed, and fall back - * to trying the classloader associated with this class. See the - * javadoc for the newFactory method for more info on the - * consequences of this. - * - * Notes: - * * LogFactory.class.getClassLoader() may return 'null' - * if LogFactory is loaded by the bootstrap classloader. - */ - // Warning: must typecast here & allow exception - // to be generated/caught & recast properly. - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to load factory class via classloader " + objectId(classLoader) + - " - trying the classloader associated with this LogFactory."); - } - logFactoryClass = Class.forName(factoryClass); - return (LogFactory) logFactoryClass.newInstance(); - } catch (Exception e) { - // Check to see if we've got a bad configuration - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to create LogFactory instance."); - } - if (logFactoryClass != null && !LogFactory.class.isAssignableFrom(logFactoryClass)) { - return new LogConfigurationException( - "The chosen LogFactory implementation does not extend LogFactory." + - " Please check your configuration.", e); - } - return new LogConfigurationException(e); - } - } - - /** - * Determines whether the given class actually implements LogFactory. - * Diagnostic information is also logged. - *

- * Usage: to diagnose whether a classloader conflict is the cause - * of incompatibility. The test used is whether the class is assignable from - * the LogFactory class loaded by the class's classloader. - * @param logFactoryClass Class which may implement LogFactory - * @return true if the logFactoryClass does extend - * LogFactory when that class is loaded via the same - * classloader that loaded the logFactoryClass. - */ - private static boolean implementsLogFactory(Class logFactoryClass) { - boolean implementsLogFactory = false; - if (logFactoryClass != null) { - try { - ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader(); - if (logFactoryClassLoader == null) { - logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot classloader"); - } else { - logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader); - Class factoryFromCustomLoader - = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader); - implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass); - if (implementsLogFactory) { - logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() + - " implements LogFactory but was loaded by an incompatible classloader."); - } else { - logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() + - " does not implement LogFactory."); - } - } - } catch (SecurityException e) { - // - // The application is running within a hostile security environment. - // This will make it very hard to diagnose issues with JCL. - // Consider running less securely whilst debugging this issue. - // - logDiagnostic("[CUSTOM LOG FACTORY] SecurityException thrown whilst trying to determine whether " + - "the compatibility was caused by a classloader conflict: " + e.getMessage()); - } catch (LinkageError e) { - // - // This should be an unusual circumstance. - // LinkageError's usually indicate that a dependent class has incompatibly changed. - // Another possibility may be an exception thrown by an initializer. - // Time for a clean rebuild? - // - logDiagnostic("[CUSTOM LOG FACTORY] LinkageError thrown whilst trying to determine whether " + - "the compatibility was caused by a classloader conflict: " + e.getMessage()); - } catch (ClassNotFoundException e) { - // - // LogFactory cannot be loaded by the classloader which loaded the custom factory implementation. - // The custom implementation is not viable until this is corrected. - // Ensure that the JCL jar and the custom class are available from the same classloader. - // Running with diagnostics on should give information about the classloaders used - // to load the custom factory. - // - logDiagnostic("[CUSTOM LOG FACTORY] LogFactory class cannot be loaded by classloader which loaded " + - "the custom LogFactory implementation. Is the custom factory in the right classloader?"); - } - } - return implementsLogFactory; - } - - /** - * Applets may run in an environment where accessing resources of a loader is - * a secure operation, but where the commons-logging library has explicitly - * been granted permission for that operation. In this case, we need to - * run the operation using an AccessController. - */ - private static InputStream getResourceAsStream(final ClassLoader loader, final String name) { - return (InputStream)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - if (loader != null) { - return loader.getResourceAsStream(name); - } else { - return ClassLoader.getSystemResourceAsStream(name); - } - } - }); - } - - /** - * Given a filename, return an enumeration of URLs pointing to - * all the occurrences of that filename in the classpath. - *

- * This is just like ClassLoader.getResources except that the - * operation is done under an AccessController so that this method will - * succeed when this jarfile is privileged but the caller is not. - * This method must therefore remain private to avoid security issues. - *

- * If no instances are found, an Enumeration is returned whose - * hasMoreElements method returns false (ie an "empty" enumeration). - * If resources could not be listed for some reason, null is returned. - */ - private static Enumeration getResources(final ClassLoader loader, final String name) { - PrivilegedAction action = - new PrivilegedAction() { - public Object run() { - try { - if (loader != null) { - return loader.getResources(name); - } else { - return ClassLoader.getSystemResources(name); - } - } catch (IOException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Exception while trying to find configuration file " + - name + ":" + e.getMessage()); - } - return null; - } catch (NoSuchMethodError e) { - // we must be running on a 1.1 JVM which doesn't support - // ClassLoader.getSystemResources; just return null in - // this case. - return null; - } - } - }; - Object result = AccessController.doPrivileged(action); - return (Enumeration) result; - } - - /** - * Given a URL that refers to a .properties file, load that file. - * This is done under an AccessController so that this method will - * succeed when this jarfile is privileged but the caller is not. - * This method must therefore remain private to avoid security issues. - *

- * {@code Null} is returned if the URL cannot be opened. - */ - private static Properties getProperties(final URL url) { - PrivilegedAction action = - new PrivilegedAction() { - public Object run() { - InputStream stream = null; - try { - // We must ensure that useCaches is set to false, as the - // default behaviour of java is to cache file handles, and - // this "locks" files, preventing hot-redeploy on windows. - URLConnection connection = url.openConnection(); - connection.setUseCaches(false); - stream = connection.getInputStream(); - if (stream != null) { - Properties props = new Properties(); - props.load(stream); - stream.close(); - stream = null; - return props; - } - } catch (IOException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to read URL " + url); - } - } finally { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - // ignore exception; this should not happen - if (isDiagnosticsEnabled()) { - logDiagnostic("Unable to close stream for URL " + url); - } - } - } - } - - return null; - } - }; - return (Properties) AccessController.doPrivileged(action); - } - - /** - * Locate a user-provided configuration file. - *

- * The classpath of the specified classLoader (usually the context classloader) - * is searched for properties files of the specified name. If none is found, - * null is returned. If more than one is found, then the file with the greatest - * value for its PRIORITY property is returned. If multiple files have the - * same PRIORITY value then the first in the classpath is returned. - *

- * This differs from the 1.0.x releases; those always use the first one found. - * However as the priority is a new field, this change is backwards compatible. - *

- * The purpose of the priority field is to allow a webserver administrator to - * override logging settings in all webapps by placing a commons-logging.properties - * file in a shared classpath location with a priority > 0; this overrides any - * commons-logging.properties files without priorities which are in the - * webapps. Webapps can also use explicit priorities to override a configuration - * file in the shared classpath if needed. - */ - private static final Properties getConfigurationFile(ClassLoader classLoader, String fileName) { - Properties props = null; - double priority = 0.0; - URL propsUrl = null; - try { - Enumeration urls = getResources(classLoader, fileName); - - if (urls == null) { - return null; - } - - while (urls.hasMoreElements()) { - URL url = (URL) urls.nextElement(); - - Properties newProps = getProperties(url); - if (newProps != null) { - if (props == null) { - propsUrl = url; - props = newProps; - String priorityStr = props.getProperty(PRIORITY_KEY); - priority = 0.0; - if (priorityStr != null) { - priority = Double.parseDouble(priorityStr); - } - - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Properties file found at '" + url + "'" + - " with priority " + priority); - } - } else { - String newPriorityStr = newProps.getProperty(PRIORITY_KEY); - double newPriority = 0.0; - if (newPriorityStr != null) { - newPriority = Double.parseDouble(newPriorityStr); - } - - if (newPriority > priority) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Properties file at '" + url + "'" + - " with priority " + newPriority + - " overrides file at '" + propsUrl + "'" + - " with priority " + priority); - } - - propsUrl = url; - props = newProps; - priority = newPriority; - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic("[LOOKUP] Properties file at '" + url + "'" + - " with priority " + newPriority + - " does not override file at '" + propsUrl + "'" + - " with priority " + priority); - } - } - } - - } - } - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("SecurityException thrown while trying to find/read config files."); - } - } - - if (isDiagnosticsEnabled()) { - if (props == null) { - logDiagnostic("[LOOKUP] No properties file of name '" + fileName + "' found."); - } else { - logDiagnostic("[LOOKUP] Properties file of name '" + fileName + "' found at '" + propsUrl + '"'); - } - } - - return props; - } - - /** - * Read the specified system property, using an AccessController so that - * the property can be read if JCL has been granted the appropriate - * security rights even if the calling code has not. - *

- * Take care not to expose the value returned by this method to the - * calling application in any way; otherwise the calling app can use that - * info to access data that should not be available to it. - */ - private static String getSystemProperty(final String key, final String def) - throws SecurityException { - return (String) AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return System.getProperty(key, def); - } - }); - } - - /** - * Determines whether the user wants internal diagnostic output. If so, - * returns an appropriate writer object. Users can enable diagnostic - * output by setting the system property named {@link #DIAGNOSTICS_DEST_PROPERTY} to - * a filename, or the special values STDOUT or STDERR. - */ - private static PrintStream initDiagnostics() { - String dest; - try { - dest = getSystemProperty(DIAGNOSTICS_DEST_PROPERTY, null); - if (dest == null) { - return null; - } - } catch (SecurityException ex) { - // We must be running in some very secure environment. - // We just have to assume output is not wanted.. - return null; - } - - if (dest.equals("STDOUT")) { - return System.out; - } else if (dest.equals("STDERR")) { - return System.err; - } else { - try { - // open the file in append mode - FileOutputStream fos = new FileOutputStream(dest, true); - return new PrintStream(fos); - } catch (IOException ex) { - // We should report this to the user - but how? - return null; - } - } - } - - /** - * Indicates true if the user has enabled internal logging. - *

- * By the way, sorry for the incorrect grammar, but calling this method - * areDiagnosticsEnabled just isn't java beans style. - * - * @return true if calls to logDiagnostic will have any effect. - * @since 1.1 - */ - protected static boolean isDiagnosticsEnabled() { - return diagnosticsStream != null; - } - - /** - * Write the specified message to the internal logging destination. - *

- * Note that this method is private; concrete subclasses of this class - * should not call it because the diagnosticPrefix string this - * method puts in front of all its messages is LogFactory@...., - * while subclasses should put SomeSubClass@... - *

- * Subclasses should instead compute their own prefix, then call - * logRawDiagnostic. Note that calling isDiagnosticsEnabled is - * fine for subclasses. - *

- * Note that it is safe to call this method before initDiagnostics - * is called; any output will just be ignored (as isDiagnosticsEnabled - * will return false). - * - * @param msg is the diagnostic message to be output. - */ - private static final void logDiagnostic(String msg) { - if (diagnosticsStream != null) { - diagnosticsStream.print(diagnosticPrefix); - diagnosticsStream.println(msg); - diagnosticsStream.flush(); - } - } - - /** - * Write the specified message to the internal logging destination. - * - * @param msg is the diagnostic message to be output. - * @since 1.1 - */ - protected static final void logRawDiagnostic(String msg) { - if (diagnosticsStream != null) { - diagnosticsStream.println(msg); - diagnosticsStream.flush(); - } - } - - /** - * Generate useful diagnostics regarding the classloader tree for - * the specified class. - *

- * As an example, if the specified class was loaded via a webapp's - * classloader, then you may get the following output: - *

-     * Class com.acme.Foo was loaded via classloader 11111
-     * ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT
-     * 
- *

- * This method returns immediately if isDiagnosticsEnabled() - * returns false. - * - * @param clazz is the class whose classloader + tree are to be - * output. - */ - private static void logClassLoaderEnvironment(Class clazz) { - if (!isDiagnosticsEnabled()) { - return; - } - - try { - // Deliberately use System.getProperty here instead of getSystemProperty; if - // the overall security policy for the calling application forbids access to - // these variables then we do not want to output them to the diagnostic stream. - logDiagnostic("[ENV] Extension directories (java.ext.dir): " + System.getProperty("java.ext.dir")); - logDiagnostic("[ENV] Application classpath (java.class.path): " + System.getProperty("java.class.path")); - } catch (SecurityException ex) { - logDiagnostic("[ENV] Security setting prevent interrogation of system classpaths."); - } - - String className = clazz.getName(); - ClassLoader classLoader; - - try { - classLoader = getClassLoader(clazz); - } catch (SecurityException ex) { - // not much useful diagnostics we can print here! - logDiagnostic("[ENV] Security forbids determining the classloader for " + className); - return; - } - - logDiagnostic("[ENV] Class " + className + " was loaded via classloader " + objectId(classLoader)); - logHierarchy("[ENV] Ancestry of classloader which loaded " + className + " is ", classLoader); - } - - /** - * Logs diagnostic messages about the given classloader - * and it's hierarchy. The prefix is prepended to the message - * and is intended to make it easier to understand the logs. - * @param prefix - * @param classLoader - */ - private static void logHierarchy(String prefix, ClassLoader classLoader) { - if (!isDiagnosticsEnabled()) { - return; - } - ClassLoader systemClassLoader; - if (classLoader != null) { - final String classLoaderString = classLoader.toString(); - logDiagnostic(prefix + objectId(classLoader) + " == '" + classLoaderString + "'"); - } - - try { - systemClassLoader = ClassLoader.getSystemClassLoader(); - } catch (SecurityException ex) { - logDiagnostic(prefix + "Security forbids determining the system classloader."); - return; - } - if (classLoader != null) { - final StringBuffer buf = new StringBuffer(prefix + "ClassLoader tree:"); - for(;;) { - buf.append(objectId(classLoader)); - if (classLoader == systemClassLoader) { - buf.append(" (SYSTEM) "); - } - - try { - classLoader = classLoader.getParent(); - } catch (SecurityException ex) { - buf.append(" --> SECRET"); - break; - } - - buf.append(" --> "); - if (classLoader == null) { - buf.append("BOOT"); - break; - } - } - logDiagnostic(buf.toString()); - } - } - - /** - * Returns a string that uniquely identifies the specified object, including - * its class. - *

- * The returned string is of form "classname@hashcode", ie is the same as - * the return value of the Object.toString() method, but works even when - * the specified object's class has overidden the toString method. - * - * @param o may be null. - * @return a string of form classname@hashcode, or "null" if param o is null. - * @since 1.1 - */ - public static String objectId(Object o) { - if (o == null) { - return "null"; - } else { - return o.getClass().getName() + "@" + System.identityHashCode(o); - } - } - - // ---------------------------------------------------------------------- - // Static initialiser block to perform initialisation at class load time. - // - // We can't do this in the class constructor, as there are many - // static methods on this class that can be called before any - // LogFactory instances are created, and they depend upon this - // stuff having been set up. - // - // Note that this block must come after any variable declarations used - // by any methods called from this block, as we want any static initialiser - // associated with the variable to run first. If static initialisers for - // variables run after this code, then (a) their value might be needed - // by methods called from here, and (b) they might *override* any value - // computed here! - // - // So the wisest thing to do is just to place this code at the very end - // of the class file. - // ---------------------------------------------------------------------- - - static { - // note: it's safe to call methods before initDiagnostics (though - // diagnostic output gets discarded). - thisClassLoader = getClassLoader(LogFactory.class); - // In order to avoid confusion where multiple instances of JCL are - // being used via different classloaders within the same app, we - // ensure each logged message has a prefix of form - // [LogFactory from classloader OID] - // - // Note that this prefix should be kept consistent with that - // in LogFactoryImpl. However here we don't need to output info - // about the actual *instance* of LogFactory, as all methods that - // output diagnostics from this class are static. - String classLoaderName; - try { - ClassLoader classLoader = thisClassLoader; - if (thisClassLoader == null) { - classLoaderName = "BOOTLOADER"; - } else { - classLoaderName = objectId(classLoader); - } - } catch (SecurityException e) { - classLoaderName = "UNKNOWN"; - } - diagnosticPrefix = "[LogFactory from " + classLoaderName + "] "; - diagnosticsStream = initDiagnostics(); - logClassLoaderEnvironment(LogFactory.class); - factories = createFactoryStore(); - if (isDiagnosticsEnabled()) { - logDiagnostic("BOOTSTRAP COMPLETED"); - } - } -} diff --git a/src/org/apache/commons/logging/LogSource.java b/src/org/apache/commons/logging/LogSource.java deleted file mode 100644 index d9afaf604ec..00000000000 --- a/src/org/apache/commons/logging/LogSource.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging; - -import java.lang.reflect.Constructor; -import java.util.Hashtable; - -import org.apache.commons.logging.impl.NoOpLog; - -/** - * Factory for creating {@link Log} instances. Applications should call - * the makeNewLogInstance() method to instantiate new instances - * of the configured {@link Log} implementation class. - *

- * By default, calling getInstance() will use the following - * algorithm: - *

    - *
  • If Log4J is available, return an instance of - * org.apache.commons.logging.impl.Log4JLogger.
  • - *
  • If JDK 1.4 or later is available, return an instance of - * org.apache.commons.logging.impl.Jdk14Logger.
  • - *
  • Otherwise, return an instance of - * org.apache.commons.logging.impl.NoOpLog.
  • - *
- *

- * You can change the default behavior in one of two ways: - *

    - *
  • On the startup command line, set the system property - * org.apache.commons.logging.log to the name of the - * org.apache.commons.logging.Log implementation class - * you want to use.
  • - *
  • At runtime, call LogSource.setLogImplementation().
  • - *
- * - * @deprecated Use {@link LogFactory} instead - The default factory - * implementation performs exactly the same algorithm as this class did - * - * @version $Id: LogSource.java 1612041 2014-07-20 06:54:48Z ggregory $ - */ -public class LogSource { - - // ------------------------------------------------------- Class Attributes - - static protected Hashtable logs = new Hashtable(); - - /** Is log4j available (in the current classpath) */ - static protected boolean log4jIsAvailable = false; - - /** Is JDK 1.4 logging available */ - static protected boolean jdk14IsAvailable = false; - - /** Constructor for current log class */ - static protected Constructor logImplctor = null; - - // ----------------------------------------------------- Class Initializers - - static { - - // Is Log4J Available? - try { - log4jIsAvailable = null != Class.forName("org.apache.log4j.Logger"); - } catch (Throwable t) { - log4jIsAvailable = false; - } - - // Is JDK 1.4 Logging Available? - try { - jdk14IsAvailable = null != Class.forName("java.util.logging.Logger") && - null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger"); - } catch (Throwable t) { - jdk14IsAvailable = false; - } - - // Set the default Log implementation - String name = null; - try { - name = System.getProperty("org.apache.commons.logging.log"); - if (name == null) { - name = System.getProperty("org.apache.commons.logging.Log"); - } - } catch (Throwable t) { - } - if (name != null) { - try { - setLogImplementation(name); - } catch (Throwable t) { - try { - setLogImplementation("org.apache.commons.logging.impl.NoOpLog"); - } catch (Throwable u) { - // ignored - } - } - } else { - try { - if (log4jIsAvailable) { - setLogImplementation("org.apache.commons.logging.impl.Log4JLogger"); - } else if (jdk14IsAvailable) { - setLogImplementation("org.apache.commons.logging.impl.Jdk14Logger"); - } else { - setLogImplementation("org.apache.commons.logging.impl.NoOpLog"); - } - } catch (Throwable t) { - try { - setLogImplementation("org.apache.commons.logging.impl.NoOpLog"); - } catch (Throwable u) { - // ignored - } - } - } - - } - - // ------------------------------------------------------------ Constructor - - /** Don't allow others to create instances. */ - private LogSource() { - } - - // ---------------------------------------------------------- Class Methods - - /** - * Set the log implementation/log implementation factory - * by the name of the class. The given class must implement {@link Log}, - * and provide a constructor that takes a single {@link String} argument - * (containing the name of the log). - */ - static public void setLogImplementation(String classname) - throws LinkageError, NoSuchMethodException, SecurityException, ClassNotFoundException { - try { - Class logclass = Class.forName(classname); - Class[] argtypes = new Class[1]; - argtypes[0] = "".getClass(); - logImplctor = logclass.getConstructor(argtypes); - } catch (Throwable t) { - logImplctor = null; - } - } - - /** - * Set the log implementation/log implementation factory by class. - * The given class must implement {@link Log}, and provide a constructor - * that takes a single {@link String} argument (containing the name of the log). - */ - static public void setLogImplementation(Class logclass) - throws LinkageError, ExceptionInInitializerError, NoSuchMethodException, SecurityException { - Class[] argtypes = new Class[1]; - argtypes[0] = "".getClass(); - logImplctor = logclass.getConstructor(argtypes); - } - - /** Get a Log instance by class name. */ - static public Log getInstance(String name) { - Log log = (Log) logs.get(name); - if (null == log) { - log = makeNewLogInstance(name); - logs.put(name, log); - } - return log; - } - - /** Get a Log instance by class. */ - static public Log getInstance(Class clazz) { - return getInstance(clazz.getName()); - } - - /** - * Create a new {@link Log} implementation, based on the given name. - *

- * The specific {@link Log} implementation returned is determined by the - * value of the {@code org.apache.commons.logging.log} property. The value - * of {@code org.apache.commons.logging.log} may be set to the fully specified - * name of a class that implements the {@link Log} interface. This class must - * also have a public constructor that takes a single {@link String} argument - * (containing the name of the {@link Log} to be constructed. - *

- * When {@code org.apache.commons.logging.log} is not set, or when no corresponding - * class can be found, this method will return a Log4JLogger if the log4j Logger - * class is available in the {@link LogSource}'s classpath, or a Jdk14Logger if we - * are on a JDK 1.4 or later system, or NoOpLog if neither of the above conditions is true. - * - * @param name the log name (or category) - */ - static public Log makeNewLogInstance(String name) { - Log log; - try { - Object[] args = { name }; - log = (Log) logImplctor.newInstance(args); - } catch (Throwable t) { - log = null; - } - if (null == log) { - log = new NoOpLog(name); - } - return log; - } - - /** - * Returns a {@link String} array containing the names of - * all logs known to me. - */ - static public String[] getLogNames() { - return (String[]) logs.keySet().toArray(new String[logs.size()]); - } -} diff --git a/src/org/apache/commons/logging/impl/AvalonLogger.java b/src/org/apache/commons/logging/impl/AvalonLogger.java deleted file mode 100644 index 344462ba624..00000000000 --- a/src/org/apache/commons/logging/impl/AvalonLogger.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import org.apache.avalon.framework.logger.Logger; -import org.apache.commons.logging.Log; - -/** - * Implementation of commons-logging Log interface that delegates all - * logging calls to the Avalon logging abstraction: the Logger interface. - *

- * There are two ways in which this class can be used: - *

    - *
  • the instance can be constructed with an Avalon logger - * (by calling {@link #AvalonLogger(Logger)}). In this case, it acts - * as a simple thin wrapping implementation over the logger. This is - * particularly useful when using a property setter. - *
  • - *
  • the {@link #setDefaultLogger} class property can be called which - * sets the ancestral Avalon logger for this class. Any AvalonLogger - * instances created through the LogFactory mechanisms will output - * to child loggers of this Logger. - *
  • - *
- *

- * Note: AvalonLogger does not implement Serializable - * because the constructors available for it make this impossible to achieve in all - * circumstances; there is no way to "reconnect" to an underlying Logger object on - * deserialization if one was just passed in to the constructor of the original - * object. This class was marked Serializable in the 1.0.4 release of - * commons-logging, but this never actually worked (a NullPointerException would - * be thrown as soon as the deserialized object was used), so removing this marker - * is not considered to be an incompatible change. - * - * @version $Id: AvalonLogger.java 1435115 2013-01-18 12:40:19Z tn $ - */ -public class AvalonLogger implements Log { - - /** Ancestral Avalon logger. */ - private static volatile Logger defaultLogger = null; - /** Avalon logger used to perform log. */ - private final transient Logger logger; - - /** - * Constructs an AvalonLogger that outputs to the given - * Logger instance. - * - * @param logger the Avalon logger implementation to delegate to - */ - public AvalonLogger(Logger logger) { - this.logger = logger; - } - - /** - * Constructs an AvalonLogger that will log to a child - * of the Logger set by calling {@link #setDefaultLogger}. - * - * @param name the name of the avalon logger implementation to delegate to - */ - public AvalonLogger(String name) { - if (defaultLogger == null) { - throw new NullPointerException("default logger has to be specified if this constructor is used!"); - } - this.logger = defaultLogger.getChildLogger(name); - } - - /** - * Gets the Avalon logger implementation used to perform logging. - * - * @return avalon logger implementation - */ - public Logger getLogger() { - return logger; - } - - /** - * Sets the ancestral Avalon logger from which the delegating loggers will descend. - * - * @param logger the default avalon logger, - * in case there is no logger instance supplied in constructor - */ - public static void setDefaultLogger(Logger logger) { - defaultLogger = logger; - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.debug. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public void debug(Object message, Throwable t) { - if (getLogger().isDebugEnabled()) { - getLogger().debug(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.debug. - * - * @param message to log. - * @see org.apache.commons.logging.Log#debug(Object) - */ - public void debug(Object message) { - if (getLogger().isDebugEnabled()) { - getLogger().debug(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.error. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public void error(Object message, Throwable t) { - if (getLogger().isErrorEnabled()) { - getLogger().error(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.error. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public void error(Object message) { - if (getLogger().isErrorEnabled()) { - getLogger().error(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.fatalError. - * - * @param message to log. - * @param t log this cause. - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public void fatal(Object message, Throwable t) { - if (getLogger().isFatalErrorEnabled()) { - getLogger().fatalError(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.fatalError. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public void fatal(Object message) { - if (getLogger().isFatalErrorEnabled()) { - getLogger().fatalError(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.info. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public void info(Object message, Throwable t) { - if (getLogger().isInfoEnabled()) { - getLogger().info(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.info. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public void info(Object message) { - if (getLogger().isInfoEnabled()) { - getLogger().info(String.valueOf(message)); - } - } - - /** - * Is logging to org.apache.avalon.framework.logger.Logger.debug enabled? - * @see org.apache.commons.logging.Log#isDebugEnabled() - */ - public boolean isDebugEnabled() { - return getLogger().isDebugEnabled(); - } - - /** - * Is logging to org.apache.avalon.framework.logger.Logger.error enabled? - * @see org.apache.commons.logging.Log#isErrorEnabled() - */ - public boolean isErrorEnabled() { - return getLogger().isErrorEnabled(); - } - - /** - * Is logging to org.apache.avalon.framework.logger.Logger.fatalError enabled? - * @see org.apache.commons.logging.Log#isFatalEnabled() - */ - public boolean isFatalEnabled() { - return getLogger().isFatalErrorEnabled(); - } - - /** - * Is logging to org.apache.avalon.framework.logger.Logger.info enabled? - * @see org.apache.commons.logging.Log#isInfoEnabled() - */ - public boolean isInfoEnabled() { - return getLogger().isInfoEnabled(); - } - - /** - * Is logging to org.apache.avalon.framework.logger.Logger.debug enabled? - * @see org.apache.commons.logging.Log#isTraceEnabled() - */ - public boolean isTraceEnabled() { - return getLogger().isDebugEnabled(); - } - - /** - * Is logging to org.apache.avalon.framework.logger.Logger.warn enabled? - * @see org.apache.commons.logging.Log#isWarnEnabled() - */ - public boolean isWarnEnabled() { - return getLogger().isWarnEnabled(); - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.debug. - * - * @param message to log. - * @param t log this cause. - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public void trace(Object message, Throwable t) { - if (getLogger().isDebugEnabled()) { - getLogger().debug(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.debug. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public void trace(Object message) { - if (getLogger().isDebugEnabled()) { - getLogger().debug(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.warn. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public void warn(Object message, Throwable t) { - if (getLogger().isWarnEnabled()) { - getLogger().warn(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.avalon.framework.logger.Logger.warn. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public void warn(Object message) { - if (getLogger().isWarnEnabled()) { - getLogger().warn(String.valueOf(message)); - } - } -} diff --git a/src/org/apache/commons/logging/impl/Jdk13LumberjackLogger.java b/src/org/apache/commons/logging/impl/Jdk13LumberjackLogger.java deleted file mode 100644 index da3faa48c76..00000000000 --- a/src/org/apache/commons/logging/impl/Jdk13LumberjackLogger.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.io.Serializable; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.LogRecord; -import java.util.StringTokenizer; -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.apache.commons.logging.Log; - -/** - * Implementation of the org.apache.commons.logging.Log - * interface that wraps the standard JDK logging mechanisms that are - * available in SourceForge's Lumberjack for JDKs prior to 1.4. - * - * @version $Id: Jdk13LumberjackLogger.java 1432663 2013-01-13 17:24:18Z tn $ - * @since 1.1 - */ -public class Jdk13LumberjackLogger implements Log, Serializable { - - /** Serializable version identifier. */ - private static final long serialVersionUID = -8649807923527610591L; - - // ----------------------------------------------------- Instance Variables - - /** - * The underlying Logger implementation we are using. - */ - protected transient Logger logger = null; - protected String name = null; - private String sourceClassName = "unknown"; - private String sourceMethodName = "unknown"; - private boolean classAndMethodFound = false; - - /** - * This member variable simply ensures that any attempt to initialise - * this class in a pre-1.4 JVM will result in an ExceptionInInitializerError. - * It must not be private, as an optimising compiler could detect that it - * is not used and optimise it away. - */ - protected static final Level dummyLevel = Level.FINE; - - // ----------------------------------------------------------- Constructors - - /** - * Construct a named instance of this Logger. - * - * @param name Name of the logger to be constructed - */ - public Jdk13LumberjackLogger(String name) { - this.name = name; - logger = getLogger(); - } - - // --------------------------------------------------------- Public Methods - - private void log( Level level, String msg, Throwable ex ) { - if( getLogger().isLoggable(level) ) { - LogRecord record = new LogRecord(level, msg); - if( !classAndMethodFound ) { - getClassAndMethod(); - } - record.setSourceClassName(sourceClassName); - record.setSourceMethodName(sourceMethodName); - if( ex != null ) { - record.setThrown(ex); - } - getLogger().log(record); - } - } - - /** - * Gets the class and method by looking at the stack trace for the - * first entry that is not this class. - */ - private void getClassAndMethod() { - try { - Throwable throwable = new Throwable(); - throwable.fillInStackTrace(); - StringWriter stringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter( stringWriter ); - throwable.printStackTrace( printWriter ); - String traceString = stringWriter.getBuffer().toString(); - StringTokenizer tokenizer = - new StringTokenizer( traceString, "\n" ); - tokenizer.nextToken(); - String line = tokenizer.nextToken(); - while ( line.indexOf( this.getClass().getName() ) == -1 ) { - line = tokenizer.nextToken(); - } - while ( line.indexOf( this.getClass().getName() ) >= 0 ) { - line = tokenizer.nextToken(); - } - int start = line.indexOf( "at " ) + 3; - int end = line.indexOf( '(' ); - String temp = line.substring( start, end ); - int lastPeriod = temp.lastIndexOf( '.' ); - sourceClassName = temp.substring( 0, lastPeriod ); - sourceMethodName = temp.substring( lastPeriod + 1 ); - } catch ( Exception ex ) { - // ignore - leave class and methodname unknown - } - classAndMethodFound = true; - } - - /** - * Logs a message with java.util.logging.Level.FINE. - * - * @param message to log - * @see org.apache.commons.logging.Log#debug(Object) - */ - public void debug(Object message) { - log(Level.FINE, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.FINE. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public void debug(Object message, Throwable exception) { - log(Level.FINE, String.valueOf(message), exception); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public void error(Object message) { - log(Level.SEVERE, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public void error(Object message, Throwable exception) { - log(Level.SEVERE, String.valueOf(message), exception); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public void fatal(Object message) { - log(Level.SEVERE, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public void fatal(Object message, Throwable exception) { - log(Level.SEVERE, String.valueOf(message), exception); - } - - /** - * Return the native Logger instance we are using. - */ - public Logger getLogger() { - if (logger == null) { - logger = Logger.getLogger(name); - } - return logger; - } - - /** - * Logs a message with java.util.logging.Level.INFO. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public void info(Object message) { - log(Level.INFO, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.INFO. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public void info(Object message, Throwable exception) { - log(Level.INFO, String.valueOf(message), exception); - } - - /** - * Is debug logging currently enabled? - */ - public boolean isDebugEnabled() { - return getLogger().isLoggable(Level.FINE); - } - - /** - * Is error logging currently enabled? - */ - public boolean isErrorEnabled() { - return getLogger().isLoggable(Level.SEVERE); - } - - /** - * Is fatal logging currently enabled? - */ - public boolean isFatalEnabled() { - return getLogger().isLoggable(Level.SEVERE); - } - - /** - * Is info logging currently enabled? - */ - public boolean isInfoEnabled() { - return getLogger().isLoggable(Level.INFO); - } - - /** - * Is trace logging currently enabled? - */ - public boolean isTraceEnabled() { - return getLogger().isLoggable(Level.FINEST); - } - - /** - * Is warn logging currently enabled? - */ - public boolean isWarnEnabled() { - return getLogger().isLoggable(Level.WARNING); - } - - /** - * Logs a message with java.util.logging.Level.FINEST. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public void trace(Object message) { - log(Level.FINEST, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.FINEST. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public void trace(Object message, Throwable exception) { - log(Level.FINEST, String.valueOf(message), exception); - } - - /** - * Logs a message with java.util.logging.Level.WARNING. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public void warn(Object message) { - log(Level.WARNING, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.WARNING. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public void warn(Object message, Throwable exception) { - log(Level.WARNING, String.valueOf(message), exception); - } -} diff --git a/src/org/apache/commons/logging/impl/Jdk14Logger.java b/src/org/apache/commons/logging/impl/Jdk14Logger.java deleted file mode 100644 index 7a19acbe256..00000000000 --- a/src/org/apache/commons/logging/impl/Jdk14Logger.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.io.Serializable; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.apache.commons.logging.Log; - -/** - * Implementation of the org.apache.commons.logging.Log - * interface that wraps the standard JDK logging mechanisms that were - * introduced in the Merlin release (JDK 1.4). - * - * @version $Id: Jdk14Logger.java 1448063 2013-02-20 10:01:41Z tn $ - */ -public class Jdk14Logger implements Log, Serializable { - - /** Serializable version identifier. */ - private static final long serialVersionUID = 4784713551416303804L; - - /** - * This member variable simply ensures that any attempt to initialise - * this class in a pre-1.4 JVM will result in an ExceptionInInitializerError. - * It must not be private, as an optimising compiler could detect that it - * is not used and optimise it away. - */ - protected static final Level dummyLevel = Level.FINE; - - // ----------------------------------------------------------- Constructors - - /** - * Construct a named instance of this Logger. - * - * @param name Name of the logger to be constructed - */ - public Jdk14Logger(String name) { - this.name = name; - logger = getLogger(); - } - - // ----------------------------------------------------- Instance Variables - - /** - * The underlying Logger implementation we are using. - */ - protected transient Logger logger = null; - - /** - * The name of the logger we are wrapping. - */ - protected String name = null; - - // --------------------------------------------------------- Protected Methods - - protected void log( Level level, String msg, Throwable ex ) { - Logger logger = getLogger(); - if (logger.isLoggable(level)) { - // Hack (?) to get the stack trace. - Throwable dummyException = new Throwable(); - StackTraceElement locations[] = dummyException.getStackTrace(); - // LOGGING-132: use the provided logger name instead of the class name - String cname = name; - String method = "unknown"; - // Caller will be the third element - if( locations != null && locations.length > 2 ) { - StackTraceElement caller = locations[2]; - method = caller.getMethodName(); - } - if( ex == null ) { - logger.logp( level, cname, method, msg ); - } else { - logger.logp( level, cname, method, msg, ex ); - } - } - } - - // --------------------------------------------------------- Public Methods - - /** - * Logs a message with java.util.logging.Level.FINE. - * - * @param message to log - * @see org.apache.commons.logging.Log#debug(Object) - */ - public void debug(Object message) { - log(Level.FINE, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.FINE. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public void debug(Object message, Throwable exception) { - log(Level.FINE, String.valueOf(message), exception); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public void error(Object message) { - log(Level.SEVERE, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public void error(Object message, Throwable exception) { - log(Level.SEVERE, String.valueOf(message), exception); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public void fatal(Object message) { - log(Level.SEVERE, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.SEVERE. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public void fatal(Object message, Throwable exception) { - log(Level.SEVERE, String.valueOf(message), exception); - } - - /** - * Return the native Logger instance we are using. - */ - public Logger getLogger() { - if (logger == null) { - logger = Logger.getLogger(name); - } - return logger; - } - - /** - * Logs a message with java.util.logging.Level.INFO. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public void info(Object message) { - log(Level.INFO, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.INFO. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public void info(Object message, Throwable exception) { - log(Level.INFO, String.valueOf(message), exception); - } - - /** - * Is debug logging currently enabled? - */ - public boolean isDebugEnabled() { - return getLogger().isLoggable(Level.FINE); - } - - /** - * Is error logging currently enabled? - */ - public boolean isErrorEnabled() { - return getLogger().isLoggable(Level.SEVERE); - } - - /** - * Is fatal logging currently enabled? - */ - public boolean isFatalEnabled() { - return getLogger().isLoggable(Level.SEVERE); - } - - /** - * Is info logging currently enabled? - */ - public boolean isInfoEnabled() { - return getLogger().isLoggable(Level.INFO); - } - - /** - * Is trace logging currently enabled? - */ - public boolean isTraceEnabled() { - return getLogger().isLoggable(Level.FINEST); - } - - /** - * Is warn logging currently enabled? - */ - public boolean isWarnEnabled() { - return getLogger().isLoggable(Level.WARNING); - } - - /** - * Logs a message with java.util.logging.Level.FINEST. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public void trace(Object message) { - log(Level.FINEST, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.FINEST. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public void trace(Object message, Throwable exception) { - log(Level.FINEST, String.valueOf(message), exception); - } - - /** - * Logs a message with java.util.logging.Level.WARNING. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public void warn(Object message) { - log(Level.WARNING, String.valueOf(message), null); - } - - /** - * Logs a message with java.util.logging.Level.WARNING. - * - * @param message to log - * @param exception log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public void warn(Object message, Throwable exception) { - log(Level.WARNING, String.valueOf(message), exception); - } -} diff --git a/src/org/apache/commons/logging/impl/Log4JLogger.java b/src/org/apache/commons/logging/impl/Log4JLogger.java deleted file mode 100644 index de3b140dd7e..00000000000 --- a/src/org/apache/commons/logging/impl/Log4JLogger.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.io.Serializable; -import org.apache.commons.logging.Log; -import org.apache.log4j.Logger; -import org.apache.log4j.Priority; -import org.apache.log4j.Level; - -/** - * Implementation of {@link Log} that maps directly to a - * Logger for log4J version 1.2. - *

- * Initial configuration of the corresponding Logger instances should be done - * in the usual manner, as outlined in the Log4J documentation. - *

- * The reason this logger is distinct from the 1.3 logger is that in version 1.2 - * of Log4J: - *

    - *
  • class Logger takes Priority parameters not Level parameters. - *
  • class Level extends Priority - *
- * Log4J1.3 is expected to change Level so it no longer extends Priority, which is - * a non-binary-compatible change. The class generated by compiling this code against - * log4j 1.2 will therefore not run against log4j 1.3. - * - * @version $Id: Log4JLogger.java 1448119 2013-02-20 12:28:04Z tn $ - */ -public class Log4JLogger implements Log, Serializable { - - /** Serializable version identifier. */ - private static final long serialVersionUID = 5160705895411730424L; - - // ------------------------------------------------------------- Attributes - - /** The fully qualified name of the Log4JLogger class. */ - private static final String FQCN = Log4JLogger.class.getName(); - - /** Log to this logger */ - private transient volatile Logger logger = null; - - /** Logger name */ - private final String name; - - private static final Priority traceLevel; - - // ------------------------------------------------------------ - // Static Initializer. - // - // Note that this must come after the static variable declarations - // otherwise initialiser expressions associated with those variables - // will override any settings done here. - // - // Verify that log4j is available, and that it is version 1.2. - // If an ExceptionInInitializerError is generated, then LogFactoryImpl - // will treat that as meaning that the appropriate underlying logging - // library is just not present - if discovery is in progress then - // discovery will continue. - // ------------------------------------------------------------ - - static { - if (!Priority.class.isAssignableFrom(Level.class)) { - // nope, this is log4j 1.3, so force an ExceptionInInitializerError - throw new InstantiationError("Log4J 1.2 not available"); - } - - // Releases of log4j1.2 >= 1.2.12 have Priority.TRACE available, earlier - // versions do not. If TRACE is not available, then we have to map - // calls to Log.trace(...) onto the DEBUG level. - - Priority _traceLevel; - try { - _traceLevel = (Priority) Level.class.getDeclaredField("TRACE").get(null); - } catch(Exception ex) { - // ok, trace not available - _traceLevel = Level.DEBUG; - } - traceLevel = _traceLevel; - } - - // ------------------------------------------------------------ Constructor - - public Log4JLogger() { - name = null; - } - - /** - * Base constructor. - */ - public Log4JLogger(String name) { - this.name = name; - this.logger = getLogger(); - } - - /** - * For use with a log4j factory. - */ - public Log4JLogger(Logger logger) { - if (logger == null) { - throw new IllegalArgumentException( - "Warning - null logger in constructor; possible log4j misconfiguration."); - } - this.name = logger.getName(); - this.logger = logger; - } - - /** - * Logs a message with org.apache.log4j.Priority.TRACE. - * When using a log4j version that does not support the TRACE - * level, the message will be logged at the DEBUG level. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public void trace(Object message) { - getLogger().log(FQCN, traceLevel, message, null); - } - - /** - * Logs a message with org.apache.log4j.Priority.TRACE. - * When using a log4j version that does not support the TRACE - * level, the message will be logged at the DEBUG level. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public void trace(Object message, Throwable t) { - getLogger().log(FQCN, traceLevel, message, t); - } - - /** - * Logs a message with org.apache.log4j.Priority.DEBUG. - * - * @param message to log - * @see org.apache.commons.logging.Log#debug(Object) - */ - public void debug(Object message) { - getLogger().log(FQCN, Level.DEBUG, message, null); - } - - /** - * Logs a message with org.apache.log4j.Priority.DEBUG. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public void debug(Object message, Throwable t) { - getLogger().log(FQCN, Level.DEBUG, message, t); - } - - /** - * Logs a message with org.apache.log4j.Priority.INFO. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public void info(Object message) { - getLogger().log(FQCN, Level.INFO, message, null); - } - - /** - * Logs a message with org.apache.log4j.Priority.INFO. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public void info(Object message, Throwable t) { - getLogger().log(FQCN, Level.INFO, message, t); - } - - /** - * Logs a message with org.apache.log4j.Priority.WARN. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public void warn(Object message) { - getLogger().log(FQCN, Level.WARN, message, null); - } - - /** - * Logs a message with org.apache.log4j.Priority.WARN. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public void warn(Object message, Throwable t) { - getLogger().log(FQCN, Level.WARN, message, t); - } - - /** - * Logs a message with org.apache.log4j.Priority.ERROR. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public void error(Object message) { - getLogger().log(FQCN, Level.ERROR, message, null); - } - - /** - * Logs a message with org.apache.log4j.Priority.ERROR. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public void error(Object message, Throwable t) { - getLogger().log(FQCN, Level.ERROR, message, t); - } - - /** - * Logs a message with org.apache.log4j.Priority.FATAL. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public void fatal(Object message) { - getLogger().log(FQCN, Level.FATAL, message, null); - } - - /** - * Logs a message with org.apache.log4j.Priority.FATAL. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public void fatal(Object message, Throwable t) { - getLogger().log(FQCN, Level.FATAL, message, t); - } - - /** - * Return the native Logger instance we are using. - */ - public Logger getLogger() { - Logger result = logger; - if (result == null) { - synchronized(this) { - result = logger; - if (result == null) { - logger = result = Logger.getLogger(name); - } - } - } - return result; - } - - /** - * Check whether the Log4j Logger used is enabled for DEBUG priority. - */ - public boolean isDebugEnabled() { - return getLogger().isDebugEnabled(); - } - - /** - * Check whether the Log4j Logger used is enabled for ERROR priority. - */ - public boolean isErrorEnabled() { - return getLogger().isEnabledFor(Level.ERROR); - } - - /** - * Check whether the Log4j Logger used is enabled for FATAL priority. - */ - public boolean isFatalEnabled() { - return getLogger().isEnabledFor(Level.FATAL); - } - - /** - * Check whether the Log4j Logger used is enabled for INFO priority. - */ - public boolean isInfoEnabled() { - return getLogger().isInfoEnabled(); - } - - /** - * Check whether the Log4j Logger used is enabled for TRACE priority. - * When using a log4j version that does not support the TRACE level, this call - * will report whether DEBUG is enabled or not. - */ - public boolean isTraceEnabled() { - return getLogger().isEnabledFor(traceLevel); - } - - /** - * Check whether the Log4j Logger used is enabled for WARN priority. - */ - public boolean isWarnEnabled() { - return getLogger().isEnabledFor(Level.WARN); - } -} diff --git a/src/org/apache/commons/logging/impl/LogFactoryImpl.java b/src/org/apache/commons/logging/impl/LogFactoryImpl.java deleted file mode 100644 index f893883b2cc..00000000000 --- a/src/org/apache/commons/logging/impl/LogFactoryImpl.java +++ /dev/null @@ -1,1393 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Hashtable; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogConfigurationException; -import org.apache.commons.logging.LogFactory; - -/** - * Concrete subclass of {@link LogFactory} that implements the - * following algorithm to dynamically select a logging implementation - * class to instantiate a wrapper for: - *
    - *
  • Use a factory configuration attribute named - * org.apache.commons.logging.Log to identify the - * requested implementation class.
  • - *
  • Use the org.apache.commons.logging.Log system property - * to identify the requested implementation class.
  • - *
  • If Log4J is available, return an instance of - * org.apache.commons.logging.impl.Log4JLogger.
  • - *
  • If JDK 1.4 or later is available, return an instance of - * org.apache.commons.logging.impl.Jdk14Logger.
  • - *
  • Otherwise, return an instance of - * org.apache.commons.logging.impl.SimpleLog.
  • - *
- *

- * If the selected {@link Log} implementation class has a - * setLogFactory() method that accepts a {@link LogFactory} - * parameter, this method will be called on each newly created instance - * to identify the associated factory. This makes factory configuration - * attributes available to the Log instance, if it so desires. - *

- * This factory will remember previously created Log instances - * for the same name, and will return them on repeated requests to the - * getInstance() method. - * - * @version $Id: LogFactoryImpl.java 1747117 2016-06-07 02:19:52Z ggregory $ - */ -public class LogFactoryImpl extends LogFactory { - - /** Log4JLogger class name */ - private static final String LOGGING_IMPL_LOG4J_LOGGER = "org.apache.commons.logging.impl.Log4JLogger"; - /** Jdk14Logger class name */ - private static final String LOGGING_IMPL_JDK14_LOGGER = "org.apache.commons.logging.impl.Jdk14Logger"; - /** Jdk13LumberjackLogger class name */ - private static final String LOGGING_IMPL_LUMBERJACK_LOGGER = - "org.apache.commons.logging.impl.Jdk13LumberjackLogger"; - - /** SimpleLog class name */ - private static final String LOGGING_IMPL_SIMPLE_LOGGER = "org.apache.commons.logging.impl.SimpleLog"; - - private static final String PKG_IMPL="org.apache.commons.logging.impl."; - private static final int PKG_LEN = PKG_IMPL.length(); - - // ----------------------------------------------------------- Constructors - - /** - * Public no-arguments constructor required by the lookup mechanism. - */ - public LogFactoryImpl() { - super(); - initDiagnostics(); // method on this object - if (isDiagnosticsEnabled()) { - logDiagnostic("Instance created."); - } - } - - // ----------------------------------------------------- Manifest Constants - - /** - * The name (org.apache.commons.logging.Log) of the system - * property identifying our {@link Log} implementation class. - */ - public static final String LOG_PROPERTY = "org.apache.commons.logging.Log"; - - /** - * The deprecated system property used for backwards compatibility with - * old versions of JCL. - */ - protected static final String LOG_PROPERTY_OLD = "org.apache.commons.logging.log"; - - /** - * The name (org.apache.commons.logging.Log.allowFlawedContext) - * of the system property which can be set true/false to - * determine system behaviour when a bad context-classloader is encountered. - * When set to false, a LogConfigurationException is thrown if - * LogFactoryImpl is loaded via a child classloader of the TCCL (this - * should never happen in sane systems). - * - * Default behaviour: true (tolerates bad context classloaders) - * - * See also method setAttribute. - */ - public static final String ALLOW_FLAWED_CONTEXT_PROPERTY = - "org.apache.commons.logging.Log.allowFlawedContext"; - - /** - * The name (org.apache.commons.logging.Log.allowFlawedDiscovery) - * of the system property which can be set true/false to - * determine system behaviour when a bad logging adapter class is - * encountered during logging discovery. When set to false, an - * exception will be thrown and the app will fail to start. When set - * to true, discovery will continue (though the user might end up - * with a different logging implementation than they expected). - *

- * Default behaviour: true (tolerates bad logging adapters) - * - * See also method setAttribute. - */ - public static final String ALLOW_FLAWED_DISCOVERY_PROPERTY = - "org.apache.commons.logging.Log.allowFlawedDiscovery"; - - /** - * The name (org.apache.commons.logging.Log.allowFlawedHierarchy) - * of the system property which can be set true/false to - * determine system behaviour when a logging adapter class is - * encountered which has bound to the wrong Log class implementation. - * When set to false, an exception will be thrown and the app will fail - * to start. When set to true, discovery will continue (though the user - * might end up with a different logging implementation than they expected). - *

- * Default behaviour: true (tolerates bad Log class hierarchy) - * - * See also method setAttribute. - */ - public static final String ALLOW_FLAWED_HIERARCHY_PROPERTY = - "org.apache.commons.logging.Log.allowFlawedHierarchy"; - - /** - * The names of classes that will be tried (in order) as logging - * adapters. Each class is expected to implement the Log interface, - * and to throw NoClassDefFound or ExceptionInInitializerError when - * loaded if the underlying logging library is not available. Any - * other error indicates that the underlying logging library is available - * but broken/unusable for some reason. - */ - private static final String[] classesToDiscover = { - LOGGING_IMPL_LOG4J_LOGGER, - "org.apache.commons.logging.impl.Jdk14Logger", - "org.apache.commons.logging.impl.Jdk13LumberjackLogger", - "org.apache.commons.logging.impl.SimpleLog" - }; - - // ----------------------------------------------------- Instance Variables - - /** - * Determines whether logging classes should be loaded using the thread-context - * classloader, or via the classloader that loaded this LogFactoryImpl class. - */ - private boolean useTCCL = true; - - /** - * The string prefixed to every message output by the logDiagnostic method. - */ - private String diagnosticPrefix; - - /** - * Configuration attributes. - */ - protected Hashtable attributes = new Hashtable(); - - /** - * The {@link org.apache.commons.logging.Log} instances that have - * already been created, keyed by logger name. - */ - protected Hashtable instances = new Hashtable(); - - /** - * Name of the class implementing the Log interface. - */ - private String logClassName; - - /** - * The one-argument constructor of the - * {@link org.apache.commons.logging.Log} - * implementation class that will be used to create new instances. - * This value is initialized by getLogConstructor(), - * and then returned repeatedly. - */ - protected Constructor logConstructor = null; - - /** - * The signature of the Constructor to be used. - */ - protected Class logConstructorSignature[] = { java.lang.String.class }; - - /** - * The one-argument setLogFactory method of the selected - * {@link org.apache.commons.logging.Log} method, if it exists. - */ - protected Method logMethod = null; - - /** - * The signature of the setLogFactory method to be used. - */ - protected Class logMethodSignature[] = { LogFactory.class }; - - /** - * See getBaseClassLoader and initConfiguration. - */ - private boolean allowFlawedContext; - - /** - * See handleFlawedDiscovery and initConfiguration. - */ - private boolean allowFlawedDiscovery; - - /** - * See handleFlawedHierarchy and initConfiguration. - */ - private boolean allowFlawedHierarchy; - - // --------------------------------------------------------- Public Methods - - /** - * Return the configuration attribute with the specified name (if any), - * or null if there is no such attribute. - * - * @param name Name of the attribute to return - */ - public Object getAttribute(String name) { - return attributes.get(name); - } - - /** - * Return an array containing the names of all currently defined - * configuration attributes. If there are no such attributes, a zero - * length array is returned. - */ - public String[] getAttributeNames() { - return (String[]) attributes.keySet().toArray(new String[attributes.size()]); - } - - /** - * Convenience method to derive a name from the specified class and - * call getInstance(String) with it. - * - * @param clazz Class for which a suitable Log name will be derived - * - * @throws LogConfigurationException if a suitable Log - * instance cannot be returned - */ - public Log getInstance(Class clazz) throws LogConfigurationException { - return getInstance(clazz.getName()); - } - - /** - *

Construct (if necessary) and return a Log instance, - * using the factory's current set of configuration attributes.

- * - *

NOTE - Depending upon the implementation of - * the LogFactory you are using, the Log - * instance you are returned may or may not be local to the current - * application, and may or may not be returned again on a subsequent - * call with the same name argument.

- * - * @param name Logical name of the Log instance to be - * returned (the meaning of this name is only known to the underlying - * logging implementation that is being wrapped) - * - * @throws LogConfigurationException if a suitable Log - * instance cannot be returned - */ - public Log getInstance(String name) throws LogConfigurationException { - Log instance = (Log) instances.get(name); - if (instance == null) { - instance = newInstance(name); - instances.put(name, instance); - } - return instance; - } - - /** - * Release any internal references to previously created - * {@link org.apache.commons.logging.Log} - * instances returned by this factory. This is useful in environments - * like servlet containers, which implement application reloading by - * throwing away a ClassLoader. Dangling references to objects in that - * class loader would prevent garbage collection. - */ - public void release() { - - logDiagnostic("Releasing all known loggers"); - instances.clear(); - } - - /** - * Remove any configuration attribute associated with the specified name. - * If there is no such attribute, no action is taken. - * - * @param name Name of the attribute to remove - */ - public void removeAttribute(String name) { - attributes.remove(name); - } - - /** - * Set the configuration attribute with the specified name. Calling - * this with a null value is equivalent to calling - * removeAttribute(name). - *

- * This method can be used to set logging configuration programmatically - * rather than via system properties. It can also be used in code running - * within a container (such as a webapp) to configure behaviour on a - * per-component level instead of globally as system properties would do. - * To use this method instead of a system property, call - *

-     * LogFactory.getFactory().setAttribute(...)
-     * 
- * This must be done before the first Log object is created; configuration - * changes after that point will be ignored. - *

- * This method is also called automatically if LogFactory detects a - * commons-logging.properties file; every entry in that file is set - * automatically as an attribute here. - * - * @param name Name of the attribute to set - * @param value Value of the attribute to set, or null - * to remove any setting for this attribute - */ - public void setAttribute(String name, Object value) { - if (logConstructor != null) { - logDiagnostic("setAttribute: call too late; configuration already performed."); - } - - if (value == null) { - attributes.remove(name); - } else { - attributes.put(name, value); - } - - if (name.equals(TCCL_KEY)) { - useTCCL = value != null && Boolean.valueOf(value.toString()).booleanValue(); - } - } - - // ------------------------------------------------------ - // Static Methods - // - // These methods only defined as workarounds for a java 1.2 bug; - // theoretically none of these are needed. - // ------------------------------------------------------ - - /** - * Gets the context classloader. - * This method is a workaround for a java 1.2 compiler bug. - * @since 1.1 - */ - protected static ClassLoader getContextClassLoader() throws LogConfigurationException { - return LogFactory.getContextClassLoader(); - } - - /** - * Workaround for bug in Java1.2; in theory this method is not needed. - * See LogFactory.isDiagnosticsEnabled. - */ - protected static boolean isDiagnosticsEnabled() { - return LogFactory.isDiagnosticsEnabled(); - } - - /** - * Workaround for bug in Java1.2; in theory this method is not needed. - * See LogFactory.getClassLoader. - * @since 1.1 - */ - protected static ClassLoader getClassLoader(Class clazz) { - return LogFactory.getClassLoader(clazz); - } - - // ------------------------------------------------------ Protected Methods - - /** - * Calculate and cache a string that uniquely identifies this instance, - * including which classloader the object was loaded from. - *

- * This string will later be prefixed to each "internal logging" message - * emitted, so that users can clearly see any unexpected behaviour. - *

- * Note that this method does not detect whether internal logging is - * enabled or not, nor where to output stuff if it is; that is all - * handled by the parent LogFactory class. This method just computes - * its own unique prefix for log messages. - */ - private void initDiagnostics() { - // It would be nice to include an identifier of the context classloader - // that this LogFactoryImpl object is responsible for. However that - // isn't possible as that information isn't available. It is possible - // to figure this out by looking at the logging from LogFactory to - // see the context & impl ids from when this object was instantiated, - // in order to link the impl id output as this object's prefix back to - // the context it is intended to manage. - // Note that this prefix should be kept consistent with that - // in LogFactory. - Class clazz = this.getClass(); - ClassLoader classLoader = getClassLoader(clazz); - String classLoaderName; - try { - if (classLoader == null) { - classLoaderName = "BOOTLOADER"; - } else { - classLoaderName = objectId(classLoader); - } - } catch (SecurityException e) { - classLoaderName = "UNKNOWN"; - } - diagnosticPrefix = "[LogFactoryImpl@" + System.identityHashCode(this) + " from " + classLoaderName + "] "; - } - - /** - * Output a diagnostic message to a user-specified destination (if the - * user has enabled diagnostic logging). - * - * @param msg diagnostic message - * @since 1.1 - */ - protected void logDiagnostic(String msg) { - if (isDiagnosticsEnabled()) { - logRawDiagnostic(diagnosticPrefix + msg); - } - } - - /** - * Return the fully qualified Java classname of the {@link Log} - * implementation we will be using. - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected String getLogClassName() { - if (logClassName == null) { - discoverLogImplementation(getClass().getName()); - } - - return logClassName; - } - - - /** - *

Return the Constructor that can be called to instantiate - * new {@link org.apache.commons.logging.Log} instances.

- * - *

IMPLEMENTATION NOTE - Race conditions caused by - * calling this method from more than one thread are ignored, because - * the same Constructor instance will ultimately be derived - * in all circumstances.

- * - * @throws LogConfigurationException if a suitable constructor - * cannot be returned - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected Constructor getLogConstructor() - throws LogConfigurationException { - - // Return the previously identified Constructor (if any) - if (logConstructor == null) { - discoverLogImplementation(getClass().getName()); - } - - return logConstructor; - } - - /** - * Is JDK 1.3 with Lumberjack logging available? - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected boolean isJdk13LumberjackAvailable() { - return isLogLibraryAvailable( - "Jdk13Lumberjack", - "org.apache.commons.logging.impl.Jdk13LumberjackLogger"); - } - - /** - * Return true if JDK 1.4 or later logging - * is available. Also checks that the Throwable class - * supports getStackTrace(), which is required by - * Jdk14Logger. - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected boolean isJdk14Available() { - return isLogLibraryAvailable( - "Jdk14", - "org.apache.commons.logging.impl.Jdk14Logger"); - } - - /** - * Is a Log4J implementation available? - * - * @deprecated Never invoked by this class; subclasses should not assume - * it will be. - */ - protected boolean isLog4JAvailable() { - return isLogLibraryAvailable( - "Log4J", - LOGGING_IMPL_LOG4J_LOGGER); - } - - /** - * Create and return a new {@link org.apache.commons.logging.Log} - * instance for the specified name. - * - * @param name Name of the new logger - * - * @throws LogConfigurationException if a new instance cannot - * be created - */ - protected Log newInstance(String name) throws LogConfigurationException { - Log instance; - try { - if (logConstructor == null) { - instance = discoverLogImplementation(name); - } - else { - Object params[] = { name }; - instance = (Log) logConstructor.newInstance(params); - } - - if (logMethod != null) { - Object params[] = { this }; - logMethod.invoke(instance, params); - } - - return instance; - - } catch (LogConfigurationException lce) { - - // this type of exception means there was a problem in discovery - // and we've already output diagnostics about the issue, etc.; - // just pass it on - throw lce; - - } catch (InvocationTargetException e) { - // A problem occurred invoking the Constructor or Method - // previously discovered - Throwable c = e.getTargetException(); - throw new LogConfigurationException(c == null ? e : c); - } catch (Throwable t) { - handleThrowable(t); // may re-throw t - // A problem occurred invoking the Constructor or Method - // previously discovered - throw new LogConfigurationException(t); - } - } - - // ------------------------------------------------------ Private Methods - - /** - * Calls LogFactory.directGetContextClassLoader under the control of an - * AccessController class. This means that java code running under a - * security manager that forbids access to ClassLoaders will still work - * if this class is given appropriate privileges, even when the caller - * doesn't have such privileges. Without using an AccessController, the - * the entire call stack must have the privilege before the call is - * allowed. - * - * @return the context classloader associated with the current thread, - * or null if security doesn't allow it. - * - * @throws LogConfigurationException if there was some weird error while - * attempting to get the context classloader. - * - * @throws SecurityException if the current java security policy doesn't - * allow this class to access the context classloader. - */ - private static ClassLoader getContextClassLoaderInternal() - throws LogConfigurationException { - return (ClassLoader)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return LogFactory.directGetContextClassLoader(); - } - }); - } - - /** - * Read the specified system property, using an AccessController so that - * the property can be read if JCL has been granted the appropriate - * security rights even if the calling code has not. - *

- * Take care not to expose the value returned by this method to the - * calling application in any way; otherwise the calling app can use that - * info to access data that should not be available to it. - */ - private static String getSystemProperty(final String key, final String def) - throws SecurityException { - return (String) AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return System.getProperty(key, def); - } - }); - } - - /** - * Fetch the parent classloader of a specified classloader. - *

- * If a SecurityException occurs, null is returned. - *

- * Note that this method is non-static merely so logDiagnostic is available. - */ - private ClassLoader getParentClassLoader(final ClassLoader cl) { - try { - return (ClassLoader)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - return cl.getParent(); - } - }); - } catch (SecurityException ex) { - logDiagnostic("[SECURITY] Unable to obtain parent classloader"); - return null; - } - - } - - /** - * Utility method to check whether a particular logging library is - * present and available for use. Note that this does not - * affect the future behaviour of this class. - */ - private boolean isLogLibraryAvailable(String name, String classname) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Checking for '" + name + "'."); - } - try { - Log log = createLogFromClass( - classname, - this.getClass().getName(), // dummy category - false); - - if (log == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Did not find '" + name + "'."); - } - return false; - } else { - if (isDiagnosticsEnabled()) { - logDiagnostic("Found '" + name + "'."); - } - return true; - } - } catch (LogConfigurationException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Logging system '" + name + "' is available but not useable."); - } - return false; - } - } - - /** - * Attempt to find an attribute (see method setAttribute) or a - * system property with the provided name and return its value. - *

- * The attributes associated with this object are checked before - * system properties in case someone has explicitly called setAttribute, - * or a configuration property has been set in a commons-logging.properties - * file. - * - * @return the value associated with the property, or null. - */ - private String getConfigurationValue(String property) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Trying to get configuration for item " + property); - } - - Object valueObj = getAttribute(property); - if (valueObj != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Found LogFactory attribute [" + valueObj + "] for " + property); - } - return valueObj.toString(); - } - - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] No LogFactory attribute found for " + property); - } - - try { - // warning: minor security hole here, in that we potentially read a system - // property that the caller cannot, then output it in readable form as a - // diagnostic message. However it's only ever JCL-specific properties - // involved here, so the harm is truly trivial. - String value = getSystemProperty(property, null); - if (value != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Found system property [" + value + "] for " + property); - } - return value; - } - - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] No system property found for property " + property); - } - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] Security prevented reading system property " + property); - } - } - - if (isDiagnosticsEnabled()) { - logDiagnostic("[ENV] No configuration defined for item " + property); - } - - return null; - } - - /** - * Get the setting for the user-configurable behaviour specified by key. - * If nothing has explicitly been set, then return dflt. - */ - private boolean getBooleanConfiguration(String key, boolean dflt) { - String val = getConfigurationValue(key); - if (val == null) { - return dflt; - } - return Boolean.valueOf(val).booleanValue(); - } - - /** - * Initialize a number of variables that control the behaviour of this - * class and that can be tweaked by the user. This is done when the first - * logger is created, not in the constructor of this class, because we - * need to give the user a chance to call method setAttribute in order to - * configure this object. - */ - private void initConfiguration() { - allowFlawedContext = getBooleanConfiguration(ALLOW_FLAWED_CONTEXT_PROPERTY, true); - allowFlawedDiscovery = getBooleanConfiguration(ALLOW_FLAWED_DISCOVERY_PROPERTY, true); - allowFlawedHierarchy = getBooleanConfiguration(ALLOW_FLAWED_HIERARCHY_PROPERTY, true); - } - - /** - * Attempts to create a Log instance for the given category name. - * Follows the discovery process described in the class javadoc. - * - * @param logCategory the name of the log category - * - * @throws LogConfigurationException if an error in discovery occurs, - * or if no adapter at all can be instantiated - */ - private Log discoverLogImplementation(String logCategory) - throws LogConfigurationException { - if (isDiagnosticsEnabled()) { - logDiagnostic("Discovering a Log implementation..."); - } - - initConfiguration(); - - Log result = null; - - // See if the user specified the Log implementation to use - String specifiedLogClassName = findUserSpecifiedLogClassName(); - - if (specifiedLogClassName != null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Attempting to load user-specified log class '" + - specifiedLogClassName + "'..."); - } - - result = createLogFromClass(specifiedLogClassName, - logCategory, - true); - if (result == null) { - StringBuffer messageBuffer = new StringBuffer("User-specified log class '"); - messageBuffer.append(specifiedLogClassName); - messageBuffer.append("' cannot be found or is not useable."); - - // Mistyping or misspelling names is a common fault. - // Construct a good error message, if we can - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER); - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER); - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER); - informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER); - throw new LogConfigurationException(messageBuffer.toString()); - } - - return result; - } - - // No user specified log; try to discover what's on the classpath - // - // Note that we deliberately loop here over classesToDiscover and - // expect method createLogFromClass to loop over the possible source - // classloaders. The effect is: - // for each discoverable log adapter - // for each possible classloader - // see if it works - // - // It appears reasonable at first glance to do the opposite: - // for each possible classloader - // for each discoverable log adapter - // see if it works - // - // The latter certainly has advantages for user-installable logging - // libraries such as log4j; in a webapp for example this code should - // first check whether the user has provided any of the possible - // logging libraries before looking in the parent classloader. - // Unfortunately, however, Jdk14Logger will always work in jvm>=1.4, - // and SimpleLog will always work in any JVM. So the loop would never - // ever look for logging libraries in the parent classpath. Yet many - // users would expect that putting log4j there would cause it to be - // detected (and this is the historical JCL behaviour). So we go with - // the first approach. A user that has bundled a specific logging lib - // in a webapp should use a commons-logging.properties file or a - // service file in META-INF to force use of that logging lib anyway, - // rather than relying on discovery. - - if (isDiagnosticsEnabled()) { - logDiagnostic( - "No user-specified Log implementation; performing discovery" + - " using the standard supported logging implementations..."); - } - for(int i=0; iStringBuffer the message should be appended to, - * not null - * @param name the (trimmed) name to be test against the candidate, not null - * @param candidate the candidate name (not null) - */ - private void informUponSimilarName(final StringBuffer messageBuffer, final String name, - final String candidate) { - if (name.equals(candidate)) { - // Don't suggest a name that is exactly the same as the one the - // user tried... - return; - } - - // If the user provides a name that is in the right package, and gets - // the first 5 characters of the adapter class right (ignoring case), - // then suggest the candidate adapter class name. - if (name.regionMatches(true, 0, candidate, 0, PKG_LEN + 5)) { - messageBuffer.append(" Did you mean '"); - messageBuffer.append(candidate); - messageBuffer.append("'?"); - } - } - - /** - * Checks system properties and the attribute map for - * a Log implementation specified by the user under the - * property names {@link #LOG_PROPERTY} or {@link #LOG_PROPERTY_OLD}. - * - * @return classname specified by the user, or null - */ - private String findUserSpecifiedLogClassName() { - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from attribute '" + LOG_PROPERTY + "'"); - } - String specifiedClass = (String) getAttribute(LOG_PROPERTY); - - if (specifiedClass == null) { // @deprecated - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from attribute '" + - LOG_PROPERTY_OLD + "'"); - } - specifiedClass = (String) getAttribute(LOG_PROPERTY_OLD); - } - - if (specifiedClass == null) { - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from system property '" + - LOG_PROPERTY + "'"); - } - try { - specifiedClass = getSystemProperty(LOG_PROPERTY, null); - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("No access allowed to system property '" + - LOG_PROPERTY + "' - " + e.getMessage()); - } - } - } - - if (specifiedClass == null) { // @deprecated - if (isDiagnosticsEnabled()) { - logDiagnostic("Trying to get log class from system property '" + - LOG_PROPERTY_OLD + "'"); - } - try { - specifiedClass = getSystemProperty(LOG_PROPERTY_OLD, null); - } catch (SecurityException e) { - if (isDiagnosticsEnabled()) { - logDiagnostic("No access allowed to system property '" + - LOG_PROPERTY_OLD + "' - " + e.getMessage()); - } - } - } - - // Remove any whitespace; it's never valid in a classname so its - // presence just means a user mistake. As we know what they meant, - // we may as well strip the spaces. - if (specifiedClass != null) { - specifiedClass = specifiedClass.trim(); - } - - return specifiedClass; - } - - /** - * Attempts to load the given class, find a suitable constructor, - * and instantiate an instance of Log. - * - * @param logAdapterClassName classname of the Log implementation - * @param logCategory argument to pass to the Log implementation's constructor - * @param affectState true if this object's state should - * be affected by this method call, false otherwise. - * @return an instance of the given class, or null if the logging - * library associated with the specified adapter is not available. - * @throws LogConfigurationException if there was a serious error with - * configuration and the handleFlawedDiscovery method decided this - * problem was fatal. - */ - private Log createLogFromClass(String logAdapterClassName, - String logCategory, - boolean affectState) - throws LogConfigurationException { - - if (isDiagnosticsEnabled()) { - logDiagnostic("Attempting to instantiate '" + logAdapterClassName + "'"); - } - - Object[] params = { logCategory }; - Log logAdapter = null; - Constructor constructor = null; - - Class logAdapterClass = null; - ClassLoader currentCL = getBaseClassLoader(); - - for(;;) { - // Loop through the classloader hierarchy trying to find - // a viable classloader. - logDiagnostic("Trying to load '" + logAdapterClassName + "' from classloader " + objectId(currentCL)); - try { - if (isDiagnosticsEnabled()) { - // Show the location of the first occurrence of the .class file - // in the classpath. This is the location that ClassLoader.loadClass - // will load the class from -- unless the classloader is doing - // something weird. - URL url; - String resourceName = logAdapterClassName.replace('.', '/') + ".class"; - if (currentCL != null) { - url = currentCL.getResource(resourceName ); - } else { - url = ClassLoader.getSystemResource(resourceName + ".class"); - } - - if (url == null) { - logDiagnostic("Class '" + logAdapterClassName + "' [" + resourceName + "] cannot be found."); - } else { - logDiagnostic("Class '" + logAdapterClassName + "' was found at '" + url + "'"); - } - } - - Class c; - try { - c = Class.forName(logAdapterClassName, true, currentCL); - } catch (ClassNotFoundException originalClassNotFoundException) { - // The current classloader was unable to find the log adapter - // in this or any ancestor classloader. There's no point in - // trying higher up in the hierarchy in this case.. - String msg = originalClassNotFoundException.getMessage(); - logDiagnostic("The log adapter '" + logAdapterClassName + "' is not available via classloader " + - objectId(currentCL) + ": " + msg.trim()); - try { - // Try the class classloader. - // This may work in cases where the TCCL - // does not contain the code executed or JCL. - // This behaviour indicates that the application - // classloading strategy is not consistent with the - // Java 1.2 classloading guidelines but JCL can - // and so should handle this case. - c = Class.forName(logAdapterClassName); - } catch (ClassNotFoundException secondaryClassNotFoundException) { - // no point continuing: this adapter isn't available - msg = secondaryClassNotFoundException.getMessage(); - logDiagnostic("The log adapter '" + logAdapterClassName + - "' is not available via the LogFactoryImpl class classloader: " + msg.trim()); - break; - } - } - - constructor = c.getConstructor(logConstructorSignature); - Object o = constructor.newInstance(params); - - // Note that we do this test after trying to create an instance - // [rather than testing Log.class.isAssignableFrom(c)] so that - // we don't complain about Log hierarchy problems when the - // adapter couldn't be instantiated anyway. - if (o instanceof Log) { - logAdapterClass = c; - logAdapter = (Log) o; - break; - } - - // Oops, we have a potential problem here. An adapter class - // has been found and its underlying lib is present too, but - // there are multiple Log interface classes available making it - // impossible to cast to the type the caller wanted. We - // certainly can't use this logger, but we need to know whether - // to keep on discovering or terminate now. - // - // The handleFlawedHierarchy method will throw - // LogConfigurationException if it regards this problem as - // fatal, and just return if not. - handleFlawedHierarchy(currentCL, c); - } catch (NoClassDefFoundError e) { - // We were able to load the adapter but it had references to - // other classes that could not be found. This simply means that - // the underlying logger library is not present in this or any - // ancestor classloader. There's no point in trying higher up - // in the hierarchy in this case.. - String msg = e.getMessage(); - logDiagnostic("The log adapter '" + logAdapterClassName + - "' is missing dependencies when loaded via classloader " + objectId(currentCL) + - ": " + msg.trim()); - break; - } catch (ExceptionInInitializerError e) { - // A static initializer block or the initializer code associated - // with a static variable on the log adapter class has thrown - // an exception. - // - // We treat this as meaning the adapter's underlying logging - // library could not be found. - String msg = e.getMessage(); - logDiagnostic("The log adapter '" + logAdapterClassName + - "' is unable to initialize itself when loaded via classloader " + objectId(currentCL) + - ": " + msg.trim()); - break; - } catch (LogConfigurationException e) { - // call to handleFlawedHierarchy above must have thrown - // a LogConfigurationException, so just throw it on - throw e; - } catch (Throwable t) { - handleThrowable(t); // may re-throw t - // handleFlawedDiscovery will determine whether this is a fatal - // problem or not. If it is fatal, then a LogConfigurationException - // will be thrown. - handleFlawedDiscovery(logAdapterClassName, currentCL, t); - } - - if (currentCL == null) { - break; - } - - // try the parent classloader - // currentCL = currentCL.getParent(); - currentCL = getParentClassLoader(currentCL); - } - - if (logAdapterClass != null && affectState) { - // We've succeeded, so set instance fields - this.logClassName = logAdapterClassName; - this.logConstructor = constructor; - - // Identify the setLogFactory method (if there is one) - try { - this.logMethod = logAdapterClass.getMethod("setLogFactory", logMethodSignature); - logDiagnostic("Found method setLogFactory(LogFactory) in '" + logAdapterClassName + "'"); - } catch (Throwable t) { - handleThrowable(t); // may re-throw t - this.logMethod = null; - logDiagnostic("[INFO] '" + logAdapterClassName + "' from classloader " + objectId(currentCL) + - " does not declare optional method " + "setLogFactory(LogFactory)"); - } - - logDiagnostic("Log adapter '" + logAdapterClassName + "' from classloader " + - objectId(logAdapterClass.getClassLoader()) + " has been selected for use."); - } - - return logAdapter; - } - - /** - * Return the classloader from which we should try to load the logging - * adapter classes. - *

- * This method usually returns the context classloader. However if it - * is discovered that the classloader which loaded this class is a child - * of the context classloader and the allowFlawedContext option - * has been set then the classloader which loaded this class is returned - * instead. - *

- * The only time when the classloader which loaded this class is a - * descendant (rather than the same as or an ancestor of the context - * classloader) is when an app has created custom classloaders but - * failed to correctly set the context classloader. This is a bug in - * the calling application; however we provide the option for JCL to - * simply generate a warning rather than fail outright. - * - */ - private ClassLoader getBaseClassLoader() throws LogConfigurationException { - ClassLoader thisClassLoader = getClassLoader(LogFactoryImpl.class); - - if (!useTCCL) { - return thisClassLoader; - } - - ClassLoader contextClassLoader = getContextClassLoaderInternal(); - - ClassLoader baseClassLoader = getLowestClassLoader( - contextClassLoader, thisClassLoader); - - if (baseClassLoader == null) { - // The two classloaders are not part of a parent child relationship. - // In some classloading setups (e.g. JBoss with its - // UnifiedLoaderRepository) this can still work, so if user hasn't - // forbidden it, just return the contextClassLoader. - if (allowFlawedContext) { - if (isDiagnosticsEnabled()) { - logDiagnostic("[WARNING] the context classloader is not part of a" + - " parent-child relationship with the classloader that" + - " loaded LogFactoryImpl."); - } - // If contextClassLoader were null, getLowestClassLoader() would - // have returned thisClassLoader. The fact we are here means - // contextClassLoader is not null, so we can just return it. - return contextClassLoader; - } - else { - throw new LogConfigurationException("Bad classloader hierarchy; LogFactoryImpl was loaded via" + - " a classloader that is not related to the current context" + - " classloader."); - } - } - - if (baseClassLoader != contextClassLoader) { - // We really should just use the contextClassLoader as the starting - // point for scanning for log adapter classes. However it is expected - // that there are a number of broken systems out there which create - // custom classloaders but fail to set the context classloader so - // we handle those flawed systems anyway. - if (allowFlawedContext) { - if (isDiagnosticsEnabled()) { - logDiagnostic( - "Warning: the context classloader is an ancestor of the" + - " classloader that loaded LogFactoryImpl; it should be" + - " the same or a descendant. The application using" + - " commons-logging should ensure the context classloader" + - " is used correctly."); - } - } else { - throw new LogConfigurationException( - "Bad classloader hierarchy; LogFactoryImpl was loaded via" + - " a classloader that is not related to the current context" + - " classloader."); - } - } - - return baseClassLoader; - } - - /** - * Given two related classloaders, return the one which is a child of - * the other. - *

- * @param c1 is a classloader (including the null classloader) - * @param c2 is a classloader (including the null classloader) - * - * @return c1 if it has c2 as an ancestor, c2 if it has c1 as an ancestor, - * and null if neither is an ancestor of the other. - */ - private ClassLoader getLowestClassLoader(ClassLoader c1, ClassLoader c2) { - // TODO: use AccessController when dealing with classloaders here - - if (c1 == null) { - return c2; - } - - if (c2 == null) { - return c1; - } - - ClassLoader current; - - // scan c1's ancestors to find c2 - current = c1; - while (current != null) { - if (current == c2) { - return c1; - } - // current = current.getParent(); - current = getParentClassLoader(current); - } - - // scan c2's ancestors to find c1 - current = c2; - while (current != null) { - if (current == c1) { - return c2; - } - // current = current.getParent(); - current = getParentClassLoader(current); - } - - return null; - } - - /** - * Generates an internal diagnostic logging of the discovery failure and - * then throws a LogConfigurationException that wraps - * the passed Throwable. - * - * @param logAdapterClassName is the class name of the Log implementation - * that could not be instantiated. Cannot be null. - * - * @param classLoader is the classloader that we were trying to load the - * logAdapterClassName from when the exception occurred. - * - * @param discoveryFlaw is the Throwable created by the classloader - * - * @throws LogConfigurationException ALWAYS - */ - private void handleFlawedDiscovery(String logAdapterClassName, - ClassLoader classLoader, // USED? - Throwable discoveryFlaw) { - - if (isDiagnosticsEnabled()) { - logDiagnostic("Could not instantiate Log '" + - logAdapterClassName + "' -- " + - discoveryFlaw.getClass().getName() + ": " + - discoveryFlaw.getLocalizedMessage()); - - if (discoveryFlaw instanceof InvocationTargetException ) { - // Ok, the lib is there but while trying to create a real underlying - // logger something failed in the underlying lib; display info about - // that if possible. - InvocationTargetException ite = (InvocationTargetException)discoveryFlaw; - Throwable cause = ite.getTargetException(); - if (cause != null) { - logDiagnostic("... InvocationTargetException: " + - cause.getClass().getName() + ": " + - cause.getLocalizedMessage()); - - if (cause instanceof ExceptionInInitializerError) { - ExceptionInInitializerError eiie = (ExceptionInInitializerError)cause; - Throwable cause2 = eiie.getException(); - if (cause2 != null) { - final StringWriter sw = new StringWriter(); - cause2.printStackTrace(new PrintWriter(sw, true)); - logDiagnostic("... ExceptionInInitializerError: " + sw.toString()); - } - } - } - } - } - - if (!allowFlawedDiscovery) { - throw new LogConfigurationException(discoveryFlaw); - } - } - - /** - * Report a problem loading the log adapter, then either return - * (if the situation is considered recoverable) or throw a - * LogConfigurationException. - *

- * There are two possible reasons why we successfully loaded the - * specified log adapter class then failed to cast it to a Log object: - *

    - *
  1. the specific class just doesn't implement the Log interface - * (user screwed up), or - *
  2. the specified class has bound to a Log class loaded by some other - * classloader; Log@classloaderX cannot be cast to Log@classloaderY. - *
- *

- * Here we try to figure out which case has occurred so we can give the - * user some reasonable feedback. - * - * @param badClassLoader is the classloader we loaded the problem class from, - * ie it is equivalent to badClass.getClassLoader(). - * - * @param badClass is a Class object with the desired name, but which - * does not implement Log correctly. - * - * @throws LogConfigurationException when the situation - * should not be recovered from. - */ - private void handleFlawedHierarchy(ClassLoader badClassLoader, Class badClass) - throws LogConfigurationException { - - boolean implementsLog = false; - String logInterfaceName = Log.class.getName(); - Class interfaces[] = badClass.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - if (logInterfaceName.equals(interfaces[i].getName())) { - implementsLog = true; - break; - } - } - - if (implementsLog) { - // the class does implement an interface called Log, but - // it is in the wrong classloader - if (isDiagnosticsEnabled()) { - try { - ClassLoader logInterfaceClassLoader = getClassLoader(Log.class); - logDiagnostic("Class '" + badClass.getName() + "' was found in classloader " + - objectId(badClassLoader) + ". It is bound to a Log interface which is not" + - " the one loaded from classloader " + objectId(logInterfaceClassLoader)); - } catch (Throwable t) { - handleThrowable(t); // may re-throw t - logDiagnostic("Error while trying to output diagnostics about" + " bad class '" + badClass + "'"); - } - } - - if (!allowFlawedHierarchy) { - StringBuffer msg = new StringBuffer(); - msg.append("Terminating logging for this context "); - msg.append("due to bad log hierarchy. "); - msg.append("You have more than one version of '"); - msg.append(Log.class.getName()); - msg.append("' visible."); - if (isDiagnosticsEnabled()) { - logDiagnostic(msg.toString()); - } - throw new LogConfigurationException(msg.toString()); - } - - if (isDiagnosticsEnabled()) { - StringBuffer msg = new StringBuffer(); - msg.append("Warning: bad log hierarchy. "); - msg.append("You have more than one version of '"); - msg.append(Log.class.getName()); - msg.append("' visible."); - logDiagnostic(msg.toString()); - } - } else { - // this is just a bad adapter class - if (!allowFlawedDiscovery) { - StringBuffer msg = new StringBuffer(); - msg.append("Terminating logging for this context. "); - msg.append("Log class '"); - msg.append(badClass.getName()); - msg.append("' does not implement the Log interface."); - if (isDiagnosticsEnabled()) { - logDiagnostic(msg.toString()); - } - - throw new LogConfigurationException(msg.toString()); - } - - if (isDiagnosticsEnabled()) { - StringBuffer msg = new StringBuffer(); - msg.append("[WARNING] Log class '"); - msg.append(badClass.getName()); - msg.append("' does not implement the Log interface."); - logDiagnostic(msg.toString()); - } - } - } -} diff --git a/src/org/apache/commons/logging/impl/LogKitLogger.java b/src/org/apache/commons/logging/impl/LogKitLogger.java deleted file mode 100644 index 6feaa31479c..00000000000 --- a/src/org/apache/commons/logging/impl/LogKitLogger.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.io.Serializable; -import org.apache.log.Logger; -import org.apache.log.Hierarchy; -import org.apache.commons.logging.Log; - -/** - * Implementation of org.apache.commons.logging.Log - * that wraps the avalon-logkit - * logging system. Configuration of LogKit is left to the user. - *

- * LogKit accepts only String messages. - * Therefore, this implementation converts object messages into strings - * by called their toString() method before logging them. - * - * @version $Id: LogKitLogger.java 1448119 2013-02-20 12:28:04Z tn $ - */ -public class LogKitLogger implements Log, Serializable { - - /** Serializable version identifier. */ - private static final long serialVersionUID = 3768538055836059519L; - - // ------------------------------------------------------------- Attributes - - /** Logging goes to this LogKit logger */ - protected transient volatile Logger logger = null; - - /** Name of this logger */ - protected String name = null; - - // ------------------------------------------------------------ Constructor - - /** - * Construct LogKitLogger which wraps the LogKit - * logger with given name. - * - * @param name log name - */ - public LogKitLogger(String name) { - this.name = name; - this.logger = getLogger(); - } - - // --------------------------------------------------------- Public Methods - - /** - * Return the underlying Logger we are using. - */ - public Logger getLogger() { - Logger result = logger; - if (result == null) { - synchronized(this) { - result = logger; - if (result == null) { - logger = result = Hierarchy.getDefaultHierarchy().getLoggerFor(name); - } - } - } - return result; - } - - // ----------------------------------------------------- Log Implementation - - /** - * Logs a message with org.apache.log.Priority.DEBUG. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public void trace(Object message) { - debug(message); - } - - /** - * Logs a message with org.apache.log.Priority.DEBUG. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public void trace(Object message, Throwable t) { - debug(message, t); - } - - /** - * Logs a message with org.apache.log.Priority.DEBUG. - * - * @param message to log - * @see org.apache.commons.logging.Log#debug(Object) - */ - public void debug(Object message) { - if (message != null) { - getLogger().debug(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.log.Priority.DEBUG. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public void debug(Object message, Throwable t) { - if (message != null) { - getLogger().debug(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.log.Priority.INFO. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public void info(Object message) { - if (message != null) { - getLogger().info(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.log.Priority.INFO. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public void info(Object message, Throwable t) { - if (message != null) { - getLogger().info(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.log.Priority.WARN. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public void warn(Object message) { - if (message != null) { - getLogger().warn(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.log.Priority.WARN. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public void warn(Object message, Throwable t) { - if (message != null) { - getLogger().warn(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.log.Priority.ERROR. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public void error(Object message) { - if (message != null) { - getLogger().error(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.log.Priority.ERROR. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public void error(Object message, Throwable t) { - if (message != null) { - getLogger().error(String.valueOf(message), t); - } - } - - /** - * Logs a message with org.apache.log.Priority.FATAL_ERROR. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public void fatal(Object message) { - if (message != null) { - getLogger().fatalError(String.valueOf(message)); - } - } - - /** - * Logs a message with org.apache.log.Priority.FATAL_ERROR. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public void fatal(Object message, Throwable t) { - if (message != null) { - getLogger().fatalError(String.valueOf(message), t); - } - } - - /** - * Checks whether the LogKit logger will log messages of priority DEBUG. - */ - public boolean isDebugEnabled() { - return getLogger().isDebugEnabled(); - } - - /** - * Checks whether the LogKit logger will log messages of priority ERROR. - */ - public boolean isErrorEnabled() { - return getLogger().isErrorEnabled(); - } - - /** - * Checks whether the LogKit logger will log messages of priority FATAL_ERROR. - */ - public boolean isFatalEnabled() { - return getLogger().isFatalErrorEnabled(); - } - - /** - * Checks whether the LogKit logger will log messages of priority INFO. - */ - public boolean isInfoEnabled() { - return getLogger().isInfoEnabled(); - } - - /** - * Checks whether the LogKit logger will log messages of priority DEBUG. - */ - public boolean isTraceEnabled() { - return getLogger().isDebugEnabled(); - } - - /** - * Checks whether the LogKit logger will log messages of priority WARN. - */ - public boolean isWarnEnabled() { - return getLogger().isWarnEnabled(); - } -} diff --git a/src/org/apache/commons/logging/impl/NoOpLog.java b/src/org/apache/commons/logging/impl/NoOpLog.java deleted file mode 100644 index ef0de242e54..00000000000 --- a/src/org/apache/commons/logging/impl/NoOpLog.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.io.Serializable; -import org.apache.commons.logging.Log; - -/** - * Trivial implementation of Log that throws away all messages. No - * configurable system properties are supported. - * - * @version $Id: NoOpLog.java 1432663 2013-01-13 17:24:18Z tn $ - */ -public class NoOpLog implements Log, Serializable { - - /** Serializable version identifier. */ - private static final long serialVersionUID = 561423906191706148L; - - /** Convenience constructor */ - public NoOpLog() { } - /** Base constructor */ - public NoOpLog(String name) { } - /** Do nothing */ - public void trace(Object message) { } - /** Do nothing */ - public void trace(Object message, Throwable t) { } - /** Do nothing */ - public void debug(Object message) { } - /** Do nothing */ - public void debug(Object message, Throwable t) { } - /** Do nothing */ - public void info(Object message) { } - /** Do nothing */ - public void info(Object message, Throwable t) { } - /** Do nothing */ - public void warn(Object message) { } - /** Do nothing */ - public void warn(Object message, Throwable t) { } - /** Do nothing */ - public void error(Object message) { } - /** Do nothing */ - public void error(Object message, Throwable t) { } - /** Do nothing */ - public void fatal(Object message) { } - /** Do nothing */ - public void fatal(Object message, Throwable t) { } - - /** - * Debug is never enabled. - * - * @return false - */ - public final boolean isDebugEnabled() { return false; } - - /** - * Error is never enabled. - * - * @return false - */ - public final boolean isErrorEnabled() { return false; } - - /** - * Fatal is never enabled. - * - * @return false - */ - public final boolean isFatalEnabled() { return false; } - - /** - * Info is never enabled. - * - * @return false - */ - public final boolean isInfoEnabled() { return false; } - - /** - * Trace is never enabled. - * - * @return false - */ - public final boolean isTraceEnabled() { return false; } - - /** - * Warn is never enabled. - * - * @return false - */ - public final boolean isWarnEnabled() { return false; } -} diff --git a/src/org/apache/commons/logging/impl/ServletContextCleaner.java b/src/org/apache/commons/logging/impl/ServletContextCleaner.java deleted file mode 100644 index c7c21625b48..00000000000 --- a/src/org/apache/commons/logging/impl/ServletContextCleaner.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.apache.commons.logging.LogFactory; - -/** - * This class is capable of receiving notifications about the undeployment of - * a webapp, and responds by ensuring that commons-logging releases all - * memory associated with the undeployed webapp. - *

- * In general, the WeakHashtable support added in commons-logging release 1.1 - * ensures that logging classes do not hold references that prevent an - * undeployed webapp's memory from being garbage-collected even when multiple - * copies of commons-logging are deployed via multiple classloaders (a - * situation that earlier versions had problems with). However there are - * some rare cases where the WeakHashtable approach does not work; in these - * situations specifying this class as a listener for the web application will - * ensure that all references held by commons-logging are fully released. - *

- * To use this class, configure the webapp deployment descriptor to call - * this class on webapp undeploy; the contextDestroyed method will tell - * every accessible LogFactory class that the entry in its map for the - * current webapp's context classloader should be cleared. - * - * @version $Id: ServletContextCleaner.java 1432580 2013-01-13 10:41:05Z tn $ - * @since 1.1 - */ -public class ServletContextCleaner implements ServletContextListener { - - private static final Class[] RELEASE_SIGNATURE = {ClassLoader.class}; - - /** - * Invoked when a webapp is undeployed, this tells the LogFactory - * class to release any logging information related to the current - * contextClassloader. - */ - public void contextDestroyed(ServletContextEvent sce) { - ClassLoader tccl = Thread.currentThread().getContextClassLoader(); - - Object[] params = new Object[1]; - params[0] = tccl; - - // Walk up the tree of classloaders, finding all the available - // LogFactory classes and releasing any objects associated with - // the tccl (ie the webapp). - // - // When there is only one LogFactory in the classpath, and it - // is within the webapp being undeployed then there is no problem; - // garbage collection works fine. - // - // When there are multiple LogFactory classes in the classpath but - // parent-first classloading is used everywhere, this loop is really - // short. The first instance of LogFactory found will - // be the highest in the classpath, and then no more will be found. - // This is ok, as with this setup this will be the only LogFactory - // holding any data associated with the tccl being released. - // - // When there are multiple LogFactory classes in the classpath and - // child-first classloading is used in any classloader, then multiple - // LogFactory instances may hold info about this TCCL; whenever the - // webapp makes a call into a class loaded via an ancestor classloader - // and that class calls LogFactory the tccl gets registered in - // the LogFactory instance that is visible from the ancestor - // classloader. However the concrete logging library it points - // to is expected to have been loaded via the TCCL, so the - // underlying logging lib is only initialised/configured once. - // These references from ancestor LogFactory classes down to - // TCCL classloaders are held via weak references and so should - // be released but there are circumstances where they may not. - // Walking up the classloader ancestry ladder releasing - // the current tccl at each level tree, though, will definitely - // clear any problem references. - ClassLoader loader = tccl; - while (loader != null) { - // Load via the current loader. Note that if the class is not accessible - // via this loader, but is accessible via some ancestor then that class - // will be returned. - try { - Class logFactoryClass = loader.loadClass("org.apache.commons.logging.LogFactory"); - Method releaseMethod = logFactoryClass.getMethod("release", RELEASE_SIGNATURE); - releaseMethod.invoke(null, params); - loader = logFactoryClass.getClassLoader().getParent(); - } catch(ClassNotFoundException ex) { - // Neither the current classloader nor any of its ancestors could find - // the LogFactory class, so we can stop now. - loader = null; - } catch(NoSuchMethodException ex) { - // This is not expected; every version of JCL has this method - System.err.println("LogFactory instance found which does not support release method!"); - loader = null; - } catch(IllegalAccessException ex) { - // This is not expected; every ancestor class should be accessible - System.err.println("LogFactory instance found which is not accessable!"); - loader = null; - } catch(InvocationTargetException ex) { - // This is not expected - System.err.println("LogFactory instance release method failed!"); - loader = null; - } - } - - // Just to be sure, invoke release on the LogFactory that is visible from - // this ServletContextCleaner class too. This should already have been caught - // by the above loop but just in case... - LogFactory.release(tccl); - } - - /** - * Invoked when a webapp is deployed. Nothing needs to be done here. - */ - public void contextInitialized(ServletContextEvent sce) { - // do nothing - } -} diff --git a/src/org/apache/commons/logging/impl/SimpleLog.java b/src/org/apache/commons/logging/impl/SimpleLog.java deleted file mode 100644 index 01a1d9e16f2..00000000000 --- a/src/org/apache/commons/logging/impl/SimpleLog.java +++ /dev/null @@ -1,655 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Properties; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogConfigurationException; - -/** - * Simple implementation of Log that sends all enabled log messages, - * for all defined loggers, to System.err. The following system properties - * are supported to configure the behavior of this logger: - *

    - *
  • org.apache.commons.logging.simplelog.defaultlog - - * Default logging detail level for all instances of SimpleLog. - * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal"). - * If not specified, defaults to "info".
  • - *
  • org.apache.commons.logging.simplelog.log.xxxxx - - * Logging detail level for a SimpleLog instance named "xxxxx". - * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal"). - * If not specified, the default logging detail level is used.
  • - *
  • org.apache.commons.logging.simplelog.showlogname - - * Set to true if you want the Log instance name to be - * included in output messages. Defaults to false.
  • - *
  • org.apache.commons.logging.simplelog.showShortLogname - - * Set to true if you want the last component of the name to be - * included in output messages. Defaults to true.
  • - *
  • org.apache.commons.logging.simplelog.showdatetime - - * Set to true if you want the current date and time - * to be included in output messages. Default is false.
  • - *
  • org.apache.commons.logging.simplelog.dateTimeFormat - - * The date and time format to be used in the output messages. - * The pattern describing the date and time format is the same that is - * used in java.text.SimpleDateFormat. If the format is not - * specified or is invalid, the default format is used. - * The default format is yyyy/MM/dd HH:mm:ss:SSS zzz.
  • - *
- *

- * In addition to looking for system properties with the names specified - * above, this implementation also checks for a class loader resource named - * "simplelog.properties", and includes any matching definitions - * from this resource (if it exists). - * - * @version $Id: SimpleLog.java 1765376 2016-10-17 21:52:30Z ggregory $ - */ -public class SimpleLog implements Log, Serializable { - - /** Serializable version identifier. */ - private static final long serialVersionUID = 136942970684951178L; - - // ------------------------------------------------------- Class Attributes - - /** All system properties used by SimpleLog start with this */ - static protected final String systemPrefix = "org.apache.commons.logging.simplelog."; - - /** Properties loaded from simplelog.properties */ - static protected final Properties simpleLogProps = new Properties(); - - /** The default format to use when formating dates */ - static protected final String DEFAULT_DATE_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss:SSS zzz"; - - /** Include the instance name in the log message? */ - static volatile protected boolean showLogName = false; - - /** Include the short name ( last component ) of the logger in the log - * message. Defaults to true - otherwise we'll be lost in a flood of - * messages without knowing who sends them. - */ - static volatile protected boolean showShortName = true; - - /** Include the current time in the log message */ - static volatile protected boolean showDateTime = false; - - /** The date and time format to use in the log message */ - static volatile protected String dateTimeFormat = DEFAULT_DATE_TIME_FORMAT; - - /** - * Used to format times. - *

- * Any code that accesses this object should first obtain a lock on it, - * ie use synchronized(dateFormatter); this requirement was introduced - * in 1.1.1 to fix an existing thread safety bug (SimpleDateFormat.format - * is not thread-safe). - */ - static protected DateFormat dateFormatter = null; - - // ---------------------------------------------------- Log Level Constants - - /** "Trace" level logging. */ - public static final int LOG_LEVEL_TRACE = 1; - /** "Debug" level logging. */ - public static final int LOG_LEVEL_DEBUG = 2; - /** "Info" level logging. */ - public static final int LOG_LEVEL_INFO = 3; - /** "Warn" level logging. */ - public static final int LOG_LEVEL_WARN = 4; - /** "Error" level logging. */ - public static final int LOG_LEVEL_ERROR = 5; - /** "Fatal" level logging. */ - public static final int LOG_LEVEL_FATAL = 6; - - /** Enable all logging levels */ - public static final int LOG_LEVEL_ALL = LOG_LEVEL_TRACE - 1; - - /** Enable no logging levels */ - public static final int LOG_LEVEL_OFF = LOG_LEVEL_FATAL + 1; - - // ------------------------------------------------------------ Initializer - - private static String getStringProperty(String name) { - String prop = null; - try { - prop = System.getProperty(name); - } catch (SecurityException e) { - // Ignore - } - return prop == null ? simpleLogProps.getProperty(name) : prop; - } - - private static String getStringProperty(String name, String dephault) { - String prop = getStringProperty(name); - return prop == null ? dephault : prop; - } - - private static boolean getBooleanProperty(String name, boolean dephault) { - String prop = getStringProperty(name); - return prop == null ? dephault : "true".equalsIgnoreCase(prop); - } - - // Initialize class attributes. - // Load properties file, if found. - // Override with system properties. - static { - // Add props from the resource simplelog.properties - InputStream in = getResourceAsStream("simplelog.properties"); - if (null != in) { - try { - simpleLogProps.load(in); - } catch (IOException e) { - // ignored - } finally { - try { - in.close(); - } catch (IOException e) { - // ignored - } - } - } - - showLogName = getBooleanProperty(systemPrefix + "showlogname", showLogName); - showShortName = getBooleanProperty(systemPrefix + "showShortLogname", showShortName); - showDateTime = getBooleanProperty(systemPrefix + "showdatetime", showDateTime); - - if(showDateTime) { - dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat", - dateTimeFormat); - try { - dateFormatter = new SimpleDateFormat(dateTimeFormat); - } catch(IllegalArgumentException e) { - // If the format pattern is invalid - use the default format - dateTimeFormat = DEFAULT_DATE_TIME_FORMAT; - dateFormatter = new SimpleDateFormat(dateTimeFormat); - } - } - } - - // ------------------------------------------------------------- Attributes - - /** The name of this simple log instance */ - protected volatile String logName = null; - /** The current log level */ - protected volatile int currentLogLevel; - /** The short name of this simple log instance */ - private volatile String shortLogName = null; - - // ------------------------------------------------------------ Constructor - - /** - * Construct a simple log with given name. - * - * @param name log name - */ - public SimpleLog(String name) { - logName = name; - - // Set initial log level - // Used to be: set default log level to ERROR - // IMHO it should be lower, but at least info ( costin ). - setLevel(SimpleLog.LOG_LEVEL_INFO); - - // Set log level from properties - String lvl = getStringProperty(systemPrefix + "log." + logName); - int i = String.valueOf(name).lastIndexOf("."); - while(null == lvl && i > -1) { - name = name.substring(0,i); - lvl = getStringProperty(systemPrefix + "log." + name); - i = String.valueOf(name).lastIndexOf("."); - } - - if(null == lvl) { - lvl = getStringProperty(systemPrefix + "defaultlog"); - } - - if("all".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_ALL); - } else if("trace".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_TRACE); - } else if("debug".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_DEBUG); - } else if("info".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_INFO); - } else if("warn".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_WARN); - } else if("error".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_ERROR); - } else if("fatal".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_FATAL); - } else if("off".equalsIgnoreCase(lvl)) { - setLevel(SimpleLog.LOG_LEVEL_OFF); - } - } - - // -------------------------------------------------------- Properties - - /** - * Set logging level. - * - * @param currentLogLevel new logging level - */ - public void setLevel(int currentLogLevel) { - this.currentLogLevel = currentLogLevel; - } - - /** - * Get logging level. - */ - public int getLevel() { - return currentLogLevel; - } - - // -------------------------------------------------------- Logging Methods - - /** - * Do the actual logging. - *

- * This method assembles the message and then calls write() - * to cause it to be written. - * - * @param type One of the LOG_LEVEL_XXX constants defining the log level - * @param message The message itself (typically a String) - * @param t The exception whose stack trace should be logged - */ - protected void log(int type, Object message, Throwable t) { - // Use a string buffer for better performance - final StringBuffer buf = new StringBuffer(); - - // Append date-time if so configured - if(showDateTime) { - final Date now = new Date(); - String dateText; - synchronized(dateFormatter) { - dateText = dateFormatter.format(now); - } - buf.append(dateText); - buf.append(" "); - } - - // Append a readable representation of the log level - switch(type) { - case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break; - case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break; - case SimpleLog.LOG_LEVEL_INFO: buf.append("[INFO] "); break; - case SimpleLog.LOG_LEVEL_WARN: buf.append("[WARN] "); break; - case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break; - case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break; - } - - // Append the name of the log instance if so configured - if(showShortName) { - if(shortLogName == null) { - // Cut all but the last component of the name for both styles - final String slName = logName.substring(logName.lastIndexOf(".") + 1); - shortLogName = slName.substring(slName.lastIndexOf("/") + 1); - } - buf.append(String.valueOf(shortLogName)).append(" - "); - } else if(showLogName) { - buf.append(String.valueOf(logName)).append(" - "); - } - - // Append the message - buf.append(String.valueOf(message)); - - // Append stack trace if not null - if(t != null) { - buf.append(" <"); - buf.append(t.toString()); - buf.append(">"); - - final java.io.StringWriter sw = new java.io.StringWriter(1024); - final java.io.PrintWriter pw = new java.io.PrintWriter(sw); - t.printStackTrace(pw); - pw.close(); - buf.append(sw.toString()); - } - - // Print to the appropriate destination - write(buf); - } - - /** - * Write the content of the message accumulated in the specified - * StringBuffer to the appropriate output destination. The - * default implementation writes to System.err. - * - * @param buffer A StringBuffer containing the accumulated - * text to be logged - */ - protected void write(StringBuffer buffer) { - System.err.println(buffer.toString()); - } - - /** - * Is the given log level currently enabled? - * - * @param logLevel is this level enabled? - */ - protected boolean isLevelEnabled(int logLevel) { - // log level are numerically ordered so can use simple numeric - // comparison - return logLevel >= currentLogLevel; - } - - // -------------------------------------------------------- Log Implementation - - /** - * Logs a message with - * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG. - * - * @param message to log - * @see org.apache.commons.logging.Log#debug(Object) - */ - public final void debug(Object message) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) { - log(SimpleLog.LOG_LEVEL_DEBUG, message, null); - } - } - - /** - * Logs a message with - * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#debug(Object, Throwable) - */ - public final void debug(Object message, Throwable t) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) { - log(SimpleLog.LOG_LEVEL_DEBUG, message, t); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE. - * - * @param message to log - * @see org.apache.commons.logging.Log#trace(Object) - */ - public final void trace(Object message) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) { - log(SimpleLog.LOG_LEVEL_TRACE, message, null); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#trace(Object, Throwable) - */ - public final void trace(Object message, Throwable t) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) { - log(SimpleLog.LOG_LEVEL_TRACE, message, t); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO. - * - * @param message to log - * @see org.apache.commons.logging.Log#info(Object) - */ - public final void info(Object message) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) { - log(SimpleLog.LOG_LEVEL_INFO,message,null); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#info(Object, Throwable) - */ - public final void info(Object message, Throwable t) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) { - log(SimpleLog.LOG_LEVEL_INFO, message, t); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN. - * - * @param message to log - * @see org.apache.commons.logging.Log#warn(Object) - */ - public final void warn(Object message) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) { - log(SimpleLog.LOG_LEVEL_WARN, message, null); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#warn(Object, Throwable) - */ - public final void warn(Object message, Throwable t) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) { - log(SimpleLog.LOG_LEVEL_WARN, message, t); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR. - * - * @param message to log - * @see org.apache.commons.logging.Log#error(Object) - */ - public final void error(Object message) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) { - log(SimpleLog.LOG_LEVEL_ERROR, message, null); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#error(Object, Throwable) - */ - public final void error(Object message, Throwable t) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) { - log(SimpleLog.LOG_LEVEL_ERROR, message, t); - } - } - - /** - * Log a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL. - * - * @param message to log - * @see org.apache.commons.logging.Log#fatal(Object) - */ - public final void fatal(Object message) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) { - log(SimpleLog.LOG_LEVEL_FATAL, message, null); - } - } - - /** - * Logs a message with org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL. - * - * @param message to log - * @param t log this cause - * @see org.apache.commons.logging.Log#fatal(Object, Throwable) - */ - public final void fatal(Object message, Throwable t) { - if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) { - log(SimpleLog.LOG_LEVEL_FATAL, message, t); - } - } - - /** - * Are debug messages currently enabled? - *

- * This allows expensive operations such as String - * concatenation to be avoided when the message will be ignored by the - * logger. - */ - public final boolean isDebugEnabled() { - return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG); - } - - /** - * Are error messages currently enabled? - *

- * This allows expensive operations such as String - * concatenation to be avoided when the message will be ignored by the - * logger. - */ - public final boolean isErrorEnabled() { - return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR); - } - - /** - * Are fatal messages currently enabled? - *

- * This allows expensive operations such as String - * concatenation to be avoided when the message will be ignored by the - * logger. - */ - public final boolean isFatalEnabled() { - return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL); - } - - /** - * Are info messages currently enabled? - *

- * This allows expensive operations such as String - * concatenation to be avoided when the message will be ignored by the - * logger. - */ - public final boolean isInfoEnabled() { - return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO); - } - - /** - * Are trace messages currently enabled? - *

- * This allows expensive operations such as String - * concatenation to be avoided when the message will be ignored by the - * logger. - */ - public final boolean isTraceEnabled() { - return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE); - } - - /** - * Are warn messages currently enabled? - *

- * This allows expensive operations such as String - * concatenation to be avoided when the message will be ignored by the - * logger. - */ - public final boolean isWarnEnabled() { - return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN); - } - - /** - * Return the thread context class loader if available. - * Otherwise return null. - * - * The thread context class loader is available for JDK 1.2 - * or later, if certain security conditions are met. - * - * @throws LogConfigurationException if a suitable class loader - * cannot be identified. - */ - private static ClassLoader getContextClassLoader() { - ClassLoader classLoader = null; - - try { - // Are we running on a JDK 1.2 or later system? - final Method method = Thread.class.getMethod("getContextClassLoader", (Class[]) null); - - // Get the thread context class loader (if there is one) - try { - classLoader = (ClassLoader)method.invoke(Thread.currentThread(), (Class[]) null); - } catch (IllegalAccessException e) { - // ignore - } catch (InvocationTargetException e) { - /** - * InvocationTargetException is thrown by 'invoke' when - * the method being invoked (getContextClassLoader) throws - * an exception. - * - * getContextClassLoader() throws SecurityException when - * the context class loader isn't an ancestor of the - * calling class's class loader, or if security - * permissions are restricted. - * - * In the first case (not related), we want to ignore and - * keep going. We cannot help but also ignore the second - * with the logic below, but other calls elsewhere (to - * obtain a class loader) will trigger this exception where - * we can make a distinction. - */ - if (e.getTargetException() instanceof SecurityException) { - // ignore - } else { - // Capture 'e.getTargetException()' exception for details - // alternate: log 'e.getTargetException()', and pass back 'e'. - throw new LogConfigurationException - ("Unexpected InvocationTargetException", e.getTargetException()); - } - } - } catch (NoSuchMethodException e) { - // Assume we are running on JDK 1.1 - // ignore - } - - if (classLoader == null) { - classLoader = SimpleLog.class.getClassLoader(); - } - - // Return the selected class loader - return classLoader; - } - - private static InputStream getResourceAsStream(final String name) { - return (InputStream)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - ClassLoader threadCL = getContextClassLoader(); - - if (threadCL != null) { - return threadCL.getResourceAsStream(name); - } else { - return ClassLoader.getSystemResourceAsStream(name); - } - } - }); - } -} - diff --git a/src/org/apache/commons/logging/impl/WeakHashtable.java b/src/org/apache/commons/logging/impl/WeakHashtable.java deleted file mode 100644 index c5773f3dfeb..00000000000 --- a/src/org/apache/commons/logging/impl/WeakHashtable.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.logging.impl; - -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Implementation of Hashtable that uses WeakReference's - * to hold its keys thus allowing them to be reclaimed by the garbage collector. - * The associated values are retained using strong references. - *

- * This class follows the semantics of Hashtable as closely as - * possible. It therefore does not accept null values or keys. - *

- * Note: - * This is not intended to be a general purpose hash table replacement. - * This implementation is also tuned towards a particular purpose: for use as a replacement - * for Hashtable in LogFactory. This application requires - * good liveliness for get and put. Various tradeoffs - * have been made with this in mind. - *

- * Usage: typical use case is as a drop-in replacement - * for the Hashtable used in LogFactory for J2EE environments - * running 1.3+ JVMs. Use of this class in most cases (see below) will - * allow classloaders to be collected by the garbage collector without the need - * to call {@link org.apache.commons.logging.LogFactory#release(ClassLoader) LogFactory.release(ClassLoader)}. - *

- * org.apache.commons.logging.LogFactory checks whether this class - * can be supported by the current JVM, and if so then uses it to store - * references to the LogFactory implementation it loads - * (rather than using a standard Hashtable instance). - * Having this class used instead of Hashtable solves - * certain issues related to dynamic reloading of applications in J2EE-style - * environments. However this class requires java 1.3 or later (due to its use - * of java.lang.ref.WeakReference and associates). - * And by the way, this extends Hashtable rather than HashMap - * for backwards compatibility reasons. See the documentation - * for method LogFactory.createFactoryStore for more details. - *

- * The reason all this is necessary is due to a issue which - * arises during hot deploy in a J2EE-like containers. - * Each component running in the container owns one or more classloaders; when - * the component loads a LogFactory instance via the component classloader - * a reference to it gets stored in the static LogFactory.factories member, - * keyed by the component's classloader so different components don't - * stomp on each other. When the component is later unloaded, the container - * sets the component's classloader to null with the intent that all the - * component's classes get garbage-collected. However there's still a - * reference to the component's classloader from a key in the "global" - * LogFactory's factories member! If LogFactory.release() - * is called whenever component is unloaded, the classloaders will be correctly - * garbage collected; this should be done by any container that - * bundles commons-logging by default. However, holding the classloader - * references weakly ensures that the classloader will be garbage collected - * without the container performing this step. - *

- * Limitations: - * There is still one (unusual) scenario in which a component will not - * be correctly unloaded without an explicit release. Though weak references - * are used for its keys, it is necessary to use strong references for its values. - *

- * If the abstract class LogFactory is - * loaded by the container classloader but a subclass of - * LogFactory [LogFactory1] is loaded by the component's - * classloader and an instance stored in the static map associated with the - * base LogFactory class, then there is a strong reference from the LogFactory - * class to the LogFactory1 instance (as normal) and a strong reference from - * the LogFactory1 instance to the component classloader via - * getClass().getClassLoader(). This chain of references will prevent - * collection of the child classloader. - *

- * Such a situation occurs when the commons-logging.jar is - * loaded by a parent classloader (e.g. a server level classloader in a - * servlet container) and a custom LogFactory implementation is - * loaded by a child classloader (e.g. a web app classloader). - *

- * To avoid this scenario, ensure - * that any custom LogFactory subclass is loaded by the same classloader as - * the base LogFactory. Creating custom LogFactory subclasses is, - * however, rare. The standard LogFactoryImpl class should be sufficient - * for most or all users. - * - * @version $Id: WeakHashtable.java 1435077 2013-01-18 10:51:35Z tn $ - * @since 1.1 - */ -public final class WeakHashtable extends Hashtable { - - /** Serializable version identifier. */ - private static final long serialVersionUID = -1546036869799732453L; - - /** - * The maximum number of times put() or remove() can be called before - * the map will be purged of all cleared entries. - */ - private static final int MAX_CHANGES_BEFORE_PURGE = 100; - - /** - * The maximum number of times put() or remove() can be called before - * the map will be purged of one cleared entry. - */ - private static final int PARTIAL_PURGE_COUNT = 10; - - /* ReferenceQueue we check for gc'd keys */ - private final ReferenceQueue queue = new ReferenceQueue(); - /* Counter used to control how often we purge gc'd entries */ - private int changeCount = 0; - - /** - * Constructs a WeakHashtable with the Hashtable default - * capacity and load factor. - */ - public WeakHashtable() {} - - /** - *@see Hashtable - */ - public boolean containsKey(Object key) { - // purge should not be required - Referenced referenced = new Referenced(key); - return super.containsKey(referenced); - } - - /** - *@see Hashtable - */ - public Enumeration elements() { - purge(); - return super.elements(); - } - - /** - *@see Hashtable - */ - public Set entrySet() { - purge(); - Set referencedEntries = super.entrySet(); - Set unreferencedEntries = new HashSet(); - for (Iterator it=referencedEntries.iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry) it.next(); - Referenced referencedKey = (Referenced) entry.getKey(); - Object key = referencedKey.getValue(); - Object value = entry.getValue(); - if (key != null) { - Entry dereferencedEntry = new Entry(key, value); - unreferencedEntries.add(dereferencedEntry); - } - } - return unreferencedEntries; - } - - /** - *@see Hashtable - */ - public Object get(Object key) { - // for performance reasons, no purge - Referenced referenceKey = new Referenced(key); - return super.get(referenceKey); - } - - /** - *@see Hashtable - */ - public Enumeration keys() { - purge(); - final Enumeration enumer = super.keys(); - return new Enumeration() { - public boolean hasMoreElements() { - return enumer.hasMoreElements(); - } - public Object nextElement() { - Referenced nextReference = (Referenced) enumer.nextElement(); - return nextReference.getValue(); - } - }; - } - - /** - *@see Hashtable - */ - public Set keySet() { - purge(); - Set referencedKeys = super.keySet(); - Set unreferencedKeys = new HashSet(); - for (Iterator it=referencedKeys.iterator(); it.hasNext();) { - Referenced referenceKey = (Referenced) it.next(); - Object keyValue = referenceKey.getValue(); - if (keyValue != null) { - unreferencedKeys.add(keyValue); - } - } - return unreferencedKeys; - } - - /** - *@see Hashtable - */ - public synchronized Object put(Object key, Object value) { - // check for nulls, ensuring semantics match superclass - if (key == null) { - throw new NullPointerException("Null keys are not allowed"); - } - if (value == null) { - throw new NullPointerException("Null values are not allowed"); - } - - // for performance reasons, only purge every - // MAX_CHANGES_BEFORE_PURGE times - if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) { - purge(); - changeCount = 0; - } - // do a partial purge more often - else if (changeCount % PARTIAL_PURGE_COUNT == 0) { - purgeOne(); - } - - Referenced keyRef = new Referenced(key, queue); - return super.put(keyRef, value); - } - - /** - *@see Hashtable - */ - public void putAll(Map t) { - if (t != null) { - Set entrySet = t.entrySet(); - for (Iterator it=entrySet.iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry) it.next(); - put(entry.getKey(), entry.getValue()); - } - } - } - - /** - *@see Hashtable - */ - public Collection values() { - purge(); - return super.values(); - } - - /** - *@see Hashtable - */ - public synchronized Object remove(Object key) { - // for performance reasons, only purge every - // MAX_CHANGES_BEFORE_PURGE times - if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) { - purge(); - changeCount = 0; - } - // do a partial purge more often - else if (changeCount % PARTIAL_PURGE_COUNT == 0) { - purgeOne(); - } - return super.remove(new Referenced(key)); - } - - /** - *@see Hashtable - */ - public boolean isEmpty() { - purge(); - return super.isEmpty(); - } - - /** - *@see Hashtable - */ - public int size() { - purge(); - return super.size(); - } - - /** - *@see Hashtable - */ - public String toString() { - purge(); - return super.toString(); - } - - /** - * @see Hashtable - */ - protected void rehash() { - // purge here to save the effort of rehashing dead entries - purge(); - super.rehash(); - } - - /** - * Purges all entries whose wrapped keys - * have been garbage collected. - */ - private void purge() { - final List toRemove = new ArrayList(); - synchronized (queue) { - WeakKey key; - while ((key = (WeakKey) queue.poll()) != null) { - toRemove.add(key.getReferenced()); - } - } - - // LOGGING-119: do the actual removal of the keys outside the sync block - // to prevent deadlock scenarios as purge() may be called from - // non-synchronized methods too - final int size = toRemove.size(); - for (int i = 0; i < size; i++) { - super.remove(toRemove.get(i)); - } - } - - /** - * Purges one entry whose wrapped key - * has been garbage collected. - */ - private void purgeOne() { - synchronized (queue) { - WeakKey key = (WeakKey) queue.poll(); - if (key != null) { - super.remove(key.getReferenced()); - } - } - } - - /** Entry implementation */ - private final static class Entry implements Map.Entry { - - private final Object key; - private final Object value; - - private Entry(Object key, Object value) { - this.key = key; - this.value = value; - } - - public boolean equals(Object o) { - boolean result = false; - if (o != null && o instanceof Map.Entry) { - Map.Entry entry = (Map.Entry) o; - result = (getKey()==null ? - entry.getKey() == null : - getKey().equals(entry.getKey())) && - (getValue()==null ? - entry.getValue() == null : - getValue().equals(entry.getValue())); - } - return result; - } - - public int hashCode() { - return (getKey()==null ? 0 : getKey().hashCode()) ^ - (getValue()==null ? 0 : getValue().hashCode()); - } - - public Object setValue(Object value) { - throw new UnsupportedOperationException("Entry.setValue is not supported."); - } - - public Object getValue() { - return value; - } - - public Object getKey() { - return key; - } - } - - /** Wrapper giving correct symantics for equals and hashcode */ - private final static class Referenced { - - private final WeakReference reference; - private final int hashCode; - - /** - * - * @throws NullPointerException if referant is null - */ - private Referenced(Object referant) { - reference = new WeakReference(referant); - // Calc a permanent hashCode so calls to Hashtable.remove() - // work if the WeakReference has been cleared - hashCode = referant.hashCode(); - } - - /** - * - * @throws NullPointerException if key is null - */ - private Referenced(Object key, ReferenceQueue queue) { - reference = new WeakKey(key, queue, this); - // Calc a permanent hashCode so calls to Hashtable.remove() - // work if the WeakReference has been cleared - hashCode = key.hashCode(); - - } - - public int hashCode() { - return hashCode; - } - - private Object getValue() { - return reference.get(); - } - - public boolean equals(Object o) { - boolean result = false; - if (o instanceof Referenced) { - Referenced otherKey = (Referenced) o; - Object thisKeyValue = getValue(); - Object otherKeyValue = otherKey.getValue(); - if (thisKeyValue == null) { - result = otherKeyValue == null; - - // Since our hashcode was calculated from the original - // non-null referant, the above check breaks the - // hashcode/equals contract, as two cleared Referenced - // objects could test equal but have different hashcodes. - // We can reduce (not eliminate) the chance of this - // happening by comparing hashcodes. - result = result && this.hashCode() == otherKey.hashCode(); - // In any case, as our c'tor does not allow null referants - // and Hashtable does not do equality checks between - // existing keys, normal hashtable operations should never - // result in an equals comparison between null referants - } - else - { - result = thisKeyValue.equals(otherKeyValue); - } - } - return result; - } - } - - /** - * WeakReference subclass that holds a hard reference to an - * associated value and also makes accessible - * the Referenced object holding it. - */ - private final static class WeakKey extends WeakReference { - - private final Referenced referenced; - - private WeakKey(Object key, - ReferenceQueue queue, - Referenced referenced) { - super(key, queue); - this.referenced = referenced; - } - - private Referenced getReferenced() { - return referenced; - } - } -} diff --git a/src/org/apache/commons/logging/impl/package.html b/src/org/apache/commons/logging/impl/package.html deleted file mode 100644 index 53447841800..00000000000 --- a/src/org/apache/commons/logging/impl/package.html +++ /dev/null @@ -1,22 +0,0 @@ - - - -

Concrete implementations of commons-logging wrapper APIs.

- diff --git a/src/org/apache/commons/logging/package.html b/src/org/apache/commons/logging/package.html deleted file mode 100644 index a5e8f9dcae7..00000000000 --- a/src/org/apache/commons/logging/package.html +++ /dev/null @@ -1,255 +0,0 @@ - - - -

Simple wrapper API around multiple logging APIs.

- - -

Overview

- -

This package provides an API for logging in server-based applications that -can be used around a variety of different logging implementations, including -prebuilt support for the following:

-
    -
  • Log4J (version 1.2 or later) - from Apache's Logging project. Each named Log - instance is connected to a corresponding Log4J Logger.
  • -
  • - JDK Logging API, included in JDK 1.4 or later systems. Each named - Log instance is connected to a corresponding - java.util.logging.Logger instance.
  • -
  • LogKit from Apache's - Avalon project. Each named Log instance is - connected to a corresponding LogKit Logger.
  • -
  • NoOpLog implementation that simply swallows - all log output, for all named Log instances.
  • -
  • SimpleLog implementation that writes all - log output, for all named Log instances, to - System.err.
  • -
- - -

Quick Start Guide

- -

For those impatient to just get on with it, the following example -illustrates the typical declaration and use of a logger that is named (by -convention) after the calling class: - -

-    import org.apache.commons.logging.Log;
-    import org.apache.commons.logging.LogFactory;
-
-    public class Foo {
-
-        private Log log = LogFactory.getLog(Foo.class);
-
-        public void foo() {
-            ...
-            try {
-                if (log.isDebugEnabled()) {
-                    log.debug("About to do something to object " + name);
-                }
-                name.bar();
-            } catch (IllegalStateException e) {
-                log.error("Something bad happened to " + name, e);
-            }
-            ...
-        }
-
- -

Unless you configure things differently, all log output will be written -to System.err. Therefore, you really will want to review the remainder of -this page in order to understand how to configure logging for your -application.

- - -

Configuring the Commons Logging Package

- - -

Choosing a LogFactory Implementation

- -

From an application perspective, the first requirement is to retrieve an -object reference to the LogFactory instance that will be used -to create Log instances for this -application. This is normally accomplished by calling the static -getFactory() method. This method implements the following -discovery algorithm to select the name of the LogFactory -implementation class this application wants to use:

-
    -
  • Check for a system property named - org.apache.commons.logging.LogFactory.
  • -
  • Use the JDK 1.3 JAR Services Discovery mechanism (see - - http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html for - more information) to look for a resource named - META-INF/services/org.apache.commons.logging.LogFactory - whose first line is assumed to contain the desired class name.
  • -
  • Look for a properties file named commons-logging.properties - visible in the application class path, with a property named - org.apache.commons.logging.LogFactory defining the - desired implementation class name.
  • -
  • Fall back to a default implementation, which is described - further below.
  • -
- -

If a commons-logging.properties file is found, all of the -properties defined there are also used to set configuration attributes on -the instantiated LogFactory instance.

- -

Once an implementation class name is selected, the corresponding class is -loaded from the current Thread context class loader (if there is one), or -from the class loader that loaded the LogFactory class itself -otherwise. This allows a copy of commons-logging.jar to be -shared in a multiple class loader environment (such as a servlet container), -but still allow each web application to provide its own LogFactory -implementation, if it so desires. An instance of this class will then be -created, and cached per class loader. - - -

The Default LogFactory Implementation

- -

The Logging Package APIs include a default LogFactory -implementation class ( -org.apache.commons.logging.impl.LogFactoryImpl) that is selected if no -other implementation class name can be discovered. Its primary purpose is -to create (as necessary) and return Log instances -in response to calls to the getInstance() method. The default -implementation uses the following rules:

-
    -
  • At most one Log instance of the same name will be created. - Subsequent getInstance() calls to the same - LogFactory instance, with the same name or Class - parameter, will return the same Log instance.
  • -
  • When a new Log instance must be created, the default - LogFactory implementation uses the following discovery - process: -
      -
    • Look for a configuration attribute of this factory named - org.apache.commons.logging.Log (for backwards - compatibility to pre-1.0 versions of this API, an attribute - org.apache.commons.logging.log is also consulted).
    • -
    • Look for a system property named - org.apache.commons.logging.Log (for backwards - compatibility to pre-1.0 versions of this API, a system property - org.apache.commons.logging.log is also consulted).
    • -
    • If the Log4J logging system is available in the application - class path, use the corresponding wrapper class - (Log4JLogger).
    • -
    • If the application is executing on a JDK 1.4 system, use - the corresponding wrapper class - (Jdk14Logger).
    • -
    • Fall back to the default simple logging implementation - (SimpleLog).
    • -
  • -
  • Load the class of the specified name from the thread context class - loader (if any), or from the class loader that loaded the - LogFactory class otherwise.
  • -
  • Instantiate an instance of the selected Log - implementation class, passing the specified name as the single - argument to its constructor.
  • -
- -

See the SimpleLog Javadocs for detailed -configuration information for this default implementation.

- - -

Configuring the Underlying Logging System

- -

The basic principle is that the user is totally responsible for the -configuration of the underlying logging system. -Commons-logging should not change the existing configuration.

- -

Each individual Log implementation may -support its own configuration properties. These will be documented in the -class descriptions for the corresponding implementation class.

- -

Finally, some Log implementations (such as the one for Log4J) -require an external configuration file for the entire logging environment. -This file should be prepared in a manner that is specific to the actual logging -technology being used.

- - -

Using the Logging Package APIs

- -

Use of the Logging Package APIs, from the perspective of an application -component, consists of the following steps:

-
    -
  1. Acquire a reference to an instance of - org.apache.commons.logging.Log, by calling the - factory method - - LogFactory.getInstance(String name). Your application can contain - references to multiple loggers that are used for different - purposes. A typical scenario for a server application is to have each - major component of the server use its own Log instance.
  2. -
  3. Cause messages to be logged (if the corresponding detail level is enabled) - by calling appropriate methods (trace(), debug(), - info(), warn(), error, and - fatal()).
  4. -
- -

For convenience, LogFactory also offers a static method -getLog() that combines the typical two-step pattern:

-
-  Log log = LogFactory.getFactory().getInstance(Foo.class);
-
-

into a single method call:

-
-  Log log = LogFactory.getLog(Foo.class);
-
- -

For example, you might use the following technique to initialize and -use a Log instance in an application component:

-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class MyComponent {
-
-  protected Log log =
-    LogFactory.getLog(MyComponent.class);
-
-  // Called once at startup time
-  public void start() {
-    ...
-    log.info("MyComponent started");
-    ...
-  }
-
-  // Called once at shutdown time
-  public void stop() {
-    ...
-    log.info("MyComponent stopped");
-    ...
-  }
-
-  // Called repeatedly to process a particular argument value
-  // which you want logged if debugging is enabled
-  public void process(String value) {
-    ...
-    // Do the string concatenation only if logging is enabled
-    if (log.isDebugEnabled())
-      log.debug("MyComponent processing " + value);
-    ...
-  }
-
-}
-
- - diff --git a/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java b/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java deleted file mode 100644 index 4e5216e32d9..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java +++ /dev/null @@ -1,109 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.util.ArrayList; -import java.util.List; - -public class AbstractLayer { - private LayerGroup parent; - private String name; - private String description; - private Style style; - private Boolean visible; - private Boolean visibleTexts = Boolean.TRUE; - - public AbstractLayer(String name) { - this(name, (String) null); - } - - public AbstractLayer(String name, String description) { - this(name, description, MapMarkerCircle.getDefaultStyle()); - } - - public AbstractLayer(String name, Style style) { - this(name, null, style); - } - - public AbstractLayer(String name, String description, Style style) { - this(null, name, description, style); - } - - public AbstractLayer(LayerGroup parent, String name) { - this(parent, name, MapMarkerCircle.getDefaultStyle()); - } - - public AbstractLayer(LayerGroup parent, String name, Style style) { - this(parent, name, null, style); - } - - public AbstractLayer(LayerGroup parent, String name, String description, Style style) { - setParent(parent); - setName(name); - setDescription(description); - setStyle(style); - setVisible(Boolean.TRUE); - - if (parent != null) parent.add(this); - } - - public LayerGroup getParent() { - return parent; - } - - public void setParent(LayerGroup parent) { - this.parent = parent; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Style getStyle() { - return style; - } - - public void setStyle(Style style) { - this.style = style; - } - - public Boolean isVisible() { - return visible; - } - - public void setVisible(Boolean visible) { - this.visible = visible; - } - - public static List add(List list, E element) { - if (element != null) { - if (list == null) list = new ArrayList<>(); - if (!list.contains(element)) list.add(element); - } - return list; - } - - public Boolean isVisibleTexts() { - return visibleTexts; - } - - public void setVisibleTexts(Boolean visibleTexts) { - this.visibleTexts = visibleTexts; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java b/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java deleted file mode 100644 index 25f261ce9a3..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java +++ /dev/null @@ -1,169 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import static org.openstreetmap.gui.jmapviewer.FeatureAdapter.tr; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.font.TextAttribute; -import java.awt.geom.Rectangle2D; -import java.awt.image.ImageObserver; -import java.util.HashMap; - -import org.openstreetmap.gui.jmapviewer.interfaces.Attributed; -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; - -public class AttributionSupport { - - private Attributed source; - - private Image attrImage; - private String attrTermsText; - private String attrTermsUrl; - public static final Font ATTR_FONT = new Font("Arial", Font.PLAIN, 10); - public static final Font ATTR_LINK_FONT; - - protected Rectangle attrTextBounds; - protected Rectangle attrToUBounds; - protected Rectangle attrImageBounds; - - static { - HashMap aUnderline = new HashMap<>(); - aUnderline.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); - ATTR_LINK_FONT = ATTR_FONT.deriveFont(aUnderline); - } - - public void initialize(Attributed source) { - this.source = source; - boolean requireAttr = source.requiresAttribution(); - if (requireAttr) { - attrImage = source.getAttributionImage(); - attrTermsText = source.getTermsOfUseText(); - attrTermsUrl = source.getTermsOfUseURL(); - if (attrTermsUrl != null && attrTermsText == null) { - attrTermsText = tr("Background Terms of Use"); - } - } else { - attrImage = null; - attrTermsUrl = null; - } - } - - public void paintAttribution(Graphics g, int width, int height, ICoordinate topLeft, ICoordinate bottomRight, - int zoom, ImageObserver observer) { - if (source == null || !source.requiresAttribution()) { - attrToUBounds = null; - attrImageBounds = null; - attrTextBounds = null; - return; - } - - // Draw attribution - Font font = g.getFont(); - g.setFont(ATTR_LINK_FONT); - - // Draw terms of use text - int termsTextHeight = 0; - int termsTextY = height; - - if (attrTermsText != null) { - Rectangle2D termsStringBounds = g.getFontMetrics().getStringBounds(attrTermsText, g); - int textRealHeight = (int) termsStringBounds.getHeight(); - termsTextHeight = textRealHeight - 5; - int termsTextWidth = (int) termsStringBounds.getWidth(); - termsTextY = height - termsTextHeight; - int x = 2; - int y = height - termsTextHeight; - attrToUBounds = new Rectangle(x, y-termsTextHeight, termsTextWidth, textRealHeight); - g.setColor(Color.black); - g.drawString(attrTermsText, x + 1, y + 1); - g.setColor(Color.white); - g.drawString(attrTermsText, x, y); - } else { - attrToUBounds = null; - } - - // Draw attribution logo - if (attrImage != null) { - int x = 2; - int imgWidth = attrImage.getWidth(observer); - int imgHeight = attrImage.getHeight(observer); - int y = termsTextY - imgHeight - termsTextHeight - 5; - attrImageBounds = new Rectangle(x, y, imgWidth, imgHeight); - g.drawImage(attrImage, x, y, null); - } else { - attrImageBounds = null; - } - - g.setFont(ATTR_FONT); - String attributionText = source.getAttributionText(zoom, topLeft, bottomRight); - if (attributionText == null) { - // In case attribution text has been forgotte, display URL - attributionText = source.getAttributionLinkURL(); - } - if (attributionText != null) { - Rectangle2D stringBounds = g.getFontMetrics().getStringBounds(attributionText, g); - int textHeight = (int) stringBounds.getHeight() - 5; - int x = width - (int) stringBounds.getWidth(); - int y = height - textHeight; - g.setColor(Color.black); - g.drawString(attributionText, x + 1, y + 1); - g.setColor(Color.white); - g.drawString(attributionText, x, y); - attrTextBounds = new Rectangle(x, y-textHeight, (int) stringBounds.getWidth(), (int) stringBounds.getHeight()); - } else { - attrTextBounds = null; - } - - g.setFont(font); - } - - public boolean handleAttributionCursor(Point p) { - if (attrTextBounds != null && attrTextBounds.contains(p)) { - return true; - } else if (attrImageBounds != null && attrImageBounds.contains(p)) { - return true; - } else if (attrToUBounds != null && attrToUBounds.contains(p)) { - return true; - } - return false; - } - - public boolean handleAttribution(Point p, boolean click) { - if (source == null || !source.requiresAttribution()) - return false; - - if (attrTextBounds != null && attrTextBounds.contains(p)) { - String attributionURL = source.getAttributionLinkURL(); - if (attributionURL != null) { - if (click) { - FeatureAdapter.openLink(attributionURL); - } - return true; - } - } else if (attrImageBounds != null && attrImageBounds.contains(p)) { - String attributionImageURL = source.getAttributionImageURL(); - if (attributionImageURL != null) { - if (click) { - FeatureAdapter.openLink(source.getAttributionImageURL()); - } - return true; - } - } else if (attrToUBounds != null && attrToUBounds.contains(p)) { - String termsOfUseURL = source.getTermsOfUseURL(); - if (termsOfUseURL != null) { - if (click) { - FeatureAdapter.openLink(termsOfUseURL); - } - return true; - } - } - return false; - } - -} - diff --git a/src/org/openstreetmap/gui/jmapviewer/Coordinate.java b/src/org/openstreetmap/gui/jmapviewer/Coordinate.java deleted file mode 100644 index 2afffbe06e1..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/Coordinate.java +++ /dev/null @@ -1,80 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.geom.Point2D; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Objects; - -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; - -/** - * This class encapsulates a Point2D.Double and provide access - * via lat and lon. - * - * @author Jan Peter Stotz - * - */ -public class Coordinate implements ICoordinate { - private transient Point2D.Double data; - - public Coordinate(double lat, double lon) { - data = new Point2D.Double(lon, lat); - } - - @Override - public double getLat() { - return data.y; - } - - @Override - public void setLat(double lat) { - data.y = lat; - } - - @Override - public double getLon() { - return data.x; - } - - @Override - public void setLon(double lon) { - data.x = lon; - } - - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeObject(data.x); - out.writeObject(data.y); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - data = new Point2D.Double(); - data.x = (Double) in.readObject(); - data.y = (Double) in.readObject(); - } - - @Override - public String toString() { - return "Coordinate[" + data.y + ", " + data.x + ']'; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 61 * hash + Objects.hashCode(this.data); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Coordinate other = (Coordinate) obj; - return Objects.equals(this.data, other.data); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java b/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java deleted file mode 100644 index 78108695bfa..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java +++ /dev/null @@ -1,198 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.Point; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.util.Locale; - -/** - * Default map controller which implements map moving by pressing the right - * mouse button and zooming by double click or by mouse wheel. - * - * @author Jan Peter Stotz - * - */ -public class DefaultMapController extends JMapController implements MouseListener, MouseMotionListener, -MouseWheelListener { - - private static final int MOUSE_BUTTONS_MASK = MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK - | MouseEvent.BUTTON2_DOWN_MASK; - - private static final int MAC_MOUSE_BUTTON3_MASK = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK; - - private Point lastDragPoint; - - private boolean isMoving; - - private boolean movementEnabled = true; - - private int movementMouseButton = MouseEvent.BUTTON3; - private int movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; - - private boolean wheelZoomEnabled = true; - private boolean doubleClickZoomEnabled = true; - - /** - * Constructs a new {@code DefaultMapController}. - * @param map map panel - */ - public DefaultMapController(JMapViewer map) { - super(map); - } - - @Override - public void mouseDragged(MouseEvent e) { - if (!movementEnabled || !isMoving) - return; - // Is only the selected mouse button pressed? - if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask - || (isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK)) { - Point p = e.getPoint(); - if (lastDragPoint != null) { - int diffx = lastDragPoint.x - p.x; - int diffy = lastDragPoint.y - p.y; - map.moveMap(diffx, diffy); - } - lastDragPoint = p; - } - } - - @Override - public void mouseClicked(MouseEvent e) { - if (doubleClickZoomEnabled && e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { - map.zoomIn(e.getPoint()); - } - } - - @Override - public void mousePressed(MouseEvent e) { - if (e.getButton() == movementMouseButton || (isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK)) { - lastDragPoint = null; - isMoving = true; - } - } - - @Override - public void mouseReleased(MouseEvent e) { - if (e.getButton() == movementMouseButton || (isPlatformOsx() && e.getButton() == MouseEvent.BUTTON1)) { - lastDragPoint = null; - isMoving = false; - } - } - - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - if (wheelZoomEnabled) { - int rotation = JMapViewer.zoomReverseWheel ? -e.getWheelRotation() : e.getWheelRotation(); - map.setZoom(map.getZoom() - rotation, e.getPoint()); - } - } - - /** - * Determines if the map pane is allowed to be moved using the mouse - * @return {@code true} to allow the map pane to be moved using the mouse - */ - public boolean isMovementEnabled() { - return movementEnabled; - } - - /** - * Enables or disables that the map pane can be moved using the mouse. - * - * @param movementEnabled {@code true} to allow the map pane to be moved using the mouse - */ - public void setMovementEnabled(boolean movementEnabled) { - this.movementEnabled = movementEnabled; - } - - public int getMovementMouseButton() { - return movementMouseButton; - } - - /** - * Sets the mouse button that is used for moving the map. Possible values are: - *
    - *
  • {@link MouseEvent#BUTTON1} (left mouse button)
  • - *
  • {@link MouseEvent#BUTTON2} (middle mouse button)
  • - *
  • {@link MouseEvent#BUTTON3} (right mouse button)
  • - *
- * - * @param movementMouseButton the mouse button that is used for moving the map - */ - public void setMovementMouseButton(int movementMouseButton) { - this.movementMouseButton = movementMouseButton; - switch (movementMouseButton) { - case MouseEvent.BUTTON1: - movementMouseButtonMask = MouseEvent.BUTTON1_DOWN_MASK; - break; - case MouseEvent.BUTTON2: - movementMouseButtonMask = MouseEvent.BUTTON2_DOWN_MASK; - break; - case MouseEvent.BUTTON3: - movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; - break; - default: - throw new RuntimeException("Unsupported button"); - } - } - - public boolean isWheelZoomEnabled() { - return wheelZoomEnabled; - } - - public void setWheelZoomEnabled(boolean wheelZoomEnabled) { - this.wheelZoomEnabled = wheelZoomEnabled; - } - - public boolean isDoubleClickZoomEnabled() { - return doubleClickZoomEnabled; - } - - public void setDoubleClickZoomEnabled(boolean doubleClickZoomEnabled) { - this.doubleClickZoomEnabled = doubleClickZoomEnabled; - } - - @Override - public void mouseEntered(MouseEvent e) { - // do nothing - } - - @Override - public void mouseExited(MouseEvent e) { - // do nothing - } - - @Override - public void mouseMoved(MouseEvent e) { - // Mac OSX simulates with ctrl + mouse 1 the second mouse button hence no dragging events get fired. - // - if (isPlatformOsx()) { - if (!movementEnabled || !isMoving) - return; - // Is only the selected mouse button pressed? - if (e.getModifiersEx() == MouseEvent.CTRL_DOWN_MASK) { - Point p = e.getPoint(); - if (lastDragPoint != null) { - int diffx = lastDragPoint.x - p.x; - int diffy = lastDragPoint.y - p.y; - map.moveMap(diffx, diffy); - } - lastDragPoint = p; - } - } - } - - /** - * Replies true if we are currently running on OSX - * - * @return true if we are currently running on OSX - */ - public static boolean isPlatformOsx() { - String os = System.getProperty("os.name"); - return os != null && os.toLowerCase(Locale.ENGLISH).startsWith("mac os x"); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/Demo.java b/src/org/openstreetmap/gui/jmapviewer/Demo.java deleted file mode 100644 index 44e6c7e25aa..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/Demo.java +++ /dev/null @@ -1,261 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.BorderLayout; -import java.awt.Cursor; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; - -import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent; -import org.openstreetmap.gui.jmapviewer.interfaces.JMapViewerEventListener; -import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon; -import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; -import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; -import org.openstreetmap.gui.jmapviewer.tilesources.BingAerialTileSource; -import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource; - -/** - * Demonstrates the usage of {@link JMapViewer} - * - * @author Jan Peter Stotz - * - */ -public class Demo extends JFrame implements JMapViewerEventListener { - - private static final long serialVersionUID = 1L; - - private final JMapViewerTree treeMap; - - private final JLabel zoomLabel; - private final JLabel zoomValue; - - private final JLabel mperpLabelName; - private final JLabel mperpLabelValue; - - /** - * Constructs the {@code Demo}. - */ - public Demo() { - super("JMapViewer Demo"); - setSize(400, 400); - - treeMap = new JMapViewerTree("Zones"); - - // Listen to the map viewer for user operations so components will - // receive events and update - map().addJMVListener(this); - - setLayout(new BorderLayout()); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setExtendedState(JFrame.MAXIMIZED_BOTH); - JPanel panel = new JPanel(new BorderLayout()); - JPanel panelTop = new JPanel(); - JPanel panelBottom = new JPanel(); - JPanel helpPanel = new JPanel(); - - mperpLabelName = new JLabel("Meters/Pixels: "); - mperpLabelValue = new JLabel(String.format("%s", map().getMeterPerPixel())); - - zoomLabel = new JLabel("Zoom: "); - zoomValue = new JLabel(String.format("%s", map().getZoom())); - - add(panel, BorderLayout.NORTH); - add(helpPanel, BorderLayout.SOUTH); - panel.add(panelTop, BorderLayout.NORTH); - panel.add(panelBottom, BorderLayout.SOUTH); - JLabel helpLabel = new JLabel("Use right mouse button to move,\n " - + "left double click or mouse wheel to zoom."); - helpPanel.add(helpLabel); - JButton button = new JButton("setDisplayToFitMapMarkers"); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setDisplayToFitMapMarkers(); - } - }); - JComboBox tileSourceSelector = new JComboBox<>(new TileSource[] { - new OsmTileSource.Mapnik(), - new OsmTileSource.CycleMap(), - new BingAerialTileSource(), - }); - tileSourceSelector.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - map().setTileSource((TileSource) e.getItem()); - } - }); - JComboBox tileLoaderSelector; - tileLoaderSelector = new JComboBox<>(new TileLoader[] {new OsmTileLoader(map())}); - tileLoaderSelector.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - map().setTileLoader((TileLoader) e.getItem()); - } - }); - map().setTileLoader((TileLoader) tileLoaderSelector.getSelectedItem()); - panelTop.add(tileSourceSelector); - panelTop.add(tileLoaderSelector); - final JCheckBox showMapMarker = new JCheckBox("Map markers visible"); - showMapMarker.setSelected(map().getMapMarkersVisible()); - showMapMarker.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setMapMarkerVisible(showMapMarker.isSelected()); - } - }); - panelBottom.add(showMapMarker); - /// - final JCheckBox showTreeLayers = new JCheckBox("Tree Layers visible"); - showTreeLayers.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - treeMap.setTreeVisible(showTreeLayers.isSelected()); - } - }); - panelBottom.add(showTreeLayers); - /// - final JCheckBox showToolTip = new JCheckBox("ToolTip visible"); - showToolTip.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setToolTipText(null); - } - }); - panelBottom.add(showToolTip); - /// - final JCheckBox showTileGrid = new JCheckBox("Tile grid visible"); - showTileGrid.setSelected(map().isTileGridVisible()); - showTileGrid.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setTileGridVisible(showTileGrid.isSelected()); - } - }); - panelBottom.add(showTileGrid); - final JCheckBox showZoomControls = new JCheckBox("Show zoom controls"); - showZoomControls.setSelected(map().getZoomControlsVisible()); - showZoomControls.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setZoomContolsVisible(showZoomControls.isSelected()); - } - }); - panelBottom.add(showZoomControls); - final JCheckBox scrollWrapEnabled = new JCheckBox("Scrollwrap enabled"); - scrollWrapEnabled.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setScrollWrapEnabled(scrollWrapEnabled.isSelected()); - } - }); - panelBottom.add(scrollWrapEnabled); - panelBottom.add(button); - - panelTop.add(zoomLabel); - panelTop.add(zoomValue); - panelTop.add(mperpLabelName); - panelTop.add(mperpLabelValue); - - add(treeMap, BorderLayout.CENTER); - - // - LayerGroup germanyGroup = new LayerGroup("Germany"); - Layer germanyWestLayer = germanyGroup.addLayer("Germany West"); - Layer germanyEastLayer = germanyGroup.addLayer("Germany East"); - MapMarkerDot eberstadt = new MapMarkerDot(germanyEastLayer, "Eberstadt", 49.814284999, 8.642065999); - MapMarkerDot ebersheim = new MapMarkerDot(germanyWestLayer, "Ebersheim", 49.91, 8.24); - MapMarkerDot empty = new MapMarkerDot(germanyEastLayer, 49.71, 8.64); - MapMarkerDot darmstadt = new MapMarkerDot(germanyEastLayer, "Darmstadt", 49.8588, 8.643); - map().addMapMarker(eberstadt); - map().addMapMarker(ebersheim); - map().addMapMarker(empty); - Layer franceLayer = treeMap.addLayer("France"); - map().addMapMarker(new MapMarkerDot(franceLayer, "La Gallerie", 48.71, -1)); - map().addMapMarker(new MapMarkerDot(43.604, 1.444)); - map().addMapMarker(new MapMarkerCircle(53.343, -6.267, 0.666)); - map().addMapRectangle(new MapRectangleImpl(new Coordinate(53.343, -6.267), new Coordinate(43.604, 1.444))); - map().addMapMarker(darmstadt); - treeMap.addLayer(germanyWestLayer); - treeMap.addLayer(germanyEastLayer); - - MapPolygon bermudas = new MapPolygonImpl(c(49, 1), c(45, 10), c(40, 5)); - map().addMapPolygon(bermudas); - map().addMapPolygon(new MapPolygonImpl(germanyEastLayer, "Riedstadt", ebersheim, darmstadt, eberstadt, empty)); - - map().addMapMarker(new MapMarkerCircle(germanyWestLayer, "North of Suisse", new Coordinate(48, 7), .5)); - Layer spain = treeMap.addLayer("Spain"); - map().addMapMarker(new MapMarkerCircle(spain, "La Garena", new Coordinate(40.4838, -3.39), .002)); - spain.setVisible(Boolean.FALSE); - - Layer wales = treeMap.addLayer("UK"); - map().addMapRectangle(new MapRectangleImpl(wales, "Wales", c(53.35, -4.57), c(51.64, -2.63))); - - // map.setDisplayPosition(new Coordinate(49.807, 8.6), 11); - // map.setTileGridVisible(true); - - map().addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - map().getAttribution().handleAttribution(e.getPoint(), true); - } - } - }); - - map().addMouseMotionListener(new MouseAdapter() { - @Override - public void mouseMoved(MouseEvent e) { - Point p = e.getPoint(); - boolean cursorHand = map().getAttribution().handleAttributionCursor(p); - if (cursorHand) { - map().setCursor(new Cursor(Cursor.HAND_CURSOR)); - } else { - map().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - if (showToolTip.isSelected()) map().setToolTipText(map().getPosition(p).toString()); - } - }); - } - - private JMapViewer map() { - return treeMap.getViewer(); - } - - private static Coordinate c(double lat, double lon) { - return new Coordinate(lat, lon); - } - - /** - * @param args Main program arguments - */ - public static void main(String[] args) { - new Demo().setVisible(true); - } - - private void updateZoomParameters() { - if (mperpLabelValue != null) - mperpLabelValue.setText(String.format("%s", map().getMeterPerPixel())); - if (zoomValue != null) - zoomValue.setText(String.format("%s", map().getZoom())); - } - - @Override - public void processCommand(JMVCommandEvent command) { - if (command.getCommand().equals(JMVCommandEvent.COMMAND.ZOOM) || - command.getCommand().equals(JMVCommandEvent.COMMAND.MOVE)) { - updateZoomParameters(); - } - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java b/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java deleted file mode 100644 index eb9f9b70cf9..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java +++ /dev/null @@ -1,88 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.Desktop; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.text.MessageFormat; -import java.util.logging.Logger; - -public final class FeatureAdapter { - - private static BrowserAdapter browserAdapter = new DefaultBrowserAdapter(); - private static TranslationAdapter translationAdapter = new DefaultTranslationAdapter(); - private static LoggingAdapter loggingAdapter = new DefaultLoggingAdapter(); - - private FeatureAdapter() { - // private constructor for utility classes - } - - public interface BrowserAdapter { - void openLink(String url); - } - - public interface TranslationAdapter { - String tr(String text, Object... objects); - // TODO: more i18n functions - } - - public interface LoggingAdapter { - Logger getLogger(String name); - } - - public static void registerBrowserAdapter(BrowserAdapter browserAdapter) { - FeatureAdapter.browserAdapter = browserAdapter; - } - - public static void registerTranslationAdapter(TranslationAdapter translationAdapter) { - FeatureAdapter.translationAdapter = translationAdapter; - } - - public static void registerLoggingAdapter(LoggingAdapter loggingAdapter) { - FeatureAdapter.loggingAdapter = loggingAdapter; - } - - public static void openLink(String url) { - browserAdapter.openLink(url); - } - - public static String tr(String text, Object... objects) { - return translationAdapter.tr(text, objects); - } - - public static Logger getLogger(String name) { - return loggingAdapter.getLogger(name); - } - - public static class DefaultBrowserAdapter implements BrowserAdapter { - @Override - public void openLink(String url) { - if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { - try { - Desktop.getDesktop().browse(new URI(url)); - } catch (IOException e) { - e.printStackTrace(); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - } else { - System.err.println(tr("Opening link not supported on current platform (''{0}'')", url)); - } - } - } - - public static class DefaultTranslationAdapter implements TranslationAdapter { - @Override - public String tr(String text, Object... objects) { - return MessageFormat.format(text, objects); - } - } - - public static class DefaultLoggingAdapter implements LoggingAdapter { - @Override - public Logger getLogger(String name) { - return Logger.getLogger(name); - } - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/JMapController.java b/src/org/openstreetmap/gui/jmapviewer/JMapController.java deleted file mode 100644 index 8de5300a1c5..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/JMapController.java +++ /dev/null @@ -1,34 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.event.MouseWheelListener; - -/** - * Abstract base class for all mouse controller implementations. For - * implementing your own controller create a class that derives from this one - * and implements one or more of the following interfaces: - *
    - *
  • {@link MouseListener}
  • - *
  • {@link MouseMotionListener}
  • - *
  • {@link MouseWheelListener}
  • - *
- * - * @author Jan Peter Stotz - */ -public abstract class JMapController { - - protected JMapViewer map; - - public JMapController(JMapViewer map) { - this.map = map; - if (this instanceof MouseListener) - map.addMouseListener((MouseListener) this); - if (this instanceof MouseWheelListener) - map.addMouseWheelListener((MouseWheelListener) this); - if (this instanceof MouseMotionListener) - map.addMouseMotionListener((MouseMotionListener) this); - } - -} diff --git a/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java b/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java deleted file mode 100644 index 2cd2f8425d0..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java +++ /dev/null @@ -1,1279 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Insets; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JPanel; -import javax.swing.JSlider; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.event.EventListenerList; - -import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent; -import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent.COMMAND; -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; -import org.openstreetmap.gui.jmapviewer.interfaces.JMapViewerEventListener; -import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker; -import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon; -import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle; -import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; -import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; -import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; -import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; -import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource; - -/** - * Provides a simple panel that displays pre-rendered map tiles loaded from the - * OpenStreetMap project. - * - * @author Jan Peter Stotz - * @author Jason Huntley - */ -public class JMapViewer extends JPanel implements TileLoaderListener { - - private static final long serialVersionUID = 1L; - - /** whether debug mode is enabled or not */ - public static boolean debug; - - /** option to reverse zoom direction with mouse wheel */ - public static boolean zoomReverseWheel; - - /** - * Vectors for clock-wise tile painting - */ - private static final Point[] move = {new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1)}; - - /** Maximum zoom level */ - public static final int MAX_ZOOM = 22; - /** Minimum zoom level */ - public static final int MIN_ZOOM = 0; - - protected transient List mapMarkerList; - protected transient List mapRectangleList; - protected transient List mapPolygonList; - - protected boolean mapMarkersVisible; - protected boolean mapRectanglesVisible; - protected boolean mapPolygonsVisible; - - protected boolean tileGridVisible; - protected boolean scrollWrapEnabled; - - protected transient TileController tileController; - - /** - * x- and y-position of the center of this map-panel on the world map - * denoted in screen pixel regarding the current zoom level. - */ - protected Point center; - - /** - * Current zoom level - */ - protected int zoom; - - protected JSlider zoomSlider; - protected JButton zoomInButton; - protected JButton zoomOutButton; - - /** - * Apparence of zoom controls. - */ - public enum ZOOM_BUTTON_STYLE { - /** Zoom buttons are displayed horizontally (default) */ - HORIZONTAL, - /** Zoom buttons are displayed vertically */ - VERTICAL - } - - protected ZOOM_BUTTON_STYLE zoomButtonStyle; - - protected transient TileSource tileSource; - - protected transient AttributionSupport attribution = new AttributionSupport(); - - protected EventListenerList evtListenerList = new EventListenerList(); - - /** - * Creates a standard {@link JMapViewer} instance that can be controlled via - * mouse: hold right mouse button for moving, double click left mouse button - * or use mouse wheel for zooming. Loaded tiles are stored in a - * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for - * retrieving the tiles. - */ - public JMapViewer() { - this(new MemoryTileCache()); - new DefaultMapController(this); - } - - /** - * Creates a new {@link JMapViewer} instance. - * @param tileCache The cache where to store tiles - * @param downloadThreadCount not used anymore - * @deprecated use {@link #JMapViewer(TileCache)} - */ - @Deprecated - public JMapViewer(TileCache tileCache, int downloadThreadCount) { - this(tileCache); - } - - /** - * Creates a new {@link JMapViewer} instance. - * @param tileCache The cache where to store tiles - * - */ - public JMapViewer(TileCache tileCache) { - tileSource = new OsmTileSource.Mapnik(); - tileController = new TileController(tileSource, tileCache, this); - mapMarkerList = Collections.synchronizedList(new ArrayList()); - mapPolygonList = Collections.synchronizedList(new ArrayList()); - mapRectangleList = Collections.synchronizedList(new ArrayList()); - mapMarkersVisible = true; - mapRectanglesVisible = true; - mapPolygonsVisible = true; - tileGridVisible = false; - setLayout(null); - initializeZoomSlider(); - setMinimumSize(new Dimension(tileSource.getTileSize(), tileSource.getTileSize())); - setPreferredSize(new Dimension(400, 400)); - setDisplayPosition(new Coordinate(50, 9), 3); - } - - @Override - public String getToolTipText(MouseEvent event) { - return super.getToolTipText(event); - } - - protected void initializeZoomSlider() { - zoomSlider = new JSlider(MIN_ZOOM, tileController.getTileSource().getMaxZoom()); - zoomSlider.setOrientation(JSlider.VERTICAL); - zoomSlider.setBounds(10, 10, 30, 150); - zoomSlider.setOpaque(false); - zoomSlider.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - setZoom(zoomSlider.getValue()); - } - }); - zoomSlider.setFocusable(false); - add(zoomSlider); - int size = 18; - URL url = JMapViewer.class.getResource("images/plus.png"); - if (url != null) { - ImageIcon icon = new ImageIcon(url); - zoomInButton = new JButton(icon); - } else { - zoomInButton = new JButton("+"); - zoomInButton.setFont(new Font("sansserif", Font.BOLD, 9)); - zoomInButton.setMargin(new Insets(0, 0, 0, 0)); - } - zoomInButton.setBounds(4, 155, size, size); - zoomInButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - zoomIn(); - } - }); - zoomInButton.setFocusable(false); - add(zoomInButton); - url = JMapViewer.class.getResource("images/minus.png"); - if (url != null) { - ImageIcon icon = new ImageIcon(url); - zoomOutButton = new JButton(icon); - } else { - zoomOutButton = new JButton("-"); - zoomOutButton.setFont(new Font("sansserif", Font.BOLD, 9)); - zoomOutButton.setMargin(new Insets(0, 0, 0, 0)); - } - zoomOutButton.setBounds(8 + size, 155, size, size); - zoomOutButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - zoomOut(); - } - }); - zoomOutButton.setFocusable(false); - add(zoomOutButton); - } - - /** - * Changes the map pane so that it is centered on the specified coordinate - * at the given zoom level. - * - * @param to - * specified coordinate - * @param zoom - * {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM} - */ - public void setDisplayPosition(ICoordinate to, int zoom) { - setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), to, zoom); - } - - /** - * Changes the map pane so that the specified coordinate at the given zoom - * level is displayed on the map at the screen coordinate - * mapPoint. - * - * @param mapPoint - * point on the map denoted in pixels where the coordinate should - * be set - * @param to - * specified coordinate - * @param zoom - * {@link #MIN_ZOOM} <= zoom level <= - * {@link TileSource#getMaxZoom()} - */ - public void setDisplayPosition(Point mapPoint, ICoordinate to, int zoom) { - Point p = tileSource.latLonToXY(to, zoom); - setDisplayPosition(mapPoint, p.x, p.y, zoom); - } - - /** - * Sets the display position. - * @param x X coordinate - * @param y Y coordinate - * @param zoom zoom level, between {@link #MIN_ZOOM} and {@link #MAX_ZOOM} - */ - public void setDisplayPosition(int x, int y, int zoom) { - setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, zoom); - } - - /** - * Sets the display position. - * @param mapPoint map point - * @param x X coordinate - * @param y Y coordinate - * @param zoom zoom level, between {@link #MIN_ZOOM} and {@link #MAX_ZOOM} - */ - public void setDisplayPosition(Point mapPoint, int x, int y, int zoom) { - if (zoom > tileController.getTileSource().getMaxZoom() || zoom < MIN_ZOOM) - return; - - // Get the plain tile number - Point p = new Point(); - p.x = x - mapPoint.x + getWidth() / 2; - p.y = y - mapPoint.y + getHeight() / 2; - center = p; - setIgnoreRepaint(true); - try { - int oldZoom = this.zoom; - this.zoom = zoom; - if (oldZoom != zoom) { - zoomChanged(oldZoom); - } - if (zoomSlider.getValue() != zoom) { - zoomSlider.setValue(zoom); - } - } finally { - setIgnoreRepaint(false); - repaint(); - } - } - - /** - * Sets the displayed map pane and zoom level so that all chosen map elements are visible. - * @param markers whether to consider markers - * @param rectangles whether to consider rectangles - * @param polygons whether to consider polygons - */ - public void setDisplayToFitMapElements(boolean markers, boolean rectangles, boolean polygons) { - int nbElemToCheck = 0; - if (markers && mapMarkerList != null) - nbElemToCheck += mapMarkerList.size(); - if (rectangles && mapRectangleList != null) - nbElemToCheck += mapRectangleList.size(); - if (polygons && mapPolygonList != null) - nbElemToCheck += mapPolygonList.size(); - if (nbElemToCheck == 0) - return; - - int xMin = Integer.MAX_VALUE; - int yMin = Integer.MAX_VALUE; - int xMax = Integer.MIN_VALUE; - int yMax = Integer.MIN_VALUE; - int mapZoomMax = tileController.getTileSource().getMaxZoom(); - - if (markers && mapMarkerList != null) { - synchronized (this) { - for (MapMarker marker : mapMarkerList) { - if (marker.isVisible()) { - Point p = tileSource.latLonToXY(marker.getCoordinate(), mapZoomMax); - xMax = Math.max(xMax, p.x); - yMax = Math.max(yMax, p.y); - xMin = Math.min(xMin, p.x); - yMin = Math.min(yMin, p.y); - } - } - } - } - - if (rectangles && mapRectangleList != null) { - synchronized (this) { - for (MapRectangle rectangle : mapRectangleList) { - if (rectangle.isVisible()) { - Point bottomRight = tileSource.latLonToXY(rectangle.getBottomRight(), mapZoomMax); - Point topLeft = tileSource.latLonToXY(rectangle.getTopLeft(), mapZoomMax); - xMax = Math.max(xMax, bottomRight.x); - yMax = Math.max(yMax, topLeft.y); - xMin = Math.min(xMin, topLeft.x); - yMin = Math.min(yMin, bottomRight.y); - } - } - } - } - - if (polygons && mapPolygonList != null) { - synchronized (this) { - for (MapPolygon polygon : mapPolygonList) { - if (polygon.isVisible()) { - for (ICoordinate c : polygon.getPoints()) { - Point p = tileSource.latLonToXY(c, mapZoomMax); - xMax = Math.max(xMax, p.x); - yMax = Math.max(yMax, p.y); - xMin = Math.min(xMin, p.x); - yMin = Math.min(yMin, p.y); - } - } - } - } - } - - int height = Math.max(0, getHeight()); - int width = Math.max(0, getWidth()); - int newZoom = mapZoomMax; - int x = xMax - xMin; - int y = yMax - yMin; - while (x > width || y > height) { - newZoom--; - x >>= 1; - y >>= 1; - } - x = xMin + (xMax - xMin) / 2; - y = yMin + (yMax - yMin) / 2; - int z = 1 << (mapZoomMax - newZoom); - x /= z; - y /= z; - setDisplayPosition(x, y, newZoom); - } - - /** - * Sets the displayed map pane and zoom level so that all map markers are visible. - */ - public void setDisplayToFitMapMarkers() { - setDisplayToFitMapElements(true, false, false); - } - - /** - * Sets the displayed map pane and zoom level so that all map rectangles are visible. - */ - public void setDisplayToFitMapRectangles() { - setDisplayToFitMapElements(false, true, false); - } - - /** - * Sets the displayed map pane and zoom level so that all map polygons are visible. - */ - public void setDisplayToFitMapPolygons() { - setDisplayToFitMapElements(false, false, true); - } - - /** - * @return the center - */ - public Point getCenter() { - return center; - } - - /** - * @param center the center to set - */ - public void setCenter(Point center) { - this.center = center; - } - - /** - * Calculates the latitude/longitude coordinate of the center of the - * currently displayed map area. - * - * @return latitude / longitude - */ - public ICoordinate getPosition() { - return tileSource.xyToLatLon(center, zoom); - } - - /** - * Converts the relative pixel coordinate (regarding the top left corner of - * the displayed map) into a latitude / longitude coordinate - * - * @param mapPoint - * relative pixel coordinate regarding the top left corner of the - * displayed map - * @return latitude / longitude - */ - public ICoordinate getPosition(Point mapPoint) { - return getPosition(mapPoint.x, mapPoint.y); - } - - /** - * Converts the relative pixel coordinate (regarding the top left corner of - * the displayed map) into a latitude / longitude coordinate - * - * @param mapPointX X coordinate - * @param mapPointY Y coordinate - * @return latitude / longitude - */ - public ICoordinate getPosition(int mapPointX, int mapPointY) { - int x = center.x + mapPointX - getWidth() / 2; - int y = center.y + mapPointY - getHeight() / 2; - return tileSource.xyToLatLon(x, y, zoom); - } - - /** - * Calculates the position on the map of a given coordinate - * - * @param lat latitude - * @param lon longitude - * @param checkOutside check if the point is outside the displayed area - * @return point on the map or null if the point is not visible - * and checkOutside set to true - */ - public Point getMapPosition(double lat, double lon, boolean checkOutside) { - Point p = tileSource.latLonToXY(lat, lon, zoom); - p.translate(-(center.x - getWidth() / 2), -(center.y - getHeight() /2)); - - if (checkOutside && (p.x < 0 || p.y < 0 || p.x > getWidth() || p.y > getHeight())) { - return null; - } - return p; - } - - /** - * Calculates the position on the map of a given coordinate - * - * @param lat latitude - * @param lon longitude - * @return point on the map or null if the point is not visible - */ - public Point getMapPosition(double lat, double lon) { - return getMapPosition(lat, lon, true); - } - - /** - * Calculates the position on the map of a given coordinate - * - * @param lat Latitude - * @param lon longitude - * @param offset Offset respect Latitude - * @param checkOutside check if the point is outside the displayed area - * @return Integer the radius in pixels - */ - public Integer getLatOffset(double lat, double lon, double offset, boolean checkOutside) { - Point p = tileSource.latLonToXY(lat + offset, lon, zoom); - int y = p.y - (center.y - getHeight() / 2); - if (checkOutside && (y < 0 || y > getHeight())) { - return null; - } - return y; - } - - /** - * Calculates the position on the map of a given coordinate - * - * @param marker MapMarker object that define the x,y coordinate - * @param p coordinate - * @return Integer the radius in pixels - */ - public Integer getRadius(MapMarker marker, Point p) { - if (marker.getMarkerStyle() == MapMarker.STYLE.FIXED) - return (int) marker.getRadius(); - else if (p != null) { - Integer radius = getLatOffset(marker.getLat(), marker.getLon(), marker.getRadius(), false); - radius = radius == null ? null : p.y - radius; - return radius; - } else - return null; - } - - /** - * Calculates the position on the map of a given coordinate - * - * @param coord coordinate - * @return point on the map or null if the point is not visible - */ - public Point getMapPosition(Coordinate coord) { - if (coord != null) - return getMapPosition(coord.getLat(), coord.getLon()); - else - return null; - } - - /** - * Calculates the position on the map of a given coordinate - * - * @param coord coordinate - * @param checkOutside check if the point is outside the displayed area - * @return point on the map or null if the point is not visible - * and checkOutside set to true - */ - public Point getMapPosition(ICoordinate coord, boolean checkOutside) { - if (coord != null) - return getMapPosition(coord.getLat(), coord.getLon(), checkOutside); - else - return null; - } - - /** - * Gets the meter per pixel. - * - * @return the meter per pixel - */ - public double getMeterPerPixel() { - Point origin = new Point(5, 5); - Point center = new Point(getWidth() / 2, getHeight() / 2); - - double pDistance = center.distance(origin); - - ICoordinate originCoord = getPosition(origin); - ICoordinate centerCoord = getPosition(center); - - double mDistance = tileSource.getDistance(originCoord.getLat(), originCoord.getLon(), - centerCoord.getLat(), centerCoord.getLon()); - - return mDistance / pDistance; - } - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - - int iMove = 0; - - int tilesize = tileSource.getTileSize(); - int tilex = center.x / tilesize; - int tiley = center.y / tilesize; - int offsx = center.x % tilesize; - int offsy = center.y % tilesize; - - int w2 = getWidth() / 2; - int h2 = getHeight() / 2; - int posx = w2 - offsx; - int posy = h2 - offsy; - - int diffLeft = offsx; - int diffRight = tilesize - offsx; - int diffTop = offsy; - int diffBottom = tilesize - offsy; - - boolean startLeft = diffLeft < diffRight; - boolean startTop = diffTop < diffBottom; - - if (startTop) { - if (startLeft) { - iMove = 2; - } else { - iMove = 3; - } - } else { - if (startLeft) { - iMove = 1; - } else { - iMove = 0; - } - } // calculate the visibility borders - int xMin = -tilesize; - int yMin = -tilesize; - int xMax = getWidth(); - int yMax = getHeight(); - - // calculate the length of the grid (number of squares per edge) - int gridLength = 1 << zoom; - - // paint the tiles in a spiral, starting from center of the map - boolean painted = true; - int x = 0; - while (painted) { - painted = false; - for (int i = 0; i < 4; i++) { - if (i % 2 == 0) { - x++; - } - for (int j = 0; j < x; j++) { - if (xMin <= posx && posx <= xMax && yMin <= posy && posy <= yMax) { - // tile is visible - Tile tile; - if (scrollWrapEnabled) { - // in case tilex is out of bounds, grab the tile to use for wrapping - int tilexWrap = ((tilex % gridLength) + gridLength) % gridLength; - tile = tileController.getTile(tilexWrap, tiley, zoom); - } else { - tile = tileController.getTile(tilex, tiley, zoom); - } - if (tile != null) { - tile.paint(g, posx, posy, tilesize, tilesize); - if (tileGridVisible) { - g.drawRect(posx, posy, tilesize, tilesize); - } - } - painted = true; - } - Point p = move[iMove]; - posx += p.x * tilesize; - posy += p.y * tilesize; - tilex += p.x; - tiley += p.y; - } - iMove = (iMove + 1) % move.length; - } - } - // outer border of the map - int mapSize = tilesize << zoom; - if (scrollWrapEnabled) { - g.drawLine(0, h2 - center.y, getWidth(), h2 - center.y); - g.drawLine(0, h2 - center.y + mapSize, getWidth(), h2 - center.y + mapSize); - } else { - g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize); - } - - // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20); - - // keep x-coordinates from growing without bound if scroll-wrap is enabled - if (scrollWrapEnabled) { - center.x = center.x % mapSize; - } - - if (mapPolygonsVisible && mapPolygonList != null) { - synchronized (this) { - for (MapPolygon polygon : mapPolygonList) { - if (polygon.isVisible()) - paintPolygon(g, polygon); - } - } - } - - if (mapRectanglesVisible && mapRectangleList != null) { - synchronized (this) { - for (MapRectangle rectangle : mapRectangleList) { - if (rectangle.isVisible()) - paintRectangle(g, rectangle); - } - } - } - - if (mapMarkersVisible && mapMarkerList != null) { - synchronized (this) { - for (MapMarker marker : mapMarkerList) { - if (marker.isVisible()) - paintMarker(g, marker); - } - } - } - - attribution.paintAttribution(g, getWidth(), getHeight(), getPosition(0, 0), getPosition(getWidth(), getHeight()), zoom, this); - } - - /** - * Paint a single marker. - * @param g Graphics used for painting - * @param marker marker to paint - */ - protected void paintMarker(Graphics g, MapMarker marker) { - Point p = getMapPosition(marker.getLat(), marker.getLon(), marker.getMarkerStyle() == MapMarker.STYLE.FIXED); - Integer radius = getRadius(marker, p); - if (scrollWrapEnabled) { - int tilesize = tileSource.getTileSize(); - int mapSize = tilesize << zoom; - if (p == null) { - p = getMapPosition(marker.getLat(), marker.getLon(), false); - radius = getRadius(marker, p); - } - marker.paint(g, p, radius); - int xSave = p.x; - int xWrap = xSave; - // overscan of 15 allows up to 30-pixel markers to gracefully scroll off the edge of the panel - while ((xWrap -= mapSize) >= -15) { - p.x = xWrap; - marker.paint(g, p, radius); - } - xWrap = xSave; - while ((xWrap += mapSize) <= getWidth() + 15) { - p.x = xWrap; - marker.paint(g, p, radius); - } - } else { - if (p != null) { - marker.paint(g, p, radius); - } - } - } - - /** - * Paint a single rectangle. - * @param g Graphics used for painting - * @param rectangle rectangle to paint - */ - protected void paintRectangle(Graphics g, MapRectangle rectangle) { - Coordinate topLeft = rectangle.getTopLeft(); - Coordinate bottomRight = rectangle.getBottomRight(); - if (topLeft != null && bottomRight != null) { - Point pTopLeft = getMapPosition(topLeft, false); - Point pBottomRight = getMapPosition(bottomRight, false); - if (pTopLeft != null && pBottomRight != null) { - rectangle.paint(g, pTopLeft, pBottomRight); - if (scrollWrapEnabled) { - int tilesize = tileSource.getTileSize(); - int mapSize = tilesize << zoom; - int xTopLeftSave = pTopLeft.x; - int xTopLeftWrap = xTopLeftSave; - int xBottomRightSave = pBottomRight.x; - int xBottomRightWrap = xBottomRightSave; - while ((xBottomRightWrap -= mapSize) >= 0) { - xTopLeftWrap -= mapSize; - pTopLeft.x = xTopLeftWrap; - pBottomRight.x = xBottomRightWrap; - rectangle.paint(g, pTopLeft, pBottomRight); - } - xTopLeftWrap = xTopLeftSave; - xBottomRightWrap = xBottomRightSave; - while ((xTopLeftWrap += mapSize) <= getWidth()) { - xBottomRightWrap += mapSize; - pTopLeft.x = xTopLeftWrap; - pBottomRight.x = xBottomRightWrap; - rectangle.paint(g, pTopLeft, pBottomRight); - } - } - } - } - } - - /** - * Paint a single polygon. - * @param g Graphics used for painting - * @param polygon polygon to paint - */ - protected void paintPolygon(Graphics g, MapPolygon polygon) { - List coords = polygon.getPoints(); - if (coords != null && coords.size() >= 3) { - List points = new ArrayList<>(); - for (ICoordinate c : coords) { - Point p = getMapPosition(c, false); - if (p == null) { - return; - } - points.add(p); - } - polygon.paint(g, points); - if (scrollWrapEnabled) { - int tilesize = tileSource.getTileSize(); - int mapSize = tilesize << zoom; - List pointsWrapped = new ArrayList<>(points); - boolean keepWrapping = true; - while (keepWrapping) { - for (Point p : pointsWrapped) { - p.x -= mapSize; - if (p.x < 0) { - keepWrapping = false; - } - } - polygon.paint(g, pointsWrapped); - } - pointsWrapped = new ArrayList<>(points); - keepWrapping = true; - while (keepWrapping) { - for (Point p : pointsWrapped) { - p.x += mapSize; - if (p.x > getWidth()) { - keepWrapping = false; - } - } - polygon.paint(g, pointsWrapped); - } - } - } - } - - /** - * Moves the visible map pane. - * - * @param x - * horizontal movement in pixel. - * @param y - * vertical movement in pixel - */ - public void moveMap(int x, int y) { - tileController.cancelOutstandingJobs(); // Clear outstanding load - center.x += x; - center.y += y; - repaint(); - this.fireJMVEvent(new JMVCommandEvent(COMMAND.MOVE, this)); - } - - /** - * @return the current zoom level - */ - public int getZoom() { - return zoom; - } - - /** - * Increases the current zoom level by one - */ - public void zoomIn() { - setZoom(zoom + 1); - } - - /** - * Increases the current zoom level by one - * @param mapPoint point to choose as center for new zoom level - */ - public void zoomIn(Point mapPoint) { - setZoom(zoom + 1, mapPoint); - } - - /** - * Decreases the current zoom level by one - */ - public void zoomOut() { - setZoom(zoom - 1); - } - - /** - * Decreases the current zoom level by one - * - * @param mapPoint point to choose as center for new zoom level - */ - public void zoomOut(Point mapPoint) { - setZoom(zoom - 1, mapPoint); - } - - /** - * Set the zoom level and center point for display - * - * @param zoom new zoom level - * @param mapPoint point to choose as center for new zoom level - */ - public void setZoom(int zoom, Point mapPoint) { - if (zoom > tileController.getTileSource().getMaxZoom() || zoom < tileController.getTileSource().getMinZoom() - || zoom == this.zoom) - return; - ICoordinate zoomPos = getPosition(mapPoint); - tileController.cancelOutstandingJobs(); // Clearing outstanding load - // requests - setDisplayPosition(mapPoint, zoomPos, zoom); - - this.fireJMVEvent(new JMVCommandEvent(COMMAND.ZOOM, this)); - } - - /** - * Set the zoom level - * - * @param zoom new zoom level - */ - public void setZoom(int zoom) { - setZoom(zoom, new Point(getWidth() / 2, getHeight() / 2)); - } - - /** - * Every time the zoom level changes this method is called. Override it in - * derived implementations for adapting zoom dependent values. The new zoom - * level can be obtained via {@link #getZoom()}. - * - * @param oldZoom the previous zoom level - */ - protected void zoomChanged(int oldZoom) { - zoomSlider.setToolTipText("Zoom level " + zoom); - zoomInButton.setToolTipText("Zoom to level " + (zoom + 1)); - zoomOutButton.setToolTipText("Zoom to level " + (zoom - 1)); - zoomOutButton.setEnabled(zoom > tileController.getTileSource().getMinZoom()); - zoomInButton.setEnabled(zoom < tileController.getTileSource().getMaxZoom()); - } - - /** - * Determines whether the tile grid is visible or not. - * @return {@code true} if the tile grid is visible, {@code false} otherwise - */ - public boolean isTileGridVisible() { - return tileGridVisible; - } - - /** - * Sets whether the tile grid is visible or not. - * @param tileGridVisible {@code true} if the tile grid is visible, {@code false} otherwise - */ - public void setTileGridVisible(boolean tileGridVisible) { - this.tileGridVisible = tileGridVisible; - repaint(); - } - - /** - * Determines whether {@link MapMarker}s are painted or not. - * @return {@code true} if {@link MapMarker}s are painted, {@code false} otherwise - */ - public boolean getMapMarkersVisible() { - return mapMarkersVisible; - } - - /** - * Enables or disables painting of the {@link MapMarker} - * - * @param mapMarkersVisible {@code true} to enable painting of markers - * @see #addMapMarker(MapMarker) - * @see #getMapMarkerList() - */ - public void setMapMarkerVisible(boolean mapMarkersVisible) { - this.mapMarkersVisible = mapMarkersVisible; - repaint(); - } - - /** - * Sets the list of {@link MapMarker}s. - * @param mapMarkerList list of {@link MapMarker}s - */ - public void setMapMarkerList(List mapMarkerList) { - this.mapMarkerList = mapMarkerList; - repaint(); - } - - /** - * Returns the list of {@link MapMarker}s. - * @return list of {@link MapMarker}s - */ - public List getMapMarkerList() { - return mapMarkerList; - } - - /** - * Sets the list of {@link MapRectangle}s. - * @param mapRectangleList list of {@link MapRectangle}s - */ - public void setMapRectangleList(List mapRectangleList) { - this.mapRectangleList = mapRectangleList; - repaint(); - } - - /** - * Returns the list of {@link MapRectangle}s. - * @return list of {@link MapRectangle}s - */ - public List getMapRectangleList() { - return mapRectangleList; - } - - /** - * Sets the list of {@link MapPolygon}s. - * @param mapPolygonList list of {@link MapPolygon}s - */ - public void setMapPolygonList(List mapPolygonList) { - this.mapPolygonList = mapPolygonList; - repaint(); - } - - /** - * Returns the list of {@link MapPolygon}s. - * @return list of {@link MapPolygon}s - */ - public List getMapPolygonList() { - return mapPolygonList; - } - - /** - * Add a {@link MapMarker}. - * @param marker map marker to add - */ - public void addMapMarker(MapMarker marker) { - mapMarkerList.add(marker); - repaint(); - } - - /** - * Remove a {@link MapMarker}. - * @param marker map marker to remove - */ - public void removeMapMarker(MapMarker marker) { - mapMarkerList.remove(marker); - repaint(); - } - - /** - * Remove all {@link MapMarker}s. - */ - public void removeAllMapMarkers() { - mapMarkerList.clear(); - repaint(); - } - - /** - * Add a {@link MapRectangle}. - * @param rectangle map rectangle to add - */ - public void addMapRectangle(MapRectangle rectangle) { - mapRectangleList.add(rectangle); - repaint(); - } - - /** - * Remove a {@link MapRectangle}. - * @param rectangle map rectangle to remove - */ - public void removeMapRectangle(MapRectangle rectangle) { - mapRectangleList.remove(rectangle); - repaint(); - } - - /** - * Remove all {@link MapRectangle}s. - */ - public void removeAllMapRectangles() { - mapRectangleList.clear(); - repaint(); - } - - /** - * Add a {@link MapPolygon}. - * @param polygon map polygon to add - */ - public void addMapPolygon(MapPolygon polygon) { - mapPolygonList.add(polygon); - repaint(); - } - - /** - * Remove a {@link MapPolygon}. - * @param polygon map polygon to remove - */ - public void removeMapPolygon(MapPolygon polygon) { - mapPolygonList.remove(polygon); - repaint(); - } - - /** - * Remove all {@link MapPolygon}s. - */ - public void removeAllMapPolygons() { - mapPolygonList.clear(); - repaint(); - } - - /** - * Sets whether zoom controls are displayed or not. - * @param visible {@code true} if zoom controls are displayed, {@code false} otherwise - * @deprecated use {@link #setZoomControlsVisible(boolean)} - */ - @Deprecated - public void setZoomContolsVisible(boolean visible) { - setZoomControlsVisible(visible); - } - - /** - * Sets whether zoom controls are displayed or not. - * @param visible {@code true} if zoom controls are displayed, {@code false} otherwise - */ - public void setZoomControlsVisible(boolean visible) { - zoomSlider.setVisible(visible); - zoomInButton.setVisible(visible); - zoomOutButton.setVisible(visible); - } - - /** - * Determines whether zoom controls are displayed or not. - * @return {@code true} if zoom controls are displayed, {@code false} otherwise - */ - public boolean getZoomControlsVisible() { - return zoomSlider.isVisible(); - } - - /** - * Sets the tile source. - * @param tileSource tile source - */ - public void setTileSource(TileSource tileSource) { - if (tileSource.getMaxZoom() > MAX_ZOOM) - throw new RuntimeException("Maximum zoom level too high"); - if (tileSource.getMinZoom() < MIN_ZOOM) - throw new RuntimeException("Minimum zoom level too low"); - ICoordinate position = getPosition(); - this.tileSource = tileSource; - tileController.setTileSource(tileSource); - zoomSlider.setMinimum(tileSource.getMinZoom()); - zoomSlider.setMaximum(tileSource.getMaxZoom()); - tileController.cancelOutstandingJobs(); - if (zoom > tileSource.getMaxZoom()) { - setZoom(tileSource.getMaxZoom()); - } - attribution.initialize(tileSource); - setDisplayPosition(position, zoom); - repaint(); - } - - @Override - public void tileLoadingFinished(Tile tile, boolean success) { - tile.setLoaded(success); - repaint(); - } - - /** - * Determines whether the {@link MapRectangle}s are painted or not. - * @return {@code true} if the {@link MapRectangle}s are painted, {@code false} otherwise - */ - public boolean isMapRectanglesVisible() { - return mapRectanglesVisible; - } - - /** - * Enables or disables painting of the {@link MapRectangle}s. - * - * @param mapRectanglesVisible {@code true} to enable painting of rectangles - * @see #addMapRectangle(MapRectangle) - * @see #getMapRectangleList() - */ - public void setMapRectanglesVisible(boolean mapRectanglesVisible) { - this.mapRectanglesVisible = mapRectanglesVisible; - repaint(); - } - - /** - * Determines whether the {@link MapPolygon}s are painted or not. - * @return {@code true} if the {@link MapPolygon}s are painted, {@code false} otherwise - */ - public boolean isMapPolygonsVisible() { - return mapPolygonsVisible; - } - - /** - * Enables or disables painting of the {@link MapPolygon}s. - * - * @param mapPolygonsVisible {@code true} to enable painting of polygons - * @see #addMapPolygon(MapPolygon) - * @see #getMapPolygonList() - */ - public void setMapPolygonsVisible(boolean mapPolygonsVisible) { - this.mapPolygonsVisible = mapPolygonsVisible; - repaint(); - } - - /** - * Determines whether scroll wrap is enabled or not. - * @return {@code true} if scroll wrap is enabled, {@code false} otherwise - */ - public boolean isScrollWrapEnabled() { - return scrollWrapEnabled; - } - - /** - * Sets whether scroll wrap is enabled or not. - * @param scrollWrapEnabled {@code true} if scroll wrap is enabled, {@code false} otherwise - */ - public void setScrollWrapEnabled(boolean scrollWrapEnabled) { - this.scrollWrapEnabled = scrollWrapEnabled; - repaint(); - } - - /** - * Returns the zoom controls apparence style (horizontal/vertical). - * @return {@link ZOOM_BUTTON_STYLE#VERTICAL} or {@link ZOOM_BUTTON_STYLE#HORIZONTAL} - */ - public ZOOM_BUTTON_STYLE getZoomButtonStyle() { - return zoomButtonStyle; - } - - /** - * Sets the zoom controls apparence style (horizontal/vertical). - * @param style {@link ZOOM_BUTTON_STYLE#VERTICAL} or {@link ZOOM_BUTTON_STYLE#HORIZONTAL} - */ - public void setZoomButtonStyle(ZOOM_BUTTON_STYLE style) { - zoomButtonStyle = style; - if (zoomSlider == null || zoomInButton == null || zoomOutButton == null) { - return; - } - switch (style) { - case VERTICAL: - zoomSlider.setBounds(10, 27, 30, 150); - zoomInButton.setBounds(14, 8, 20, 20); - zoomOutButton.setBounds(14, 176, 20, 20); - break; - case HORIZONTAL: - default: - zoomSlider.setBounds(10, 10, 30, 150); - zoomInButton.setBounds(4, 155, 18, 18); - zoomOutButton.setBounds(26, 155, 18, 18); - break; - } - repaint(); - } - - /** - * Returns the tile controller. - * @return the tile controller - */ - public TileController getTileController() { - return tileController; - } - - /** - * Return tile information caching class - * @return tile cache - * @see TileController#getTileCache() - */ - public TileCache getTileCache() { - return tileController.getTileCache(); - } - - /** - * Sets the tile loader. - * @param loader tile loader - */ - public void setTileLoader(TileLoader loader) { - tileController.setTileLoader(loader); - } - - /** - * Returns attribution. - * @return attribution - */ - public AttributionSupport getAttribution() { - return attribution; - } - - /** - * @param listener listener to set - */ - public void addJMVListener(JMapViewerEventListener listener) { - evtListenerList.add(JMapViewerEventListener.class, listener); - } - - /** - * @param listener listener to remove - */ - public void removeJMVListener(JMapViewerEventListener listener) { - evtListenerList.remove(JMapViewerEventListener.class, listener); - } - - /** - * Send an update to all objects registered with viewer - * - * @param evt event to dispatch - */ - private void fireJMVEvent(JMVCommandEvent evt) { - Object[] listeners = evtListenerList.getListenerList(); - for (int i = 0; i < listeners.length; i += 2) { - if (listeners[i] == JMapViewerEventListener.class) { - ((JMapViewerEventListener) listeners[i + 1]).processCommand(evt); - } - } - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java b/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java deleted file mode 100644 index 22048fc84a0..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java +++ /dev/null @@ -1,198 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.List; - -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JSplitPane; -import javax.swing.event.TreeModelEvent; -import javax.swing.event.TreeModelListener; - -import org.openstreetmap.gui.jmapviewer.checkBoxTree.CheckBoxNodePanel; -import org.openstreetmap.gui.jmapviewer.checkBoxTree.CheckBoxTree; -import org.openstreetmap.gui.jmapviewer.interfaces.MapObject; - -/** - * Tree of layers for JMapViewer component - * @author galo - */ -public class JMapViewerTree extends JPanel { - /** Serial Version UID */ - private static final long serialVersionUID = 3050203054402323972L; - - private JMapViewer map; - private CheckBoxTree tree; - private JPanel treePanel; - private JSplitPane splitPane; - - public JMapViewerTree(String name) { - this(name, false); - } - - public JMapViewerTree(String name, boolean treeVisible) { - super(); - splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - - tree = new CheckBoxTree(name); - treePanel = new JPanel(new BorderLayout()); - treePanel.add(tree, BorderLayout.CENTER); - treePanel.add(new JLabel("
Use right mouse button to
show/hide texts
"), BorderLayout.SOUTH); - map = new JMapViewer(); - - splitPane.setOneTouchExpandable(true); - splitPane.setDividerLocation(150); - - //Provide minimum sizes for the two components in the split pane - Dimension minimumSize = new Dimension(100, 50); - //tree.setMinimumSize(minimumSize); - map.setMinimumSize(minimumSize); - createRefresh(); - setLayout(new BorderLayout()); - setTreeVisible(treeVisible); - tree.addNodeListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - maybeShowPopup(e); - } - - @Override - public void mouseReleased(MouseEvent e) { - maybeShowPopup(e); - } - - private void maybeShowPopup(MouseEvent e) { - if (e.isPopupTrigger()) { - AbstractLayer layer = ((CheckBoxNodePanel) e.getComponent()).getData().getAbstractLayer(); - if (layer != null) - JMapViewerTree.this.createPopupMenu(layer).show(e.getComponent(), e.getX(), e.getY()); - } - } - }); - } - - private JPopupMenu createPopupMenu(final AbstractLayer layer) { - JMenuItem menuItemShow = new JMenuItem("show texts"); - JMenuItem menuItemHide = new JMenuItem("hide texts"); - - //Create the popup menu. - JPopupMenu popup = new JPopupMenu(); - - // Create items - if (layer.isVisibleTexts() == null) { - popup.add(menuItemShow); - popup.add(menuItemHide); - } else if (layer.isVisibleTexts()) popup.add(menuItemHide); - else popup.add(menuItemShow); - - menuItemShow.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - setVisibleTexts(layer, true); - if (layer.getParent() != null) layer.getParent().calculateVisibleTexts(); - map.repaint(); - } - }); - menuItemHide.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - setVisibleTexts(layer, false); - if (layer.getParent() != null) layer.getParent().calculateVisibleTexts(); - map.repaint(); - } - }); - - return popup; - } - - private static void setVisibleTexts(AbstractLayer layer, boolean visible) { - layer.setVisibleTexts(visible); - if (layer instanceof LayerGroup) { - LayerGroup group = (LayerGroup) layer; - if (group.getLayers() != null) - for (AbstractLayer al: group.getLayers()) { - setVisibleTexts(al, visible); - } - } - } - - public Layer addLayer(String name) { - Layer layer = new Layer(name); - this.addLayer(layer); - return layer; - } - - public JMapViewerTree addLayer(Layer layer) { - tree.addLayer(layer); - return this; - } - - public JMapViewerTree addLayer(MapObject element) { - //element.getLayer().add(element); - return addLayer(element.getLayer()); - } - - public Layer removeFromLayer(MapObject element) { - element.getLayer().getElements().remove(element); - return element.getLayer(); - } - - public static int size(List list) { - return list == null ? 0 : list.size(); - } - - public JMapViewer getViewer() { - return map; - } - - public CheckBoxTree getTree() { - return tree; - } - - public void addMapObject(MapObject o){ - - } - - public void setTreeVisible(boolean visible) { - removeAll(); - revalidate(); - if (visible) { - splitPane.setLeftComponent(treePanel); - splitPane.setRightComponent(map); - add(splitPane, BorderLayout.CENTER); - } else add(map, BorderLayout.CENTER); - repaint(); - } - - private void createRefresh() { - tree.getModel().addTreeModelListener(new TreeModelListener() { - @Override - public void treeNodesChanged(final TreeModelEvent e) { - repaint(); - } - - @Override - public void treeNodesInserted(TreeModelEvent arg0) { - // TODO Auto-generated method stub - } - - @Override - public void treeNodesRemoved(TreeModelEvent arg0) { - // TODO Auto-generated method stub - } - - @Override - public void treeStructureChanged(TreeModelEvent arg0) { - // TODO Auto-generated method stub - } - }); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/Layer.java b/src/org/openstreetmap/gui/jmapviewer/Layer.java deleted file mode 100644 index d41e5470f69..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/Layer.java +++ /dev/null @@ -1,52 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.util.List; - -import org.openstreetmap.gui.jmapviewer.interfaces.MapObject; - -public class Layer extends AbstractLayer { - private List elements; - - public Layer(String name) { - super(name); - } - - public Layer(String name, String description) { - super(name, description); - } - - public Layer(String name, Style style) { - super(name, style); - } - - public Layer(String name, String description, Style style) { - super(name, description, style); - } - - public Layer(LayerGroup parent, String name) { - super(parent, name); - } - - public Layer(LayerGroup parent, String name, Style style) { - super(parent, name, style); - } - - public Layer(LayerGroup parent, String name, String description, Style style) { - super(parent, name, description, style); - } - - public List getElements() { - return elements; - } - - public void setElements(List elements) { - this.elements = elements; - } - - public Layer add(MapObject element) { - element.setLayer(this); - elements = add(elements, element); - return this; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java b/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java deleted file mode 100644 index 47b158beeab..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java +++ /dev/null @@ -1,71 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.util.List; - -public class LayerGroup extends AbstractLayer { - private List layers; - - public LayerGroup(String name) { - super(name); - } - - public LayerGroup(String name, String description) { - super(name, description); - } - - public LayerGroup(String name, Style style) { - super(name, style); - } - - public LayerGroup(String name, String description, Style style) { - super(name, description, style); - } - - public LayerGroup(LayerGroup parent, String name) { - super(parent, name); - } - - public LayerGroup(LayerGroup parent, String name, String description, Style style) { - super(name, description, style); - } - - public List getLayers() { - return layers; - } - - public void setElements(List layers) { - this.layers = layers; - } - - public Layer addLayer(String name) { - Layer layer = new Layer(this, name); - layers = add(layers, layer); - return layer; - } - - public LayerGroup add(AbstractLayer layer) { - layer.setParent(this); - layers = add(layers, layer); - return this; - } - - public void calculateVisibleTexts() { - Boolean calculate = null; - if (layers != null && !layers.isEmpty()) { - calculate = layers.get(0).isVisibleTexts(); - for (int i = 1; i < layers.size(); i++) { - calculate = resultOf(calculate, layers.get(i).isVisibleTexts()); - } - } - setVisibleTexts(calculate); - if (getParent() != null) getParent().calculateVisibleTexts(); - } - - public Boolean resultOf(Boolean b1, Boolean b2) { - if (b1 != null && b1.equals(b2)) { - return b1; - } - return Boolean.FALSE; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java b/src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java deleted file mode 100644 index a0ca123ed7f..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java +++ /dev/null @@ -1,168 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; - -import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker; - -/** - * A simple implementation of the {@link MapMarker} interface. Each map marker - * is painted as a circle with a black border line and filled with a specified - * color. - * - * @author Jan Peter Stotz - * - */ -public class MapMarkerCircle extends MapObjectImpl implements MapMarker { - - private Coordinate coord; - private double radius; - private STYLE markerStyle; - - /** - * Constructs a new {@code MapMarkerCircle}. - * @param coord Coordinates of the map marker - * @param radius Radius of the map marker position - */ - public MapMarkerCircle(Coordinate coord, double radius) { - this(null, null, coord, radius); - } - - /** - * Constructs a new {@code MapMarkerCircle}. - * @param name Name of the map marker - * @param coord Coordinates of the map marker - * @param radius Radius of the map marker position - */ - public MapMarkerCircle(String name, Coordinate coord, double radius) { - this(null, name, coord, radius); - } - - /** - * Constructs a new {@code MapMarkerCircle}. - * @param layer Layer of the map marker - * @param coord Coordinates of the map marker - * @param radius Radius of the map marker position - */ - public MapMarkerCircle(Layer layer, Coordinate coord, double radius) { - this(layer, null, coord, radius); - } - - /** - * Constructs a new {@code MapMarkerCircle}. - * @param lat Latitude of the map marker - * @param lon Longitude of the map marker - * @param radius Radius of the map marker position - */ - public MapMarkerCircle(double lat, double lon, double radius) { - this(null, null, new Coordinate(lat, lon), radius); - } - - /** - * Constructs a new {@code MapMarkerCircle}. - * @param layer Layer of the map marker - * @param lat Latitude of the map marker - * @param lon Longitude of the map marker - * @param radius Radius of the map marker position - */ - public MapMarkerCircle(Layer layer, double lat, double lon, double radius) { - this(layer, null, new Coordinate(lat, lon), radius); - } - - /** - * Constructs a new {@code MapMarkerCircle}. - * @param layer Layer of the map marker - * @param name Name of the map marker - * @param coord Coordinates of the map marker - * @param radius Radius of the map marker position - */ - public MapMarkerCircle(Layer layer, String name, Coordinate coord, double radius) { - this(layer, name, coord, radius, STYLE.VARIABLE, getDefaultStyle()); - } - - /** - * Constructs a new {@code MapMarkerCircle}. - * @param layer Layer of the map marker - * @param name Name of the map marker - * @param coord Coordinates of the map marker - * @param radius Radius of the map marker position - * @param markerStyle Marker style (fixed or variable) - * @param style Graphical style - */ - public MapMarkerCircle(Layer layer, String name, Coordinate coord, double radius, STYLE markerStyle, Style style) { - super(layer, name, style); - this.markerStyle = markerStyle; - this.coord = coord; - this.radius = radius; - } - - @Override - public Coordinate getCoordinate() { - return coord; - } - - @Override - public double getLat() { - return coord.getLat(); - } - - @Override - public double getLon() { - return coord.getLon(); - } - - @Override - public double getRadius() { - return radius; - } - - @Override - public STYLE getMarkerStyle() { - return markerStyle; - } - - @Override - public void paint(Graphics g, Point position, int radius) { - int sizeH = radius; - int size = sizeH * 2; - - if (g instanceof Graphics2D && getBackColor() != null) { - Graphics2D g2 = (Graphics2D) g; - Composite oldComposite = g2.getComposite(); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - g2.setPaint(getBackColor()); - g.fillOval(position.x - sizeH, position.y - sizeH, size, size); - g2.setComposite(oldComposite); - } - g.setColor(getColor()); - g.drawOval(position.x - sizeH, position.y - sizeH, size, size); - - if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, position); - } - - public static Style getDefaultStyle() { - return new Style(Color.ORANGE, new Color(200, 200, 200, 200), null, getDefaultFont()); - } - - @Override - public String toString() { - return "MapMarker at " + getLat() + ' ' + getLon(); - } - - @Override - public void setLat(double lat) { - if (coord == null) coord = new Coordinate(lat, 0); - else coord.setLat(lat); - } - - @Override - public void setLon(double lon) { - if (coord == null) coord = new Coordinate(0, lon); - else coord.setLon(lon); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java b/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java deleted file mode 100644 index 2765a33f7ae..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java +++ /dev/null @@ -1,60 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.Color; - -import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker; - -/** - * A simple implementation of the {@link MapMarker} interface. Each map marker - * is painted as a circle with a black border line and filled with a specified - * color. - * - * @author Jan Peter Stotz - * - */ -public class MapMarkerDot extends MapMarkerCircle { - - public static final int DOT_RADIUS = 5; - - public MapMarkerDot(Coordinate coord) { - this(null, null, coord); - } - - public MapMarkerDot(String name, Coordinate coord) { - this(null, name, coord); - } - - public MapMarkerDot(Layer layer, Coordinate coord) { - this(layer, null, coord); - } - - public MapMarkerDot(Layer layer, String name, Coordinate coord) { - this(layer, name, coord, getDefaultStyle()); - } - - public MapMarkerDot(Color color, double lat, double lon) { - this(null, null, lat, lon); - setColor(color); - } - - public MapMarkerDot(double lat, double lon) { - this(null, null, lat, lon); - } - - public MapMarkerDot(Layer layer, double lat, double lon) { - this(layer, null, lat, lon); - } - - public MapMarkerDot(Layer layer, String name, double lat, double lon) { - this(layer, name, new Coordinate(lat, lon), getDefaultStyle()); - } - - public MapMarkerDot(Layer layer, String name, Coordinate coord, Style style) { - super(layer, name, coord, DOT_RADIUS, STYLE.FIXED, style); - } - - public static Style getDefaultStyle() { - return new Style(Color.BLACK, Color.YELLOW, null, getDefaultFont()); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java b/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java deleted file mode 100644 index d9262289bb4..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java +++ /dev/null @@ -1,132 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Point; -import java.awt.Stroke; - -import javax.swing.UIManager; - -public abstract class MapObjectImpl { - private Layer layer; - private String name; - private Style style; - private Boolean visible; - - public MapObjectImpl(String name) { - this(null, name, null); - } - - public MapObjectImpl(Layer layer) { - this(layer, null, null); - } - - public MapObjectImpl(Layer layer, String name, Style style) { - super(); - this.layer = layer; - this.name = name; - this.style = style; - } - - public Layer getLayer() { - return layer; - } - - public void setLayer(Layer layer) { - this.layer = layer; - } - - public Style getStyle() { - return style; - } - - public Style getStyleAssigned() { - return style == null ? (layer == null ? null : layer.getStyle()) : style; - } - - public void setStyle(Style style) { - this.style = style; - } - - public Color getColor() { - Style styleAssigned = getStyleAssigned(); - return styleAssigned == null ? null : getStyleAssigned().getColor(); - } - - public void setColor(Color color) { - if (style == null && color != null) style = new Style(); - if (style != null) style.setColor(color); - } - - public Color getBackColor() { - Style styleAssigned = getStyleAssigned(); - return styleAssigned == null ? null : getStyleAssigned().getBackColor(); - } - - public void setBackColor(Color backColor) { - if (style == null && backColor != null) style = new Style(); - if (style != null) style.setBackColor(backColor); - } - - public Stroke getStroke() { - Style styleAssigned = getStyleAssigned(); - return styleAssigned == null ? null : getStyleAssigned().getStroke(); - } - - public void setStroke(Stroke stroke) { - if (style == null && stroke != null) style = new Style(); - if (style != null) style.setStroke(stroke); - } - - public Font getFont() { - Style styleAssigned = getStyleAssigned(); - return styleAssigned == null ? null : getStyleAssigned().getFont(); - } - - public void setFont(Font font) { - if (style == null && font != null) style = new Style(); - if (style != null) style.setFont(font); - } - - private boolean isVisibleLayer() { - return layer == null || layer.isVisible() == null ? true : layer.isVisible(); - } - - public boolean isVisible() { - return visible == null ? isVisibleLayer() : visible.booleanValue(); - } - - public void setVisible(Boolean visible) { - this.visible = visible; - } - - public String getName() { - return name; - } - - public void setName(String txt) { - this.name = txt; - } - - public static Font getDefaultFont() { - Font f = UIManager.getDefaults().getFont("TextField.font"); - if (f == null) { - f = Font.decode(null); - } - return new Font(f.getName(), Font.BOLD, f.getSize()); - } - - public void paintText(Graphics g, Point position) { - if (name != null && g != null && position != null) { - if (getFont() == null) { - Font f = getDefaultFont(); - setFont(new Font(f.getName(), Font.BOLD, f.getSize())); - } - g.setColor(Color.DARK_GRAY); - g.setFont(getFont()); - g.drawString(name, position.x+MapMarkerDot.DOT_RADIUS+2, position.y+MapMarkerDot.DOT_RADIUS); - } - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java b/src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java deleted file mode 100644 index 9e08a5930b4..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java +++ /dev/null @@ -1,112 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.Stroke; -import java.util.Arrays; -import java.util.List; - -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; -import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon; - -public class MapPolygonImpl extends MapObjectImpl implements MapPolygon { - - private List points; - - public MapPolygonImpl(ICoordinate... points) { - this(null, null, points); - } - - public MapPolygonImpl(List points) { - this(null, null, points); - } - - public MapPolygonImpl(String name, List points) { - this(null, name, points); - } - - public MapPolygonImpl(String name, ICoordinate... points) { - this(null, name, points); - } - - public MapPolygonImpl(Layer layer, List points) { - this(layer, null, points); - } - - public MapPolygonImpl(Layer layer, String name, List points) { - this(layer, name, points, getDefaultStyle()); - } - - public MapPolygonImpl(Layer layer, String name, ICoordinate... points) { - this(layer, name, Arrays.asList(points), getDefaultStyle()); - } - - public MapPolygonImpl(Layer layer, String name, List points, Style style) { - super(layer, name, style); - this.points = points; - } - - @Override - public List getPoints() { - return this.points; - } - - @Override - public void paint(Graphics g, List points) { - Polygon polygon = new Polygon(); - for (Point p : points) { - polygon.addPoint(p.x, p.y); - } - paint(g, polygon); - } - - @Override - public void paint(Graphics g, Polygon polygon) { - // Prepare graphics - Color oldColor = g.getColor(); - g.setColor(getColor()); - - Stroke oldStroke = null; - if (g instanceof Graphics2D) { - Graphics2D g2 = (Graphics2D) g; - oldStroke = g2.getStroke(); - g2.setStroke(getStroke()); - } - // Draw - g.drawPolygon(polygon); - if (g instanceof Graphics2D && getBackColor() != null) { - Graphics2D g2 = (Graphics2D) g; - Composite oldComposite = g2.getComposite(); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - g2.setPaint(getBackColor()); - g2.fillPolygon(polygon); - g2.setComposite(oldComposite); - } - // Restore graphics - g.setColor(oldColor); - if (g instanceof Graphics2D) { - ((Graphics2D) g).setStroke(oldStroke); - } - Rectangle rec = polygon.getBounds(); - Point corner = rec.getLocation(); - Point p = new Point(corner.x+(rec.width/2), corner.y+(rec.height/2)); - if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, p); - } - - public static Style getDefaultStyle() { - return new Style(Color.BLUE, new Color(100, 100, 100, 50), new BasicStroke(2), getDefaultFont()); - } - - @Override - public String toString() { - return "MapPolygon [points=" + points + ']'; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java b/src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java deleted file mode 100644 index 77ff12b5028..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java +++ /dev/null @@ -1,82 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Stroke; - -import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle; - -public class MapRectangleImpl extends MapObjectImpl implements MapRectangle { - - private Coordinate topLeft; - private Coordinate bottomRight; - - public MapRectangleImpl(Coordinate topLeft, Coordinate bottomRight) { - this(null, null, topLeft, bottomRight); - } - - public MapRectangleImpl(String name, Coordinate topLeft, Coordinate bottomRight) { - this(null, name, topLeft, bottomRight); - } - - public MapRectangleImpl(Layer layer, Coordinate topLeft, Coordinate bottomRight) { - this(layer, null, topLeft, bottomRight); - } - - public MapRectangleImpl(Layer layer, String name, Coordinate topLeft, Coordinate bottomRight) { - this(layer, name, topLeft, bottomRight, getDefaultStyle()); - } - - public MapRectangleImpl(Layer layer, String name, Coordinate topLeft, Coordinate bottomRight, Style style) { - super(layer, name, style); - this.topLeft = topLeft; - this.bottomRight = bottomRight; - } - - @Override - public Coordinate getTopLeft() { - return topLeft; - } - - @Override - public Coordinate getBottomRight() { - return bottomRight; - } - - @Override - public void paint(Graphics g, Point topLeft, Point bottomRight) { - // Prepare graphics - Color oldColor = g.getColor(); - g.setColor(getColor()); - Stroke oldStroke = null; - if (g instanceof Graphics2D) { - Graphics2D g2 = (Graphics2D) g; - oldStroke = g2.getStroke(); - g2.setStroke(getStroke()); - } - // Draw - g.drawRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y); - // Restore graphics - g.setColor(oldColor); - if (g instanceof Graphics2D) { - ((Graphics2D) g).setStroke(oldStroke); - } - int width = bottomRight.x-topLeft.x; - int height = bottomRight.y-topLeft.y; - Point p = new Point(topLeft.x+(width/2), topLeft.y+(height/2)); - if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, p); - } - - public static Style getDefaultStyle() { - return new Style(Color.BLUE, null, new BasicStroke(2), getDefaultFont()); - } - - @Override - public String toString() { - return "MapRectangle from " + getTopLeft() + " to " + getBottomRight(); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java b/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java deleted file mode 100644 index 3a5ed8e9d58..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java +++ /dev/null @@ -1,228 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Logger; - -import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; -import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; - -/** - * {@link TileCache} implementation that stores all {@link Tile} objects in - * memory up to a certain limit ({@link #getCacheSize()}). If the limit is - * exceeded the least recently used {@link Tile} objects will be deleted. - * - * @author Jan Peter Stotz - */ -public class MemoryTileCache implements TileCache { - - protected static final Logger log = Logger.getLogger(MemoryTileCache.class.getName()); - - /** - * Default cache size - */ - protected int cacheSize; - - protected final Map hash; - - /** - * List of all tiles in their last recently used order - */ - protected final CacheLinkedListElement lruTiles; - - /** - * Constructs a new {@code MemoryTileCache}. - */ - public MemoryTileCache() { - this(200); - } - - /** - * Constructs a new {@code MemoryTileCache}. - * @param cacheSize size of the cache - */ - public MemoryTileCache(int cacheSize) { - this.cacheSize = cacheSize; - hash = new HashMap<>(cacheSize); - lruTiles = new CacheLinkedListElement(); - } - - @Override - public synchronized void addTile(Tile tile) { - CacheEntry entry = createCacheEntry(tile); - if (hash.put(tile.getKey(), entry) == null) { - // only if hash hadn't had the element, add it to LRU - lruTiles.addFirst(entry); - if (hash.size() > cacheSize || lruTiles.getElementCount() > cacheSize) { - removeOldEntries(); - } - } - } - - @Override - public synchronized Tile getTile(TileSource source, int x, int y, int z) { - CacheEntry entry = hash.get(Tile.getTileKey(source, x, y, z)); - if (entry == null) - return null; - lruTiles.moveElementToFirstPos(entry); - return entry.tile; - } - - /** - * Removes the least recently used tiles - */ - protected synchronized void removeOldEntries() { - try { - while (lruTiles.getElementCount() > cacheSize) { - removeEntry(lruTiles.getLastElement()); - } - } catch (NullPointerException e) { - log.warning(e.getMessage()); - } - } - - protected synchronized void removeEntry(CacheEntry entry) { - hash.remove(entry.tile.getKey()); - lruTiles.removeEntry(entry); - } - - protected CacheEntry createCacheEntry(Tile tile) { - return new CacheEntry(tile); - } - - @Override - public synchronized void clear() { - hash.clear(); - lruTiles.clear(); - } - - @Override - public synchronized int getTileCount() { - return hash.size(); - } - - @Override - public synchronized int getCacheSize() { - return cacheSize; - } - - /** - * Changes the maximum number of {@link Tile} objects that this cache holds. - * - * @param cacheSize - * new maximum number of tiles - */ - public synchronized void setCacheSize(int cacheSize) { - this.cacheSize = cacheSize; - if (hash.size() > cacheSize) - removeOldEntries(); - } - - /** - * Linked list element holding the {@link Tile} and links to the - * {@link #next} and {@link #prev} item in the list. - */ - protected static class CacheEntry { - private Tile tile; - private CacheEntry next; - private CacheEntry prev; - - protected CacheEntry(Tile tile) { - this.tile = tile; - } - - @Override - public String toString() { - return tile.toString(); - } - } - - /** - * Special implementation of a double linked list for {@link CacheEntry} - * elements. It supports element removal in constant time - in difference to - * the Java implementation which needs O(n). - * - * @author Jan Peter Stotz - */ - protected static class CacheLinkedListElement { - protected CacheEntry firstElement; - protected CacheEntry lastElement; - protected int elementCount; - - /** - * Constructs a new {@code CacheLinkedListElement}. - */ - public CacheLinkedListElement() { - clear(); - } - - public void clear() { - elementCount = 0; - firstElement = null; - lastElement = null; - } - - /** - * Add the element to the head of the list. - * - * @param element new element to be added - */ - public void addFirst(CacheEntry element) { - if (element == null) return; - if (elementCount == 0) { - firstElement = element; - lastElement = element; - element.prev = null; - element.next = null; - } else { - element.next = firstElement; - firstElement.prev = element; - element.prev = null; - firstElement = element; - } - elementCount++; - } - - /** - * Removes the specified element from the list. - * - * @param element element to be removed - */ - public void removeEntry(CacheEntry element) { - if (element == null) return; - if (element.next != null) { - element.next.prev = element.prev; - } - if (element.prev != null) { - element.prev.next = element.next; - } - if (element == firstElement) - firstElement = element.next; - if (element == lastElement) - lastElement = element.prev; - element.next = null; - element.prev = null; - elementCount--; - } - - public void moveElementToFirstPos(CacheEntry entry) { - if (firstElement == entry) - return; - removeEntry(entry); - addFirst(entry); - } - - public int getElementCount() { - return elementCount; - } - - public CacheEntry getLastElement() { - return lastElement; - } - - public CacheEntry getFirstElement() { - return firstElement; - } - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java b/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java deleted file mode 100644 index e9bac157bcb..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java +++ /dev/null @@ -1,203 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -/** - * This class implements the Mercator Projection as it is used by OpenStreetMap - * (and google). It provides methods to translate coordinates from 'map space' - * into latitude and longitude (on the WGS84 ellipsoid) and vice versa. Map - * space is measured in pixels. The origin of the map space is the top left - * corner. The map space origin (0,0) has latitude ~85 and longitude -180. - * @author Jan Peter Stotz - * @author Jason Huntley - */ -public class OsmMercator { - - /** - * default tile size - */ - public static final int DEFAUL_TILE_SIZE = 256; - /** maximum latitude (north) for mercator display */ - public static final double MAX_LAT = 85.05112877980659; - /** minimum latitude (south) for mercator display */ - public static final double MIN_LAT = -85.05112877980659; - /** equatorial earth radius for EPSG:3857 (Mercator) */ - public static final double EARTH_RADIUS = 6_378_137; - - /** - * instance with tile size of 256 for easy conversions - */ - public static final OsmMercator MERCATOR_256 = new OsmMercator(); - - /** tile size of the displayed tiles */ - private int tileSize = DEFAUL_TILE_SIZE; - - /** - * Creates instance with default tile size of 256 - */ - public OsmMercator() { - } - - /** - * Creates instance with provided tile size. - * @param tileSize tile size in pixels - */ - public OsmMercator(int tileSize) { - this.tileSize = tileSize; - } - - public double radius(int aZoomlevel) { - return (tileSize * (1 << aZoomlevel)) / (2.0 * Math.PI); - } - - /** - * Returns the absolut number of pixels in y or x, defined as: 2^Zoomlevel * - * tileSize where tileSize is the width of a tile in pixels - * - * @param aZoomlevel zoom level to request pixel data - * @return number of pixels - */ - public int getMaxPixels(int aZoomlevel) { - return tileSize * (1 << aZoomlevel); - } - - public int falseEasting(int aZoomlevel) { - return getMaxPixels(aZoomlevel) / 2; - } - - public int falseNorthing(int aZoomlevel) { - return -1 * getMaxPixels(aZoomlevel) / 2; - } - - /** - * Transform pixelspace to coordinates and get the distance. - * - * @param x1 the first x coordinate - * @param y1 the first y coordinate - * @param x2 the second x coordinate - * @param y2 the second y coordinate - * - * @param zoomLevel the zoom level - * @return the distance - */ - public double getDistance(int x1, int y1, int x2, int y2, int zoomLevel) { - double la1 = yToLat(y1, zoomLevel); - double lo1 = xToLon(x1, zoomLevel); - double la2 = yToLat(y2, zoomLevel); - double lo2 = xToLon(x2, zoomLevel); - - return getDistance(la1, lo1, la2, lo2); - } - - /** - * Gets the distance using Spherical law of cosines. - * - * @param la1 the Latitude in degrees - * @param lo1 the Longitude in degrees - * @param la2 the Latitude from 2nd coordinate in degrees - * @param lo2 the Longitude from 2nd coordinate in degrees - * @return the distance - */ - public double getDistance(double la1, double lo1, double la2, double lo2) { - double aStartLat = Math.toRadians(la1); - double aStartLong = Math.toRadians(lo1); - double aEndLat = Math.toRadians(la2); - double aEndLong = Math.toRadians(lo2); - - double distance = Math.acos(Math.sin(aStartLat) * Math.sin(aEndLat) - + Math.cos(aStartLat) * Math.cos(aEndLat) - * Math.cos(aEndLong - aStartLong)); - - return EARTH_RADIUS * distance; - } - - /** - * Transform longitude to pixelspace - * - *

- * Mathematical optimization
- * - * x = radius(aZoomlevel) * toRadians(aLongitude) + falseEasting(aZoomLevel)
- * x = getMaxPixels(aZoomlevel) / (2 * PI) * (aLongitude * PI) / 180 + getMaxPixels(aZoomlevel) / 2
- * x = getMaxPixels(aZoomlevel) * aLongitude / 360 + 180 * getMaxPixels(aZoomlevel) / 360
- * x = getMaxPixels(aZoomlevel) * (aLongitude + 180) / 360
- *
- *

- * - * @param aLongitude - * [-180..180] - * @param aZoomlevel zoom level - * @return [0..2^Zoomlevel*TILE_SIZE[ - */ - public double lonToX(double aLongitude, int aZoomlevel) { - int mp = getMaxPixels(aZoomlevel); - double x = (mp * (aLongitude + 180L)) / 360L; - return Math.min(x, mp); - } - - /** - * Transforms latitude to pixelspace - *

- * Mathematical optimization
- * - * log(u) := log((1.0 + sin(toRadians(aLat))) / (1.0 - sin(toRadians(aLat))
- * - * y = -1 * (radius(aZoomlevel) / 2 * log(u)))) - falseNorthing(aZoomlevel))
- * y = -1 * (getMaxPixel(aZoomlevel) / 2 * PI / 2 * log(u)) - -1 * getMaxPixel(aZoomLevel) / 2
- * y = getMaxPixel(aZoomlevel) / (-4 * PI) * log(u)) + getMaxPixel(aZoomLevel) / 2
- * y = getMaxPixel(aZoomlevel) * ((log(u) / (-4 * PI)) + 1/2)
- *
- *

- * @param aLat - * [-90...90] - * @param aZoomlevel zoom level - * @return [0..2^Zoomlevel*TILE_SIZE[ - */ - public double latToY(double aLat, int aZoomlevel) { - if (aLat < MIN_LAT) - aLat = MIN_LAT; - else if (aLat > MAX_LAT) - aLat = MAX_LAT; - double sinLat = Math.sin(Math.toRadians(aLat)); - double log = Math.log((1.0 + sinLat) / (1.0 - sinLat)); - int mp = getMaxPixels(aZoomlevel); - double y = mp * (0.5 - (log / (4.0 * Math.PI))); - return Math.min(y, mp - 1); - } - - /** - * Transforms pixel coordinate X to longitude - * - *

- * Mathematical optimization
- * - * lon = toDegree((aX - falseEasting(aZoomlevel)) / radius(aZoomlevel))
- * lon = 180 / PI * ((aX - getMaxPixels(aZoomlevel) / 2) / getMaxPixels(aZoomlevel) / (2 * PI)
- * lon = 180 * ((aX - getMaxPixels(aZoomlevel) / 2) / getMaxPixels(aZoomlevel))
- * lon = 360 / getMaxPixels(aZoomlevel) * (aX - getMaxPixels(aZoomlevel) / 2)
- * lon = 360 * aX / getMaxPixels(aZoomlevel) - 180
- *
- *

- * @param aX - * [0..2^Zoomlevel*TILE_WIDTH[ - * @param aZoomlevel zoom level - * @return ]-180..180[ - */ - public double xToLon(int aX, int aZoomlevel) { - return ((360d * aX) / getMaxPixels(aZoomlevel)) - 180.0; - } - - /** - * Transforms pixel coordinate Y to latitude - * - * @param aY - * [0..2^Zoomlevel*TILE_WIDTH[ - * @param aZoomlevel zoom level - * @return [MIN_LAT..MAX_LAT] is about [-85..85] - */ - public double yToLat(int aY, int aZoomlevel) { - aY += falseNorthing(aZoomlevel); - double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * aY / radius(aZoomlevel)))); - return -1 * Math.toDegrees(latitude); - } - -} diff --git a/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java b/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java deleted file mode 100644 index b1dd1b64a9f..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java +++ /dev/null @@ -1,196 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadPoolExecutor; - -import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; -import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; -import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; - -/** - * A {@link TileLoader} implementation that loads tiles from OSM. - * - * @author Jan Peter Stotz - */ -public class OsmTileLoader implements TileLoader { - private static final ThreadPoolExecutor jobDispatcher = (ThreadPoolExecutor) Executors.newFixedThreadPool(8); - - private final class OsmTileJob implements TileJob { - private final Tile tile; - private InputStream input; - private boolean force; - - private OsmTileJob(Tile tile) { - this.tile = tile; - } - - @Override - public void run() { - synchronized (tile) { - if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading()) - return; - tile.loaded = false; - tile.error = false; - tile.loading = true; - } - try { - URLConnection conn = loadTileFromOsm(tile); - if (force) { - conn.setUseCaches(false); - } - loadTileMetadata(tile, conn); - if ("no-tile".equals(tile.getValue("tile-info"))) { - tile.setError("No tile at this zoom level"); - } else { - input = conn.getInputStream(); - try { - tile.loadImage(input); - } finally { - input.close(); - input = null; - } - } - tile.setLoaded(true); - listener.tileLoadingFinished(tile, true); - } catch (IOException e) { - tile.setError(e.getMessage()); - listener.tileLoadingFinished(tile, false); - if (input == null) { - try { - System.err.println("Failed loading " + tile.getUrl() +": " - +e.getClass() + ": " + e.getMessage()); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - } finally { - tile.loading = false; - tile.setLoaded(true); - } - } - - @Override - public void submit() { - submit(false); - } - - @Override - public void submit(boolean force) { - this.force = force; - jobDispatcher.execute(this); - } - } - - /** - * Holds the HTTP headers. Insert e.g. User-Agent here when default should not be used. - */ - public Map headers = new HashMap<>(); - - public int timeoutConnect; - public int timeoutRead; - - protected TileLoaderListener listener; - - public OsmTileLoader(TileLoaderListener listener) { - this(listener, null); - } - - public OsmTileLoader(TileLoaderListener listener, Map headers) { - this.headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*"); - if (headers != null) { - this.headers.putAll(headers); - } - this.listener = listener; - } - - @Override - public TileJob createTileLoaderJob(final Tile tile) { - return new OsmTileJob(tile); - } - - protected URLConnection loadTileFromOsm(Tile tile) throws IOException { - URL url; - url = new URL(tile.getUrl()); - URLConnection urlConn = url.openConnection(); - if (urlConn instanceof HttpURLConnection) { - prepareHttpUrlConnection((HttpURLConnection) urlConn); - } - return urlConn; - } - - protected void loadTileMetadata(Tile tile, URLConnection urlConn) { - String str = urlConn.getHeaderField("X-VE-TILEMETA-CaptureDatesRange"); - if (str != null) { - tile.putValue("capture-date", str); - } - str = urlConn.getHeaderField("X-VE-Tile-Info"); - if (str != null) { - tile.putValue("tile-info", str); - } - - Long lng = urlConn.getExpiration(); - if (lng.equals(0L)) { - try { - str = urlConn.getHeaderField("Cache-Control"); - if (str != null) { - for (String token: str.split(",")) { - if (token.startsWith("max-age=")) { - lng = Long.parseLong(token.substring(8)) * 1000 + - System.currentTimeMillis(); - } - } - } - } catch (NumberFormatException e) { - // ignore malformed Cache-Control headers - if (JMapViewer.debug) { - System.err.println(e.getMessage()); - } - } - } - if (!lng.equals(0L)) { - tile.putValue("expires", lng.toString()); - } - } - - protected void prepareHttpUrlConnection(HttpURLConnection urlConn) { - for (Entry e : headers.entrySet()) { - urlConn.setRequestProperty(e.getKey(), e.getValue()); - } - if (timeoutConnect != 0) - urlConn.setConnectTimeout(timeoutConnect); - if (timeoutRead != 0) - urlConn.setReadTimeout(timeoutRead); - } - - @Override - public String toString() { - return getClass().getSimpleName(); - } - - @Override - public boolean hasOutstandingTasks() { - return jobDispatcher.getTaskCount() > jobDispatcher.getCompletedTaskCount(); - } - - @Override - public void cancelOutstandingTasks() { - jobDispatcher.getQueue().clear(); - } - - /** - * Sets the maximum number of concurrent connections the tile loader will do - * @param num number of conncurent connections - */ - public static void setConcurrentConnections(int num) { - jobDispatcher.setMaximumPoolSize(num); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/Projected.java b/src/org/openstreetmap/gui/jmapviewer/Projected.java deleted file mode 100644 index 8c2288892b3..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/Projected.java +++ /dev/null @@ -1,72 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.geom.Point2D; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Objects; - -import org.openstreetmap.gui.jmapviewer.interfaces.IProjected; - -/** - * Projected coordinates represented by an encapsulates a Point2D.Double value. - */ -public class Projected implements IProjected { - private transient Point2D.Double data; - - /** - * Constructs a new {@code Projected}. - * @param east easting - * @param north northing - */ - public Projected(double east, double north) { - data = new Point2D.Double(east, north); - } - - @Override - public double getEast() { - return data.x; - } - - @Override - public double getNorth() { - return data.y; - } - - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeObject(data.x); - out.writeObject(data.y); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - data = new Point2D.Double(); - data.x = (Double) in.readObject(); - data.y = (Double) in.readObject(); - } - - @Override - public String toString() { - return "Projected[" + data.y + ", " + data.x + ']'; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 61 * hash + Objects.hashCode(this.data); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Projected other = (Projected) obj; - return Objects.equals(this.data, other.data); - } -} - diff --git a/src/org/openstreetmap/gui/jmapviewer/Style.java b/src/org/openstreetmap/gui/jmapviewer/Style.java deleted file mode 100644 index cbf9bbc8514..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/Style.java +++ /dev/null @@ -1,73 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Font; -import java.awt.Stroke; - -public class Style { - private Color color; - private Color backColor; - private Stroke stroke; - private Font font; - - private static final AlphaComposite TRANSPARENCY = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); - private static final AlphaComposite OPAQUE = AlphaComposite.getInstance(AlphaComposite.SRC); - - public Style() { - super(); - } - - public Style(Color color, Color backColor, Stroke stroke, Font font) { - super(); - this.color = color; - this.backColor = backColor; - this.stroke = stroke; - this.font = font; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public Color getBackColor() { - return backColor; - } - - public void setBackColor(Color backColor) { - this.backColor = backColor; - } - - public Stroke getStroke() { - return stroke; - } - - public void setStroke(Stroke stroke) { - this.stroke = stroke; - } - - public Font getFont() { - return font; - } - - public void setFont(Font font) { - this.font = font; - } - - private static AlphaComposite getAlphaComposite(Color color) { - return color.getAlpha() == 255 ? OPAQUE : TRANSPARENCY; - } - - public AlphaComposite getAlphaComposite() { - return getAlphaComposite(color); - } - - public AlphaComposite getBackAlphaComposite() { - return getAlphaComposite(backColor); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/Tile.java b/src/org/openstreetmap/gui/jmapviewer/Tile.java deleted file mode 100644 index 9927709f7b2..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/Tile.java +++ /dev/null @@ -1,463 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Callable; - -import javax.imageio.ImageIO; - -import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; -import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; - -/** - * Holds one map tile. Additionally the code for loading the tile image and - * painting it is also included in this class. - * - * @author Jan Peter Stotz - */ -public class Tile { - - /** - * Hourglass image that is displayed until a map tile has been loaded, except for overlay sources - */ - public static final BufferedImage LOADING_IMAGE = loadImage("images/hourglass.png"); - - /** - * Red cross image that is displayed after a loading error, except for overlay sources - */ - public static final BufferedImage ERROR_IMAGE = loadImage("images/error.png"); - - protected TileSource source; - protected int xtile; - protected int ytile; - protected int zoom; - protected BufferedImage image; - protected String key; - protected volatile boolean loaded; // field accessed by multiple threads without any monitors, needs to be volatile - protected volatile boolean loading; - protected volatile boolean error; - protected String error_message; - - /** TileLoader-specific tile metadata */ - protected Map metadata; - - /** - * Creates a tile with empty image. - * - * @param source Tile source - * @param xtile X coordinate - * @param ytile Y coordinate - * @param zoom Zoom level - */ - public Tile(TileSource source, int xtile, int ytile, int zoom) { - this(source, xtile, ytile, zoom, LOADING_IMAGE); - } - - /** - * Creates a tile with specified image. - * - * @param source Tile source - * @param xtile X coordinate - * @param ytile Y coordinate - * @param zoom Zoom level - * @param image Image content - */ - public Tile(TileSource source, int xtile, int ytile, int zoom, BufferedImage image) { - this.source = source; - this.xtile = xtile; - this.ytile = ytile; - this.zoom = zoom; - this.image = image; - this.key = getTileKey(source, xtile, ytile, zoom); - } - - private static BufferedImage loadImage(String path) { - try { - return ImageIO.read(JMapViewer.class.getResourceAsStream(path)); - } catch (IOException | IllegalArgumentException ex) { - ex.printStackTrace(); - return null; - } - } - - private static class CachedCallable implements Callable { - private V result; - private Callable callable; - - /** - * Wraps callable so it is evaluated only once - * @param callable to cache - */ - CachedCallable(Callable callable) { - this.callable = callable; - } - - @Override - public synchronized V call() { - try { - if (result == null) { - result = callable.call(); - } - return result; - } catch (Exception e) { - // this should not happen here - throw new RuntimeException(e); - } - } - } - - /** - * Tries to get tiles of a lower or higher zoom level (one or two level - * difference) from cache and use it as a placeholder until the tile has been loaded. - * @param cache Tile cache - */ - public void loadPlaceholderFromCache(TileCache cache) { - /* - * use LazyTask as creation of BufferedImage is very expensive - * this way we can avoid object creation until we're sure it's needed - */ - final CachedCallable tmpImage = new CachedCallable<>(new Callable() { - @Override - public BufferedImage call() throws Exception { - return new BufferedImage(source.getTileSize(), source.getTileSize(), BufferedImage.TYPE_INT_ARGB); - } - }); - - for (int zoomDiff = 1; zoomDiff < 5; zoomDiff++) { - // first we check if there are already the 2^x tiles - // of a higher detail level - int zoomHigh = zoom + zoomDiff; - if (zoomDiff < 3 && zoomHigh <= JMapViewer.MAX_ZOOM) { - int factor = 1 << zoomDiff; - int xtileHigh = xtile << zoomDiff; - int ytileHigh = ytile << zoomDiff; - final double scale = 1.0 / factor; - - /* - * use LazyTask for graphics to avoid evaluation of tmpImage, until we have - * something to draw - */ - CachedCallable graphics = new CachedCallable<>(new Callable() { - @Override - public Graphics2D call() throws Exception { - Graphics2D g = (Graphics2D) tmpImage.call().getGraphics(); - g.setTransform(AffineTransform.getScaleInstance(scale, scale)); - return g; - } - }); - - int paintedTileCount = 0; - for (int x = 0; x < factor; x++) { - for (int y = 0; y < factor; y++) { - Tile tile = cache.getTile(source, xtileHigh + x, ytileHigh + y, zoomHigh); - if (tile != null && tile.isLoaded()) { - paintedTileCount++; - tile.paint(graphics.call(), x * source.getTileSize(), y * source.getTileSize()); - } - } - } - if (paintedTileCount == factor * factor) { - image = tmpImage.call(); - return; - } - } - - int zoomLow = zoom - zoomDiff; - if (zoomLow >= JMapViewer.MIN_ZOOM) { - int xtileLow = xtile >> zoomDiff; - int ytileLow = ytile >> zoomDiff; - final int factor = 1 << zoomDiff; - final double scale = factor; - CachedCallable graphics = new CachedCallable<>(new Callable() { - @Override - public Graphics2D call() throws Exception { - Graphics2D g = (Graphics2D) tmpImage.call().getGraphics(); - AffineTransform at = new AffineTransform(); - int translateX = (xtile % factor) * source.getTileSize(); - int translateY = (ytile % factor) * source.getTileSize(); - at.setTransform(scale, 0, 0, scale, -translateX, -translateY); - g.setTransform(at); - return g; - } - - }); - - Tile tile = cache.getTile(source, xtileLow, ytileLow, zoomLow); - if (tile != null && tile.isLoaded()) { - tile.paint(graphics.call(), 0, 0); - image = tmpImage.call(); - return; - } - } - } - } - - public TileSource getSource() { - return source; - } - - /** - * Returns the X coordinate. - * @return tile number on the x axis of this tile - */ - public int getXtile() { - return xtile; - } - - /** - * Returns the Y coordinate. - * @return tile number on the y axis of this tile - */ - public int getYtile() { - return ytile; - } - - /** - * Returns the zoom level. - * @return zoom level of this tile - */ - public int getZoom() { - return zoom; - } - - /** - * @return tile indexes of the top left corner as TileXY object - */ - public TileXY getTileXY() { - return new TileXY(xtile, ytile); - } - - public BufferedImage getImage() { - return image; - } - - public void setImage(BufferedImage image) { - this.image = image; - } - - public void loadImage(InputStream input) throws IOException { - setImage(ImageIO.read(input)); - } - - /** - * @return key that identifies a tile - */ - public String getKey() { - return key; - } - - public boolean isLoaded() { - return loaded; - } - - public boolean isLoading() { - return loading; - } - - public void setLoaded(boolean loaded) { - this.loaded = loaded; - } - - public String getUrl() throws IOException { - return source.getTileUrl(zoom, xtile, ytile); - } - - /** - * Paints the tile-image on the {@link Graphics} g at the - * position x/y. - * - * @param g the Graphics object - * @param x x-coordinate in g - * @param y y-coordinate in g - */ - public void paint(Graphics g, int x, int y) { - if (image == null) - return; - g.drawImage(image, x, y, null); - } - - /** - * Paints the tile-image on the {@link Graphics} g at the - * position x/y. - * - * @param g the Graphics object - * @param x x-coordinate in g - * @param y y-coordinate in g - * @param width width that tile should have - * @param height height that tile should have - */ - public void paint(Graphics g, int x, int y, int width, int height) { - if (image == null) - return; - g.drawImage(image, x, y, width, height, null); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(35).append("Tile ").append(key); - if (loading) { - sb.append(" [LOADING...]"); - } - if (loaded) { - sb.append(" [loaded]"); - } - if (error) { - sb.append(" [ERROR]"); - } - return sb.toString(); - } - - /** - * Note that the hash code does not include the {@link #source}. - * Therefore a hash based collection can only contain tiles - * of one {@link #source}. - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + xtile; - result = prime * result + ytile; - result = prime * result + zoom; - return result; - } - - /** - * Compares this object with obj based on - * the fields {@link #xtile}, {@link #ytile} and - * {@link #zoom}. - * The {@link #source} field is ignored. - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Tile other = (Tile) obj; - if (xtile != other.xtile) - return false; - if (ytile != other.ytile) - return false; - if (zoom != other.zoom) - return false; - return getTileSource().equals(other.getTileSource()); - } - - public static String getTileKey(TileSource source, int xtile, int ytile, int zoom) { - return zoom + "/" + xtile + "/" + ytile + "@" + source.getName(); - } - - public String getStatus() { - if (this.error) - return "error"; - if (this.loaded) - return "loaded"; - if (this.loading) - return "loading"; - return "new"; - } - - public boolean hasError() { - return error; - } - - public String getErrorMessage() { - return error_message; - } - - public void setError(Exception e) { - setError(e.toString()); - } - - public void setError(String message) { - error = true; - setImage(ERROR_IMAGE); - error_message = message; - } - - /** - * Puts the given key/value pair to the metadata of the tile. - * If value is null, the (possibly existing) key/value pair is removed from - * the meta data. - * - * @param key Key - * @param value Value - */ - public void putValue(String key, String value) { - if (value == null || value.isEmpty()) { - if (metadata != null) { - metadata.remove(key); - } - return; - } - if (metadata == null) { - metadata = new HashMap<>(); - } - metadata.put(key, value); - } - - /** - * returns the metadata of the Tile - * - * @param key metadata key that should be returned - * @return null if no such metadata exists, or the value of the metadata - */ - public String getValue(String key) { - if (metadata == null) return null; - return metadata.get(key); - } - - /** - * - * @return metadata of the tile - */ - public Map getMetadata() { - if (metadata == null) { - metadata = new HashMap<>(); - } - return metadata; - } - - /** - * indicate that loading process for this tile has started - */ - public void initLoading() { - error = false; - loading = true; - } - - /** - * indicate that loading process for this tile has ended - */ - public void finishLoading() { - loading = false; - loaded = true; - } - - /** - * - * @return TileSource from which this tile comes - */ - public TileSource getTileSource() { - return source; - } - - /** - * indicate that loading process for this tile has been canceled - */ - public void loadingCanceled() { - loading = false; - loaded = false; - } - -} diff --git a/src/org/openstreetmap/gui/jmapviewer/TileController.java b/src/org/openstreetmap/gui/jmapviewer/TileController.java deleted file mode 100644 index 136f11b0796..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/TileController.java +++ /dev/null @@ -1,84 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; -import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; -import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; -import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; - -public class TileController { - protected TileLoader tileLoader; - protected TileCache tileCache; - protected TileSource tileSource; - - public TileController(TileSource source, TileCache tileCache, TileLoaderListener listener) { - this.tileSource = source; - this.tileLoader = new OsmTileLoader(listener); - this.tileCache = tileCache; - } - - /** - * retrieves a tile from the cache. If the tile is not present in the cache - * a load job is added to the working queue of {@link TileLoader}. - * - * @param tilex the X position of the tile - * @param tiley the Y position of the tile - * @param zoom the zoom level of the tile - * @return specified tile from the cache or null if the tile - * was not found in the cache. - */ - public Tile getTile(int tilex, int tiley, int zoom) { - int max = 1 << zoom; - if (tilex < 0 || tilex >= max || tiley < 0 || tiley >= max) - return null; - Tile tile = tileCache.getTile(tileSource, tilex, tiley, zoom); - if (tile == null) { - tile = new Tile(tileSource, tilex, tiley, zoom); - tileCache.addTile(tile); - tile.loadPlaceholderFromCache(tileCache); - } - if (tile.error) { - tile.loadPlaceholderFromCache(tileCache); - } - if (!tile.isLoaded()) { - tileLoader.createTileLoaderJob(tile).submit(); - } - return tile; - } - - public TileCache getTileCache() { - return tileCache; - } - - public void setTileCache(TileCache tileCache) { - this.tileCache = tileCache; - } - - public TileLoader getTileLoader() { - return tileLoader; - } - - public void setTileLoader(TileLoader tileLoader) { - this.tileLoader = tileLoader; - } - - public TileSource getTileLayerSource() { - return tileSource; - } - - public TileSource getTileSource() { - return tileSource; - } - - public void setTileSource(TileSource tileSource) { - this.tileSource = tileSource; - } - - /** - * Removes all jobs from the queue that are currently not being processed. - * - */ - public void cancelOutstandingJobs() { - tileLoader.cancelOutstandingTasks(); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/TileRange.java b/src/org/openstreetmap/gui/jmapviewer/TileRange.java deleted file mode 100644 index 936efb47d38..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/TileRange.java +++ /dev/null @@ -1,57 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -/** - * This is a rectangular range of tiles. - */ -public class TileRange { - protected int minX; - protected int maxX; - protected int minY; - protected int maxY; - protected int zoom; - - protected TileRange() { - } - - /** - * Constructs a new {@code TileRange}. - * @param t1 first tile - * @param t2 second tile - * @param zoom zoom level - */ - public TileRange(TileXY t1, TileXY t2, int zoom) { - minX = (int) Math.floor(Math.min(t1.getX(), t2.getX())); - minY = (int) Math.floor(Math.min(t1.getY(), t2.getY())); - maxX = (int) Math.ceil(Math.max(t1.getX(), t2.getX())); - maxY = (int) Math.ceil(Math.max(t1.getY(), t2.getY())); - this.zoom = zoom; - } - - /** - * Constructs a new {@code TileRange}. - * @param r existing tile range to copy - */ - public TileRange(TileRange r) { - minX = r.minX; - minY = r.minY; - maxX = r.maxX; - maxY = r.maxY; - zoom = r.zoom; - } - - protected double tilesSpanned() { - return Math.sqrt(1.0 * this.size()); - } - - /** - * Returns size - * @return size - */ - public int size() { - int xSpan = maxX - minX + 1; - int ySpan = maxY - minY + 1; - return xSpan * ySpan; - } -} - diff --git a/src/org/openstreetmap/gui/jmapviewer/TileXY.java b/src/org/openstreetmap/gui/jmapviewer/TileXY.java deleted file mode 100644 index ca671ccb611..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/TileXY.java +++ /dev/null @@ -1,62 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer; - -/** - * @author w - * - */ -public class TileXY { - /** - * x index of the tile (horizontal) - */ - private final double x; - - /** - * y number of the tile (vertical) - */ - private final double y; - - /** - * Returns an instance of coordinates. - * - * @param x number of the tile - * @param y number of the tile - */ - public TileXY(double x, double y) { - this.x = x; - this.y = y; - } - - /** - * @return x index of the tile as integer - */ - public int getXIndex() { - return x < 0 ? (int) Math.ceil(x) : (int) Math.floor(x); - } - - /** - * @return y index of the tile as integer - */ - public int getYIndex() { - return y < 0 ? (int) Math.ceil(y) : (int) Math.floor(y); - } - - /** - * @return x index as double, might be non integral, when the point is not topleft corner of the tile - */ - public double getX() { - return x; - } - - /** - * @return y index as double, might be non integral, when the point is not topleft corner of the tile - */ - public double getY() { - return y; - } - - @Override - public String toString() { - return "TileXY{" + x + ", " + y + "}"; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeData.java b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeData.java deleted file mode 100644 index a1b9a2a6977..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeData.java +++ /dev/null @@ -1,52 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.checkBoxTree; - -import org.openstreetmap.gui.jmapviewer.AbstractLayer; -import org.openstreetmap.gui.jmapviewer.LayerGroup; - -/** - * Node Data for checkBox Tree - * - * @author galo - */ -public class CheckBoxNodeData { - private AbstractLayer layer; - - public CheckBoxNodeData(final AbstractLayer layer) { - this.layer = layer; - } - - public CheckBoxNodeData(final String txt) { - this(new LayerGroup(txt)); - } - - public CheckBoxNodeData(final String txt, final Boolean selected) { - this(new LayerGroup(txt)); - layer.setVisible(selected); - } - - public Boolean isSelected() { - return layer.isVisible(); - } - - public void setSelected(final Boolean newValue) { - layer.setVisible(newValue); - } - - public String getText() { - return layer.getName(); - } - - public AbstractLayer getAbstractLayer() { - return layer; - } - - public void setAbstractLayer(final AbstractLayer layer) { - this.layer = layer; - } - - @Override - public String toString() { - return getClass().getSimpleName() + '[' + getText() + '/' + isSelected() + ']'; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java deleted file mode 100644 index 73e2965e683..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java +++ /dev/null @@ -1,103 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.checkBoxTree; - -import java.awt.Component; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.EventObject; - -import javax.swing.AbstractCellEditor; -import javax.swing.JTree; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreeCellEditor; -import javax.swing.tree.TreePath; - -/** - * Editor for checkBox Tree - * - * @author galo - */ -public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor { - /** SerialVersionUID */ - private static final long serialVersionUID = -8921320784224636657L; - - private final CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer(); - - private final CheckBoxTree theTree; - - public CheckBoxNodeEditor(final CheckBoxTree tree) { - theTree = tree; - } - - @Override - public Object getCellEditorValue() { - final CheckBoxNodePanel panel = renderer.getPanel(); - /*final CheckBoxNodeData checkBoxNode = - new CheckBoxNodeData(panel.label.getText(), panel.check.isSelected()); - return checkBoxNode; - CheckBoxNodeData data = search(theTree.rootNode(), panel.label.getText()); - data.setSelected(panel.check.isSelected());*/ - return panel.getData(); - } - /*public CheckBoxNodeData search(DefaultMutableTreeNode node, String name){ - CheckBoxNodeData data = CheckBoxTree.data(node); - if(data.getText().equals(name)) return data; - else{ - data = null; - for(int i=0; iposition specifies the - * coordinates within g - * - * @param g graphics - * @param position coordinates - * @param radius radius - */ - void paint(Graphics g, Point position, int radius); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java deleted file mode 100644 index 150cae82ca9..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java +++ /dev/null @@ -1,32 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Stroke; - -import org.openstreetmap.gui.jmapviewer.Layer; -import org.openstreetmap.gui.jmapviewer.Style; - -public interface MapObject { - - Layer getLayer(); - - void setLayer(Layer layer); - - Style getStyle(); - - Style getStyleAssigned(); - - Color getColor(); - - Color getBackColor(); - - Stroke getStroke(); - - Font getFont(); - - String getName(); - - boolean isVisible(); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java deleted file mode 100644 index a46d936124b..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java +++ /dev/null @@ -1,38 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import java.awt.Graphics; -import java.awt.Point; -import java.awt.Polygon; -import java.util.List; - -/** - * Interface to be implemented by polygons that can be displayed on the map. - * - * @author Vincent Privat - */ -public interface MapPolygon extends MapObject { - - /** - * @return Latitude/Longitude of each point of polygon - */ - List getPoints(); - - /** - * Paints the map polygon on the map. The points - * are specifying the coordinates within g - * - * @param g graphics - * @param points list of points defining the polygon to draw - */ - void paint(Graphics g, List points); - - /** - * Paints the map polygon on the map. The polygon - * is specifying the coordinates within g - * - * @param g graphics - * @param polygon polygon to draw - */ - void paint(Graphics g, Polygon polygon); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java deleted file mode 100644 index 45bc5a318e2..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java +++ /dev/null @@ -1,38 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import java.awt.Graphics; -import java.awt.Point; - -import org.openstreetmap.gui.jmapviewer.Coordinate; -import org.openstreetmap.gui.jmapviewer.JMapViewer; - -/** - * Interface to be implemented by rectangles that can be displayed on the map. - * - * @author Stefan Zeller - * @see JMapViewer#addMapRectangle(MapRectangle) - * @see JMapViewer#getMapRectangleList() - */ -public interface MapRectangle extends MapObject { - - /** - * @return Latitude/Longitude of top left of rectangle - */ - Coordinate getTopLeft(); - - /** - * @return Latitude/Longitude of bottom right of rectangle - */ - Coordinate getBottomRight(); - - /** - * Paints the map rectangle on the map. The topLeft and - * bottomRight are specifying the coordinates within g - * - * @param g graphics structure for painting - * @param topLeft lop left edge of painting region - * @param bottomRight bottom right edge of painting region - */ - void paint(Graphics g, Point topLeft, Point bottomRight); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java deleted file mode 100644 index 1037c9f1e70..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java +++ /dev/null @@ -1,18 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import java.util.Map; - -/** - * Interface for template tile sources, @see TemplatedTMSTileSource - * - * @author Wiktor Niesiobędzki - * @since 1.10 - */ -public interface TemplatedTileSource extends TileSource { - /** - * - * @return headers to be sent with http requests - */ - Map getHeaders(); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java deleted file mode 100644 index ebee50ff2bf..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java +++ /dev/null @@ -1,56 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import org.openstreetmap.gui.jmapviewer.JMapViewer; -import org.openstreetmap.gui.jmapviewer.Tile; - -/** - * Implement this interface for creating your custom tile cache for - * {@link JMapViewer}. - * - * @author Jan Peter Stotz - */ -public interface TileCache { - - /** - * Retrieves a tile from the cache if present, otherwise null - * will be returned. - * - * @param source - * the tile source - * @param x - * tile number on the x axis of the tile to be retrieved - * @param y - * tile number on the y axis of the tile to be retrieved - * @param z - * zoom level of the tile to be retrieved - * @return the requested tile or null if the tile is not - * present in the cache - */ - Tile getTile(TileSource source, int x, int y, int z); - - /** - * Adds a tile to the cache. How long after adding a tile can be retrieved - * via {@link #getTile(TileSource, int, int, int)} is unspecified and depends on the - * implementation. - * - * @param tile the tile to be added - */ - void addTile(Tile tile); - - /** - * @return the number of tiles hold by the cache - */ - int getTileCount(); - - /** - * Clears the cache deleting all tiles from memory. - */ - void clear(); - - /** - * Size of the cache. - * @return maximum number of tiles in cache - */ - int getCacheSize(); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java deleted file mode 100644 index 17f2b1da4cc..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java +++ /dev/null @@ -1,17 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import java.io.File; - -public interface TileClearController { - - void initClearDir(File dir); - - void initClearFiles(File[] files); - - boolean cancel(); - - void fileDeleted(File file); - - void clearFinished(); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java deleted file mode 100644 index 925c5ba22bc..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java +++ /dev/null @@ -1,22 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -/** - * Interface for implementing a tile loading job. Tiles are usually loaded via HTTP - * or from a file. - * - * @author Dirk Stöcker - */ -public interface TileJob extends Runnable { - - /** - * submits download job to backend. - */ - void submit(); - - /** - * submits download job to backend. - * @param force true if the load should skip all the caches (local & remote) - */ - void submit(boolean force); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java deleted file mode 100644 index a4a58cb9697..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java +++ /dev/null @@ -1,40 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import org.openstreetmap.gui.jmapviewer.Tile; - -/** - * Interface for implementing a tile loader. Tiles are usually loaded via HTTP - * or from a file. - * - * @author Jan Peter Stotz - */ -public interface TileLoader { - - /** - * A typical implementation of this function should create and return a - * new {@link TileJob} instance that performs the load action. - * - * @param tile the tile to be loaded - * @return {@link TileJob} implementation that performs the desired load - * action. - */ - TileJob createTileLoaderJob(Tile tile); - - /** - * cancels all outstanding tasks in the queue. This should rollback the state of the tiles in the queue - * to loading = false / loaded = false - */ - void cancelOutstandingTasks(); - - /** - * Determines whether this {@link TileLoader} has tasks which have not completed. - * @return whether this {@link TileLoader} has tasks which have not completed. This answer may well be - * "approximate" given that many implementations will be using mechanisms where a queue's state can change - * during the computation. - */ - default boolean hasOutstandingTasks() { - // default implementation supplied just to make transition easier for external implementors - throw new UnsupportedOperationException("Not implemented"); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java deleted file mode 100644 index f698513d4eb..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java +++ /dev/null @@ -1,20 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import org.openstreetmap.gui.jmapviewer.Tile; - -/** - * This listener listens to successful tile loads. - */ -@FunctionalInterface -public interface TileLoaderListener { - - /** - * Will be called if a new {@link Tile} has been loaded successfully. - * Loaded can mean downloaded or loaded from file cache. - * - * @param tile The tile - * @param success {@code true} if the tile has been loaded successfully, {@code false} otherwise - */ - void tileLoadingFinished(Tile tile, boolean success); -} diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java deleted file mode 100644 index 855d13cf3f9..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java +++ /dev/null @@ -1,279 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.interfaces; - -import java.awt.Point; -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import org.openstreetmap.gui.jmapviewer.JMapViewer; -import org.openstreetmap.gui.jmapviewer.Tile; -import org.openstreetmap.gui.jmapviewer.TileRange; -import org.openstreetmap.gui.jmapviewer.TileXY; - -/** - * - * @author Jan Peter Stotz - */ -public interface TileSource extends Attributed { - - /** - * Specifies the maximum zoom value. The number of zoom levels is [0.. - * {@link #getMaxZoom()}]. - * - * @return maximum zoom value that has to be smaller or equal to - * {@link JMapViewer#MAX_ZOOM} - */ - int getMaxZoom(); - - /** - * Specifies the minimum zoom value. This value is usually 0. - * Only for maps that cover a certain region up to a limited zoom level - * this method should return a value different than 0. - * - * @return minimum zoom value - usually 0 - */ - int getMinZoom(); - - /** - * A tile layer name as displayed to the user. - * - * @return Name of the tile layer - */ - String getName(); - - /** - * A unique id for this tile source. - * - * Unlike the name it has to be unique and has to consist only of characters - * valid for filenames. - * - * @return the id - */ - String getId(); - - /** - * Constructs the tile url. - * - * @param zoom zoom level - * @param tilex X coordinate - * @param tiley Y coordinate - * @return fully qualified url for downloading the specified tile image - * @throws IOException if any I/O error occurs - */ - String getTileUrl(int zoom, int tilex, int tiley) throws IOException; - - /** - * Creates tile identifier that is unique among all tile sources, but the same tile will always - * get the same identifier. Used for creation of cache key. - * - * @param zoom zoom level - * @param tilex X coordinate - * @param tiley Y coordinate - * @return tile identifier - */ - String getTileId(int zoom, int tilex, int tiley); - - /** - * Specifies how large each tile is. - * @return The size of a single tile in pixels. -1 if default size should be used - */ - int getTileSize(); - - /** - * @return default tile size, for this tile source - * TODO: @since - */ - int getDefaultTileSize(); - - /** - * Gets the distance using Spherical law of cosines. - * @param la1 latitude of first point - * @param lo1 longitude of first point - * @param la2 latitude of second point - * @param lo2 longitude of second point - * @return the distance betwen first and second point, in m. - */ - double getDistance(double la1, double lo1, double la2, double lo2); - - /** - * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined). - * @param lon longitude - * @param lat latitude - * @param zoom zoom level - * @return the pixel coordinates - */ - Point latLonToXY(double lat, double lon, int zoom); - - /** - * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined). - * @param point point - * @param zoom zoom level - * @return the pixel coordinates - */ - Point latLonToXY(ICoordinate point, int zoom); - - /** - * Transforms a point in pixel space to longitude/latitude (WGS84). - * @param point point - * @param zoom zoom level - * @return WGS84 Coordinates of given point - */ - ICoordinate xyToLatLon(Point point, int zoom); - - /** - * Transforms a point in pixel space to longitude/latitude (WGS84). - * @param x X coordinate - * @param y Y coordinate - * @param zoom zoom level - * @return WGS84 Coordinates of given point - */ - ICoordinate xyToLatLon(int x, int y, int zoom); - - /** - * Transforms longitude and latitude to tile indices. - * @param lon longitude - * @param lat latitude - * @param zoom zoom level - * @return x and y tile indices - */ - TileXY latLonToTileXY(double lat, double lon, int zoom); - - /** - * Transforms longitude and latitude to tile indices. - * @param point point - * @param zoom zoom level - * @return x and y tile indices - */ - TileXY latLonToTileXY(ICoordinate point, int zoom); - - /** - * Transforms tile indices to longitude and latitude. - * @param xy X/Y tile indices - * @param zoom zoom level - * @return WGS84 coordinates of given tile - */ - ICoordinate tileXYToLatLon(TileXY xy, int zoom); - - /** - * Determines to longitude and latitude of a tile. - * (Refers to the tile origin - upper left tile corner) - * @param tile Tile - * @return WGS84 coordinates of given tile - */ - ICoordinate tileXYToLatLon(Tile tile); - - /** - * Transforms tile indices to longitude and latitude. - * @param x x tile index - * @param y y tile index - * @param zoom zoom level - * @return WGS84 coordinates of given tile - */ - ICoordinate tileXYToLatLon(int x, int y, int zoom); - - /** - * Get maximum x index of tile for specified zoom level. - * @param zoom zoom level - * @return maximum x index of tile for specified zoom level - */ - int getTileXMax(int zoom); - - /** - * Get minimum x index of tile for specified zoom level. - * @param zoom zoom level - * @return minimum x index of tile for specified zoom level - */ - int getTileXMin(int zoom); - - /** - * Get maximum y index of tile for specified zoom level. - * @param zoom zoom level - * @return maximum y index of tile for specified zoom level - */ - int getTileYMax(int zoom); - - /** - * Get minimum y index of tile for specified zoom level - * @param zoom zoom level - * @return minimum y index of tile for specified zoom level - */ - int getTileYMin(int zoom); - - /** - * Determines, if the returned data from TileSource represent "no tile at this zoom level" situation. Detection - * algorithms differ per TileSource, so each TileSource should implement each own specific way. - * - * @param headers HTTP headers from response from TileSource server - * @param statusCode HTTP status code - * @param content byte array representing the data returned from the server - * @return true, if "no tile at this zoom level" situation detected - */ - boolean isNoTileAtZoom(Map> headers, int statusCode, byte[] content); - - /** - * Extracts metadata about the tile based on HTTP headers - * - * @param headers HTTP headers from Tile Source server - * @return tile metadata - */ - Map getMetadata(Map> headers); - - /** - * Convert tile indices (x/y/zoom) into projected coordinates of the tile origin. - * @param x x tile index - * @param y z tile index - * @param zoom zoom level - * @return projected coordinates of the tile origin - */ - IProjected tileXYtoProjected(int x, int y, int zoom); - - /** - * Convert projected coordinates to tile indices. - * @param p projected coordinates - * @param zoom zoom level - * @return corresponding tile index x/y (floating point, truncate to integer - * for tile index) - */ - TileXY projectedToTileXY(IProjected p, int zoom); - - /** - * Check if one tile is inside another tile. - * @param inner the tile that is suspected to be inside the other tile - * @param outer the tile that might contain the first tile - * @return true if first tile is inside second tile (or both are identical), - * false otherwise - */ - boolean isInside(Tile inner, Tile outer); - - /** - * Returns a range of tiles, that cover a given tile, which is - * usually at a different zoom level. - * - * In standard tile layout, 4 tiles cover a tile one zoom lower, 16 tiles - * cover a tile 2 zoom levels below etc. - * If the zoom level of the covering tiles is greater or equal, a single - * tile suffices. - * - * @param tile the tile to cover - * @param newZoom zoom level of the covering tiles - * @return TileRange of all covering tiles at zoom newZoom - */ - TileRange getCoveringTileRange(Tile tile, int newZoom); - - /** - * Get coordinate reference system for this tile source. - * - * E.g. "EPSG:3857" for Google-Mercator. - * @return code for the coordinate reference system in use - */ - String getServerCRS(); - - /** - * Determines if this imagery supports "/dirty" mode (tile re-rendering). - * @return true if it supports "/dirty" mode (tile re-rendering) - */ - default boolean isModTileFeatures() { - return false; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/package.html b/src/org/openstreetmap/gui/jmapviewer/package.html deleted file mode 100644 index 37540a64985..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/package.html +++ /dev/null @@ -1,12 +0,0 @@ - -org.openstreetmap.gui.jmapviewer - -

This package and all sub-packages are belonging to the Java -component JMapViewer -

-

JMapViewer is designed to run as stand-alone component without -any further requirements. Therefore please do not add any code that -depends on other libraries or applications. Only functions and methods -provided by the runtime library of Java 8 should be used.

- - diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java deleted file mode 100644 index 49976f3e9f8..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java +++ /dev/null @@ -1,69 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.awt.Image; - -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; - -/** - * Abstract class for OSM Tile sources - */ -public abstract class AbstractOsmTileSource extends TMSTileSource { - - /** - * The OSM attribution. Must be always in line with - * https://www.openstreetmap.org/copyright/en - */ - public static final String DEFAULT_OSM_ATTRIBUTION = "\u00a9 OpenStreetMap contributors"; - - /** - * Constructs a new OSM tile source - * @param name Source name as displayed in GUI - * @param baseUrl Source URL - * @param id unique id for the tile source; contains only characters that - * are safe for file names; can be null - */ - public AbstractOsmTileSource(String name, String baseUrl, String id) { - super(new TileSourceInfo(name, baseUrl, id)); - } - - @Override - public int getMaxZoom() { - return 19; - } - - @Override - public boolean requiresAttribution() { - return true; - } - - @Override - public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) { - return DEFAULT_OSM_ATTRIBUTION; - } - - @Override - public String getAttributionLinkURL() { - return "https://openstreetmap.org/"; - } - - @Override - public Image getAttributionImage() { - return null; - } - - @Override - public String getAttributionImageURL() { - return null; - } - - @Override - public String getTermsOfUseText() { - return null; - } - - @Override - public String getTermsOfUseURL() { - return "https://www.openstreetmap.org/copyright"; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java deleted file mode 100644 index 4a698e3be40..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java +++ /dev/null @@ -1,248 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.awt.Point; -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.openstreetmap.gui.jmapviewer.OsmMercator; -import org.openstreetmap.gui.jmapviewer.Tile; -import org.openstreetmap.gui.jmapviewer.TileXY; -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; - -/** - * Class generalizing all tile based tile sources - * - * @author Wiktor Niesiobędzki - * - */ -public abstract class AbstractTMSTileSource extends AbstractTileSource { - - protected String name; - protected String baseUrl; - protected String id; - private final Map> noTileHeaders; - private final Map> noTileChecksums; - private final Map metadataHeaders; - protected boolean modTileFeatures; - protected int tileSize; - - /** - * Creates an instance based on TileSource information - * - * @param info description of the Tile Source - */ - public AbstractTMSTileSource(TileSourceInfo info) { - this.name = info.getName(); - this.baseUrl = info.getUrl(); - if (baseUrl != null && baseUrl.endsWith("/")) { - baseUrl = baseUrl.substring(0, baseUrl.length()-1); - } - this.id = info.getUrl(); - this.noTileHeaders = info.getNoTileHeaders(); - this.noTileChecksums = info.getNoTileChecksums(); - this.metadataHeaders = info.getMetadataHeaders(); - this.modTileFeatures = info.isModTileFeatures(); - this.tileSize = info.getTileSize(); - } - - /** - * @return default tile size to use, when not set in Imagery Preferences - */ - @Override - public int getDefaultTileSize() { - return OsmMercator.DEFAUL_TILE_SIZE; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getId() { - return id; - } - - @Override - public int getMaxZoom() { - return 21; - } - - @Override - public int getMinZoom() { - return 0; - } - - /** - * @return image extension, used for URL creation - */ - public String getExtension() { - return "png"; - } - - /** - * @param zoom level of the tile - * @param tilex tile number in x axis - * @param tiley tile number in y axis - * @return String containg path part of URL of the tile - * @throws IOException when subclass cannot return the tile URL - */ - public String getTilePath(int zoom, int tilex, int tiley) throws IOException { - return "/" + zoom + "/" + tilex + "/" + tiley + "." + getExtension(); - } - - /** - * @return Base part of the URL of the tile source - */ - public String getBaseUrl() { - return this.baseUrl; - } - - @Override - public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { - return this.getBaseUrl() + getTilePath(zoom, tilex, tiley); - } - - @Override - public String toString() { - return getName(); - } - - /* - * Most tilesources use OsmMercator projection. - */ - @Override - public int getTileSize() { - if (tileSize <= 0) { - return getDefaultTileSize(); - } - return tileSize; - } - - @Override - public Point latLonToXY(ICoordinate point, int zoom) { - return latLonToXY(point.getLat(), point.getLon(), zoom); - } - - @Override - public ICoordinate xyToLatLon(Point point, int zoom) { - return xyToLatLon(point.x, point.y, zoom); - } - - @Override - public TileXY latLonToTileXY(ICoordinate point, int zoom) { - return latLonToTileXY(point.getLat(), point.getLon(), zoom); - } - - @Override - public ICoordinate tileXYToLatLon(TileXY xy, int zoom) { - return tileXYToLatLon(xy.getXIndex(), xy.getYIndex(), zoom); - } - - @Override - public ICoordinate tileXYToLatLon(Tile tile) { - return tileXYToLatLon(tile.getXtile(), tile.getYtile(), tile.getZoom()); - } - - @Override - public int getTileXMax(int zoom) { - return getTileMax(zoom); - } - - @Override - public int getTileXMin(int zoom) { - return 0; - } - - @Override - public int getTileYMax(int zoom) { - return getTileMax(zoom); - } - - @Override - public int getTileYMin(int zoom) { - return 0; - } - - @Override - public boolean isNoTileAtZoom(Map> headers, int statusCode, byte[] content) { - if (noTileHeaders != null && headers != null) { - for (Entry> searchEntry: noTileHeaders.entrySet()) { - List headerVals = headers.get(searchEntry.getKey()); - if (headerVals != null) { - for (String headerValue: headerVals) { - for (String val: searchEntry.getValue()) { - if (headerValue.matches(val)) { - return true; - } - } - } - } - } - } - if (noTileChecksums != null && content != null) { - for (Entry> searchEntry: noTileChecksums.entrySet()) { - MessageDigest md = null; - try { - md = MessageDigest.getInstance(searchEntry.getKey()); - } catch (NoSuchAlgorithmException e) { - break; - } - byte[] byteDigest = md.digest(content); - final int len = byteDigest.length; - - char[] hexChars = new char[len * 2]; - for (int i = 0, j = 0; i < len; i++) { - final int v = byteDigest[i]; - int vn = (v & 0xf0) >> 4; - hexChars[j++] = (char) (vn + (vn >= 10 ? 'a'-10 : '0')); - vn = (v & 0xf); - hexChars[j++] = (char) (vn + (vn >= 10 ? 'a'-10 : '0')); - } - for (String val: searchEntry.getValue()) { - if (new String(hexChars).equalsIgnoreCase(val)) { - return true; - } - } - } - } - return super.isNoTileAtZoom(headers, statusCode, content); - } - - @Override - public Map getMetadata(Map> headers) { - Map ret = new HashMap<>(); - if (metadataHeaders != null && headers != null) { - for (Entry searchEntry: metadataHeaders.entrySet()) { - List headerVals = headers.get(searchEntry.getKey()); - if (headerVals != null) { - for (String headerValue: headerVals) { - ret.put(searchEntry.getValue(), headerValue); - } - } - } - } - return ret; - } - - @Override - public String getTileId(int zoom, int tilex, int tiley) { - return this.baseUrl + "/" + zoom + "/" + tilex + "/" + tiley; - } - - @Override - public boolean isModTileFeatures() { - return modTileFeatures; - } - - private static int getTileMax(int zoom) { - return (int) Math.pow(2.0, zoom) - 1; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java deleted file mode 100644 index 6a935543e81..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java +++ /dev/null @@ -1,85 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.awt.Image; -import java.util.List; -import java.util.Map; - -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; -import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; - -public abstract class AbstractTileSource implements TileSource { - - protected String attributionText; - protected String attributionLinkURL; - protected Image attributionImage; - protected String attributionImageURL; - protected String termsOfUseText; - protected String termsOfUseURL; - - @Override - public boolean requiresAttribution() { - return attributionText != null || attributionLinkURL != null || attributionImage != null - || termsOfUseText != null || termsOfUseURL != null; - } - - @Override - public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) { - return attributionText; - } - - @Override - public String getAttributionLinkURL() { - return attributionLinkURL; - } - - @Override - public Image getAttributionImage() { - return attributionImage; - } - - @Override - public String getAttributionImageURL() { - return attributionImageURL; - } - - @Override - public String getTermsOfUseText() { - return termsOfUseText; - } - - @Override - public String getTermsOfUseURL() { - return termsOfUseURL; - } - - public void setAttributionText(String attributionText) { - this.attributionText = attributionText; - } - - public void setAttributionLinkURL(String attributionLinkURL) { - this.attributionLinkURL = attributionLinkURL; - } - - public void setAttributionImage(Image attributionImage) { - this.attributionImage = attributionImage; - } - - public void setAttributionImageURL(String attributionImageURL) { - this.attributionImageURL = attributionImageURL; - } - - public void setTermsOfUseText(String termsOfUseText) { - this.termsOfUseText = termsOfUseText; - } - - public void setTermsOfUseURL(String termsOfUseURL) { - this.termsOfUseURL = termsOfUseURL; - } - - @Override - public boolean isNoTileAtZoom(Map> headers, int statusCode, byte[] content) { - // default handler - when HTTP 404 is returned, then treat this situation as no tile at this zoom level - return statusCode == 404; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java deleted file mode 100644 index 8cf439fff80..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java +++ /dev/null @@ -1,313 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.awt.Image; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.regex.Pattern; - -import javax.imageio.ImageIO; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.openstreetmap.gui.jmapviewer.Coordinate; -import org.openstreetmap.gui.jmapviewer.JMapViewer; -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * Tile source for the Bing Maps REST Imagery API. - * @see MSDN - */ -public class BingAerialTileSource extends TMSTileSource { - - private static final String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU"; - private static volatile Future> attributions; // volatile is required for getAttribution(), see below. - private static String imageUrlTemplate; - private static Integer imageryZoomMax; - private static String[] subdomains; - - private static final Pattern subdomainPattern = Pattern.compile("\\{subdomain\\}"); - private static final Pattern quadkeyPattern = Pattern.compile("\\{quadkey\\}"); - private static final Pattern culturePattern = Pattern.compile("\\{culture\\}"); - private String brandLogoUri; - - /** - * Constructs a new {@code BingAerialTileSource}. - */ - public BingAerialTileSource() { - super(new TileSourceInfo("Bing", null, null)); - } - - /** - * Constructs a new {@code BingAerialTileSource}. - * @param info imagery info - */ - public BingAerialTileSource(TileSourceInfo info) { - super(info); - } - - protected static class Attribution { - private String attributionText; - private int minZoom; - private int maxZoom; - private Coordinate min; - private Coordinate max; - } - - @Override - public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { - // make sure that attribution is loaded. otherwise subdomains is null. - if (getAttribution() == null) - throw new IOException("Attribution is not loaded yet"); - - int t = (zoom + tilex + tiley) % subdomains.length; - String subdomain = subdomains[t]; - - String url = imageUrlTemplate; - url = subdomainPattern.matcher(url).replaceAll(subdomain); - url = quadkeyPattern.matcher(url).replaceAll(computeQuadTree(zoom, tilex, tiley)); - - return url; - } - - protected URL getAttributionUrl() throws MalformedURLException { - return new URL("https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&output=xml&key=" - + API_KEY); - } - - protected List parseAttributionText(InputSource xml) throws IOException { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document document = builder.parse(xml); - - XPathFactory xPathFactory = XPathFactory.newInstance(); - XPath xpath = xPathFactory.newXPath(); - imageUrlTemplate = xpath.compile("//ImageryMetadata/ImageUrl/text()").evaluate(document).replace( - "http://ecn.{subdomain}.tiles.virtualearth.net/", - "https://ecn.{subdomain}.tiles.virtualearth.net/"); - imageUrlTemplate = culturePattern.matcher(imageUrlTemplate).replaceAll(Locale.getDefault().toString()); - imageryZoomMax = Integer.valueOf(xpath.compile("//ImageryMetadata/ZoomMax/text()").evaluate(document)); - - NodeList subdomainTxt = (NodeList) xpath.compile("//ImageryMetadata/ImageUrlSubdomains/string/text()") - .evaluate(document, XPathConstants.NODESET); - subdomains = new String[subdomainTxt.getLength()]; - for (int i = 0; i < subdomainTxt.getLength(); i++) { - subdomains[i] = subdomainTxt.item(i).getNodeValue(); - } - - brandLogoUri = xpath.compile("/Response/BrandLogoUri/text()").evaluate(document); - - XPathExpression attributionXpath = xpath.compile("Attribution/text()"); - XPathExpression coverageAreaXpath = xpath.compile("CoverageArea"); - XPathExpression zoomMinXpath = xpath.compile("ZoomMin/text()"); - XPathExpression zoomMaxXpath = xpath.compile("ZoomMax/text()"); - XPathExpression southLatXpath = xpath.compile("BoundingBox/SouthLatitude/text()"); - XPathExpression westLonXpath = xpath.compile("BoundingBox/WestLongitude/text()"); - XPathExpression northLatXpath = xpath.compile("BoundingBox/NorthLatitude/text()"); - XPathExpression eastLonXpath = xpath.compile("BoundingBox/EastLongitude/text()"); - - NodeList imageryProviderNodes = (NodeList) xpath.compile("//ImageryMetadata/ImageryProvider") - .evaluate(document, XPathConstants.NODESET); - List attributionsList = new ArrayList<>(imageryProviderNodes.getLength()); - for (int i = 0; i < imageryProviderNodes.getLength(); i++) { - Node providerNode = imageryProviderNodes.item(i); - - String attribution = attributionXpath.evaluate(providerNode); - - NodeList coverageAreaNodes = (NodeList) coverageAreaXpath.evaluate(providerNode, XPathConstants.NODESET); - for (int j = 0; j < coverageAreaNodes.getLength(); j++) { - Node areaNode = coverageAreaNodes.item(j); - Attribution attr = new Attribution(); - attr.attributionText = attribution; - - attr.maxZoom = Integer.parseInt(zoomMaxXpath.evaluate(areaNode)); - attr.minZoom = Integer.parseInt(zoomMinXpath.evaluate(areaNode)); - - Double southLat = Double.valueOf(southLatXpath.evaluate(areaNode)); - Double northLat = Double.valueOf(northLatXpath.evaluate(areaNode)); - Double westLon = Double.valueOf(westLonXpath.evaluate(areaNode)); - Double eastLon = Double.valueOf(eastLonXpath.evaluate(areaNode)); - attr.min = new Coordinate(southLat, westLon); - attr.max = new Coordinate(northLat, eastLon); - - attributionsList.add(attr); - } - } - - return attributionsList; - } catch (SAXException e) { - System.err.println("Could not parse Bing aerials attribution metadata."); - e.printStackTrace(); - } catch (ParserConfigurationException | XPathExpressionException | NumberFormatException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public int getMaxZoom() { - if (imageryZoomMax != null) - return imageryZoomMax; - else - return 22; - } - - @Override - public boolean requiresAttribution() { - return true; - } - - @Override - public String getAttributionLinkURL() { - // Terms of Use URL to comply with Bing Terms of Use - // (the requirement is that we have such a link at the bottom of the window) - return "https://www.microsoft.com/maps/assets/docs/terms.aspx"; - } - - @Override - public Image getAttributionImage() { - try { - final InputStream imageResource = JMapViewer.class.getResourceAsStream("images/bing_maps.png"); - if (imageResource != null) { - return ImageIO.read(imageResource); - } else { - // Some Linux distributions (like Debian) will remove Bing logo from sources, so get it at runtime - for (int i = 0; i < 5 && getAttribution() == null; i++) { - // Makes sure attribution is loaded - if (JMapViewer.debug) { - System.out.println("Bing attribution attempt " + (i+1)); - } - } - if (brandLogoUri != null && !brandLogoUri.isEmpty()) { - System.out.println("Reading Bing logo from "+brandLogoUri); - return ImageIO.read(new URL(brandLogoUri)); - } - } - } catch (IOException e) { - System.err.println("Error while retrieving Bing logo: "+e.getMessage()); - } - return null; - } - - @Override - public String getAttributionImageURL() { - return "https://opengeodata.org/microsoft-imagery-details"; - } - - @Override - public String getTermsOfUseText() { - return null; - } - - @Override - public String getTermsOfUseURL() { - return "https://opengeodata.org/microsoft-imagery-details"; - } - - protected Callable> getAttributionLoaderCallable() { - return new Callable>() { - - @Override - public List call() throws Exception { - int waitTimeSec = 1; - while (true) { - try { - InputSource xml = new InputSource(getAttributionUrl().openStream()); - List r = parseAttributionText(xml); - System.out.println("Successfully loaded Bing attribution data."); - return r; - } catch (IOException ex) { - System.err.println("Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds."); - Thread.sleep(TimeUnit.SECONDS.toMillis(waitTimeSec)); - waitTimeSec *= 2; - } - } - } - }; - } - - protected List getAttribution() { - if (attributions == null) { - // see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html - synchronized (BingAerialTileSource.class) { - if (attributions == null) { - final FutureTask> loader = new FutureTask<>(getAttributionLoaderCallable()); - new Thread(loader, "bing-attribution-loader").start(); - attributions = loader; - } - } - } - try { - return attributions.get(0, TimeUnit.MILLISECONDS); - } catch (TimeoutException ex) { - System.err.println("Bing: attribution data is not yet loaded."); - } catch (ExecutionException ex) { - throw new RuntimeException(ex.getCause()); - } catch (InterruptedException ign) { - System.err.println("InterruptedException: " + ign.getMessage()); - } - return null; - } - - @Override - public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) { - try { - final List data = getAttribution(); - if (data == null) - return "Error loading Bing attribution data"; - StringBuilder a = new StringBuilder(); - for (Attribution attr : data) { - if (zoom <= attr.maxZoom && zoom >= attr.minZoom) { - if (topLeft.getLon() < attr.max.getLon() && botRight.getLon() > attr.min.getLon() - && topLeft.getLat() > attr.min.getLat() && botRight.getLat() < attr.max.getLat()) { - a.append(attr.attributionText); - a.append(' '); - } - } - } - return a.toString(); - } catch (RuntimeException e) { - e.printStackTrace(); - } - return "Error loading Bing attribution data"; - } - - private static String computeQuadTree(int zoom, int tilex, int tiley) { - StringBuilder k = new StringBuilder(); - for (int i = zoom; i > 0; i--) { - char digit = 48; - int mask = 1 << (i - 1); - if ((tilex & mask) != 0) { - digit += (char) 1; - } - if ((tiley & mask) != 0) { - digit += (char) 2; - } - k.append(digit); - } - return k.toString(); - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java deleted file mode 100644 index 745fe852104..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java +++ /dev/null @@ -1,127 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.io.IOException; - -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; - -/** - * OSM Tile source. - */ -public class OsmTileSource { - - /** - * The default "Mapnik" OSM tile source. - */ - public static class Mapnik extends AbstractOsmTileSource { - - private static final String PATTERN = "https://%s.tile.openstreetmap.org"; - - private static final String[] SERVER = {"a", "b", "c"}; - - private int serverNum; - - /** - * Constructs a new {@code "Mapnik"} tile source. - */ - public Mapnik() { - super("Mapnik", PATTERN, "MAPNIK"); - modTileFeatures = true; - } - - @Override - public String getBaseUrl() { - String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]}); - serverNum = (serverNum + 1) % SERVER.length; - return url; - } - } - - /** - * The "Cycle Map" OSM tile source. - */ - public static class CycleMap extends AbstractOsmTileSource { - - private static final String PATTERN = "http://%s.tile.opencyclemap.org/cycle"; - - private static final String[] SERVER = {"a", "b", "c"}; - - private int serverNum; - - /** - * Constructs a new {@code CycleMap} tile source. - */ - public CycleMap() { - super("Cyclemap", PATTERN, "opencyclemap"); - } - - @Override - public String getBaseUrl() { - String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]}); - serverNum = (serverNum + 1) % SERVER.length; - return url; - } - - @Override - public int getMaxZoom() { - return 18; - } - } - - /** - * The "Transport Map" OSM tile source. - * - * Template for thunderforest.com. - */ - public abstract static class TransportMap extends AbstractOsmTileSource { - - private static final String PATTERN = "https://%s.tile.thunderforest.com/transport"; - - private static final String[] SERVER = {"a", "b", "c"}; - - private int serverNum; - - /** - * Constructs a new {@code TransportMap} tile source. - */ - public TransportMap() { - super("OSM Transport Map", PATTERN, "osmtransportmap"); - } - - /** - * Get the thunderforest API key. - * - * Needs to be registered at their web site. - * @return the API key - */ - protected abstract String getApiKey(); - - @Override - public String getBaseUrl() { - String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]}); - serverNum = (serverNum + 1) % SERVER.length; - return url; - } - - @Override - public int getMaxZoom() { - return 18; - } - - @Override - public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { - return this.getBaseUrl() + getTilePath(zoom, tilex, tiley) + "?apikey=" + getApiKey(); - } - - @Override - public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) { - return "Maps © Thunderforest, Data © OpenStreetMap contributors"; - } - - @Override - public String getAttributionLinkURL() { - return "http://www.thunderforest.com/"; - } - } - -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java deleted file mode 100644 index ab3a1588b86..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java +++ /dev/null @@ -1,196 +0,0 @@ -// License: BSD or GPL. For details, see Readme.txt file. -// Authors of this file, namely Gleb Smirnoff and Andrey Boltenkov, allow -// to reuse the code under BSD license. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.awt.Point; -import java.util.Random; - -import org.openstreetmap.gui.jmapviewer.Coordinate; -import org.openstreetmap.gui.jmapviewer.OsmMercator; -import org.openstreetmap.gui.jmapviewer.TileXY; -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; - -/** - * This tilesource uses different to OsmMercator projection. - * - * Earth is assumed an ellipsoid in this projection, unlike - * sphere in OsmMercator, so latitude calculation differs a lot. - * - * The longitude calculation is the same as in OsmMercator, - * we inherit it from AbstractTMSTileSource. - * - * TODO: correct getDistance() method. - */ -public class ScanexTileSource extends TMSTileSource { - private static final String DEFAULT_URL = "http://maps.kosmosnimki.ru"; - private static final int DEFAULT_MAXZOOM = 14; - private static final String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7"; - - private enum ScanexLayer { - IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B"), - SPOT("spot", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=F51CE95441284AF6B2FC319B609C7DEC"); - - private final String name; - private final String uri; - - ScanexLayer(String name, String uri) { - this.name = name; - this.uri = uri; - } - - public String getName() { - return name; - } - - public String getUri() { - return uri; - } - } - - /** IRS by default */ - private ScanexLayer layer = ScanexLayer.IRS; - private TemplatedTMSTileSource TemplateSource = null; - - /** cached latitude used in {@link #tileYToLat(double, int)} */ - private double cachedLat; - - /** - * Constructs a new {@code ScanexTileSource}. - * @param info tile source info - */ - public ScanexTileSource(TileSourceInfo info) { - super(info); - String url = info.getUrl(); - - /** - * The formulae in tileYToLat() and latToTileY() have 2^8 - * hardcoded in them, so explicitly state that. For now - * the assignment matches OsmMercator.DEFAUL_TILE_SIZE, and - * thus is extraneous. But let it be there just in case if - * OsmMercator changes. - */ - this.tileSize = 256; - - for (ScanexLayer slayer : ScanexLayer.values()) { - if (url.equalsIgnoreCase(slayer.getName())) { - this.layer = slayer; - // Override baseUrl and maxZoom in base class. - this.baseUrl = DEFAULT_URL; - if (maxZoom == 0) - this.maxZoom = DEFAULT_MAXZOOM; - return; - } - } - /** If not "irs" or "spot" keyword, then a custom URL. */ - TemplatedTMSTileSource.checkUrl(info.getUrl()); - this.TemplateSource = new TemplatedTMSTileSource(info); - } - - @Override - public String getExtension() { - return "jpeg"; - } - - @Override - public String getTileUrl(int zoom, int tilex, int tiley) { - if (this.TemplateSource != null) - return this.TemplateSource.getTileUrl(zoom, tilex, tiley); - else - return this.getBaseUrl() + getTilePath(zoom, tilex, tiley); - } - - @Override - public String getTilePath(int zoom, int tilex, int tiley) { - int tmp = (int) Math.pow(2.0, zoom - 1); - - tilex = tilex - tmp; - tiley = tmp - tiley - 1; - - return this.layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom; - } - - // Latitude to Y and back calculations. - private static final double RADIUS_E = 6378137; /* radius of Earth at equator, m */ - private static final double EQUATOR = 40075016.68557849; /* equator length, m */ - private static final double E = 0.0818191908426; /* eccentricity of Earth's ellipsoid */ - - @Override - public Point latLonToXY(double lat, double lon, int zoom) { - return new Point( - (int) Math.round(osmMercator.lonToX(lon, zoom)), - (int) Math.round(latToTileY(lat, zoom)) - ); - } - - @Override - public ICoordinate xyToLatLon(int x, int y, int zoom) { - return new Coordinate( - tileYToLat(y, zoom), - osmMercator.xToLon(x, zoom) - ); - } - - @Override - public TileXY latLonToTileXY(double lat, double lon, int zoom) { - return new TileXY( - osmMercator.lonToX(lon, zoom) / getTileSize(), - latToTileY(lat, zoom) - ); - } - - @Override - public ICoordinate tileXYToLatLon(int x, int y, int zoom) { - return new Coordinate( - tileYToLat(y, zoom), - osmMercator.xToLon(x * getTileSize(), zoom) - ); - } - - private double latToTileY(double lat, int zoom) { - double tmp = Math.tan(Math.PI/4 * (1 + lat/90)); - double pow = Math.pow(Math.tan(Math.PI/4 + Math.asin(E * Math.sin(Math.toRadians(lat)))/2), E); - - return (EQUATOR/2 - (RADIUS_E * Math.log(tmp/pow))) * Math.pow(2.0, zoom) / EQUATOR; - } - - /* - * To solve inverse formula latitude = f(y) we use - * Newton's method. We cache previous calculated latitude, - * because new one is usually close to the old one. In case - * if solution gets out of bounds, we reset to a new random value. - */ - private double tileYToLat(double y, int zoom) { - double lat0; - double lat = cachedLat; - do { - lat0 = lat; - lat = lat - Math.toDegrees(nextTerm(Math.toRadians(lat), y, zoom)); - if (lat > OsmMercator.MAX_LAT || lat < OsmMercator.MIN_LAT) { - Random r = new Random(); - lat = OsmMercator.MIN_LAT + - r.nextInt((int) (OsmMercator.MAX_LAT - OsmMercator.MIN_LAT)); - } - } while (Math.abs(lat0 - lat) > 0.000001); - - cachedLat = lat; - - return lat; - } - - /* Next term in Newton's polynomial */ - private static double nextTerm(double lat, double y, int zoom) { - double sinl = Math.sin(lat); - double cosl = Math.cos(lat); - - zoom = (int) Math.pow(2.0, zoom - 1); - double ec = Math.exp((1 - y/zoom)*Math.PI); - - double f = Math.tan(Math.PI/4+lat/2) - - ec * Math.pow(Math.tan(Math.PI/4 + Math.asin(E * sinl)/2), E); - double df = 1/(1 - sinl) - ec * E * cosl/((1 - E * sinl) * - (Math.sqrt(1 - E * E * sinl * sinl))); - - return f/df; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java deleted file mode 100644 index ea1c0aeb767..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java +++ /dev/null @@ -1,122 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.awt.Point; - -import org.openstreetmap.gui.jmapviewer.Coordinate; -import org.openstreetmap.gui.jmapviewer.OsmMercator; -import org.openstreetmap.gui.jmapviewer.Projected; -import org.openstreetmap.gui.jmapviewer.Tile; -import org.openstreetmap.gui.jmapviewer.TileRange; -import org.openstreetmap.gui.jmapviewer.TileXY; -import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; -import org.openstreetmap.gui.jmapviewer.interfaces.IProjected; - -/** - * TMS tile source. - */ -public class TMSTileSource extends AbstractTMSTileSource { - - protected int maxZoom; - protected int minZoom; - protected OsmMercator osmMercator; - - /** - * Constructs a new {@code TMSTileSource}. - * @param info tile source information - */ - public TMSTileSource(TileSourceInfo info) { - super(info); - minZoom = info.getMinZoom(); - maxZoom = info.getMaxZoom(); - this.osmMercator = new OsmMercator(this.getTileSize()); - } - - @Override - public int getMinZoom() { - return (minZoom == 0) ? super.getMinZoom() : minZoom; - } - - @Override - public int getMaxZoom() { - return (maxZoom == 0) ? super.getMaxZoom() : maxZoom; - } - - @Override - public double getDistance(double lat1, double lon1, double lat2, double lon2) { - return osmMercator.getDistance(lat1, lon1, lat2, lon2); - } - - @Override - public Point latLonToXY(double lat, double lon, int zoom) { - return new Point( - (int) Math.round(osmMercator.lonToX(lon, zoom)), - (int) Math.round(osmMercator.latToY(lat, zoom)) - ); - } - - @Override - public ICoordinate xyToLatLon(int x, int y, int zoom) { - return new Coordinate( - osmMercator.yToLat(y, zoom), - osmMercator.xToLon(x, zoom) - ); - } - - @Override - public TileXY latLonToTileXY(double lat, double lon, int zoom) { - return new TileXY( - osmMercator.lonToX(lon, zoom) / getTileSize(), - osmMercator.latToY(lat, zoom) / getTileSize() - ); - } - - @Override - public ICoordinate tileXYToLatLon(int x, int y, int zoom) { - return new Coordinate( - osmMercator.yToLat(y * getTileSize(), zoom), - osmMercator.xToLon(x * getTileSize(), zoom) - ); - } - - @Override - public IProjected tileXYtoProjected(int x, int y, int zoom) { - double mercatorWidth = 2 * Math.PI * OsmMercator.EARTH_RADIUS; - double f = mercatorWidth * getTileSize() / osmMercator.getMaxPixels(zoom); - return new Projected(f * x - mercatorWidth / 2, -(f * y - mercatorWidth / 2)); - } - - @Override - public TileXY projectedToTileXY(IProjected p, int zoom) { - double mercatorWidth = 2 * Math.PI * OsmMercator.EARTH_RADIUS; - double f = mercatorWidth * getTileSize() / osmMercator.getMaxPixels(zoom); - return new TileXY((p.getEast() + mercatorWidth / 2) / f, (-p.getNorth() + mercatorWidth / 2) / f); - } - - @Override - public boolean isInside(Tile inner, Tile outer) { - int dz = inner.getZoom() - outer.getZoom(); - if (dz < 0) return false; - return outer.getXtile() == inner.getXtile() >> dz && - outer.getYtile() == inner.getYtile() >> dz; - } - - @Override - public TileRange getCoveringTileRange(Tile tile, int newZoom) { - if (newZoom <= tile.getZoom()) { - int dz = tile.getZoom() - newZoom; - TileXY xy = new TileXY(tile.getXtile() >> dz, tile.getYtile() >> dz); - return new TileRange(xy, xy, newZoom); - } else { - int dz = newZoom - tile.getZoom(); - TileXY t1 = new TileXY(tile.getXtile() << dz, tile.getYtile() << dz); - TileXY t2 = new TileXY(t1.getX() + (1 << dz) - 1, t1.getY() + (1 << dz) - 1); - return new TileRange(t1, t2, newZoom); - } - } - - @Override - public String getServerCRS() { - return "EPSG:3857"; - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java deleted file mode 100644 index 00aa032f371..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java +++ /dev/null @@ -1,136 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.util.HashMap; -import java.util.Map; -import java.util.Random; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource; - -/** - * Handles templated TMS Tile Source. Templated means, that some patterns within - * URL gets substituted. - * - * Supported parameters - * {zoom} - substituted with zoom level - * {z} - as above - * {NUMBER-zoom} - substituted with result of equation "NUMBER - zoom", - * eg. {20-zoom} for zoom level 15 will result in 5 in this place - * {zoom+number} - substituted with result of equation "zoom + number", - * eg. {zoom+5} for zoom level 15 will result in 20. - * {x} - substituted with X tile number - * {y} - substituted with Y tile number - * {!y} - substituted with Yahoo Y tile number - * {-y} - substituted with reversed Y tile number - * {switch:VAL_A,VAL_B,VAL_C,...} - substituted with one of VAL_A, VAL_B, VAL_C. Usually - * used to specify many tile servers - * {header:(HEADER_NAME,HEADER_VALUE)} - sets the headers to be sent to tile server - */ -public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTileSource { - - private Random rand; - private String[] randomParts; - private final Map headers = new HashMap<>(); - - // CHECKSTYLE.OFF: SingleSpaceSeparator - private static final String COOKIE_HEADER = "Cookie"; - private static final String PATTERN_ZOOM = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}"; - private static final String PATTERN_X = "\\{x\\}"; - private static final String PATTERN_Y = "\\{y\\}"; - private static final String PATTERN_Y_YAHOO = "\\{!y\\}"; - private static final String PATTERN_NEG_Y = "\\{-y\\}"; - private static final String PATTERN_SWITCH = "\\{switch:([^}]+)\\}"; - private static final String PATTERN_HEADER = "\\{header\\(([^,]+),([^}]+)\\)\\}"; - // CHECKSTYLE.ON: SingleSpaceSeparator - - private static final String[] ALL_PATTERNS = { - PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH - }; - - /** - * Creates Templated TMS Tile Source based on ImageryInfo - * @param info imagery info - */ - public TemplatedTMSTileSource(TileSourceInfo info) { - super(info); - String cookies = info.getCookies(); - if (cookies != null && !cookies.isEmpty()) { - headers.put(COOKIE_HEADER, cookies); - } - handleTemplate(); - } - - private void handleTemplate() { - // Capturing group pattern on switch values - Matcher m = Pattern.compile(".*"+PATTERN_SWITCH+".*").matcher(baseUrl); - if (m.matches()) { - rand = new Random(); - randomParts = m.group(1).split(","); - } - Pattern pattern = Pattern.compile(PATTERN_HEADER); - StringBuffer output = new StringBuffer(); - Matcher matcher = pattern.matcher(baseUrl); - while (matcher.find()) { - headers.put(matcher.group(1), matcher.group(2)); - matcher.appendReplacement(output, ""); - } - matcher.appendTail(output); - baseUrl = output.toString(); - } - - @Override - public Map getHeaders() { - return headers; - } - - @Override - public String getTileUrl(int zoom, int tilex, int tiley) { - int finalZoom = zoom; - Matcher m = Pattern.compile(".*"+PATTERN_ZOOM+".*").matcher(this.baseUrl); - if (m.matches()) { - if (m.group(1) != null) { - finalZoom = Integer.parseInt(m.group(1))-zoom; - } - if (m.group(2) != null) { - String ofs = m.group(2); - if (ofs.startsWith("+")) - ofs = ofs.substring(1); - finalZoom += Integer.parseInt(ofs); - } - } - String r = this.baseUrl - .replaceAll(PATTERN_ZOOM, Integer.toString(finalZoom)) - .replaceAll(PATTERN_X, Integer.toString(tilex)) - .replaceAll(PATTERN_Y, Integer.toString(tiley)) - .replaceAll(PATTERN_Y_YAHOO, Integer.toString((int) Math.pow(2, zoom-1)-1-tiley)) - .replaceAll(PATTERN_NEG_Y, Integer.toString((int) Math.pow(2, zoom)-1-tiley)); - if (rand != null) { - r = r.replaceAll(PATTERN_SWITCH, randomParts[rand.nextInt(randomParts.length)]); - } - return r; - } - - /** - * Checks if url is acceptable by this Tile Source - * @param url URL to check - */ - public static void checkUrl(String url) { - assert url != null && !"".equals(url) : "URL cannot be null or empty"; - Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(url); - while (m.find()) { - boolean isSupportedPattern = false; - for (String pattern : ALL_PATTERNS) { - if (m.group().matches(pattern)) { - isSupportedPattern = true; - break; - } - } - if (!isSupportedPattern) { - throw new IllegalArgumentException( - m.group() + " is not a valid TMS argument. Please check this server URL:\n" + url); - } - } - } -} diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java deleted file mode 100644 index fcd596a2d3c..00000000000 --- a/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java +++ /dev/null @@ -1,209 +0,0 @@ -// License: GPL. For details, see Readme.txt file. -package org.openstreetmap.gui.jmapviewer.tilesources; - -import java.util.Map; -import java.util.Set; - -/** - * Data class that keeps basic information about a tile source. - * - * @since 31122 - */ -public class TileSourceInfo { - /** id for this imagery entry, optional at the moment */ - protected String id; - - /** URL of the imagery service */ - protected String url; - - /** name of the imagery layer */ - protected String name; - - /** headers meaning, that there is no tile at this zoom level */ - protected Map> noTileHeaders; - - /** checksum of empty tiles */ - protected Map> noTileChecksums; - - /** minimum zoom level supported by the tile source */ - protected int minZoom; - - /** maximum zoom level supported by the tile source */ - protected int maxZoom; - - /** cookies that needs to be sent to tile source */ - protected String cookies = ""; - - /** tile size of the displayed tiles */ - protected int tileSize = -1; - - /** mapping <header key, metadata key> */ - protected Map metadataHeaders; - - /** supports "/status" and "/dirty" mode (tile re-rendering) */ - protected boolean modTileFeatures; - - /** - * Create a TileSourceInfo class - * - * @param name name - * @param baseUrl base URL - * @param id unique id - */ - public TileSourceInfo(String name, String baseUrl, String id) { - this.name = name; - this.url = baseUrl; - this.id = id; - } - - /** - * Create a TileSourceInfo class - * - * @param name name - */ - public TileSourceInfo(String name) { - this(name, null, null); - } - - /** - * Creates empty TileSourceInfo class - */ - public TileSourceInfo() { - this(null, null, null); - } - - /** - * Request name of the tile source - * @return name of the tile source - */ - public final String getName() { - return name; - } - - /** - * Request URL of the tile source - * @return url of the tile source - */ - public final String getUrl() { - return url; - } - - /** - * Request ID of the tile source. Id can be null. This gets the configured id as is. - * Due to a user error, this may not be unique. - * @return id of the tile source - */ - public final String getId() { - return id; - } - - /** - * Request header information for empty tiles for servers delivering such tile types - * @return map of headers, that when set, means that this is "no tile at this zoom level" situation - * @since 32022 - */ - public Map> getNoTileHeaders() { - return noTileHeaders; - } - - /** - * Checkusm for empty tiles for servers delivering such tile types - * @return map of checksums, that when detected, means that this is "no tile at this zoom level" situation - * @since 32022 - */ - public Map> getNoTileChecksums() { - return noTileChecksums; - } - - /** - * Request supported minimum zoom level - * @return minimum zoom level supported by tile source - */ - public int getMinZoom() { - return minZoom; - } - - /** - * Request supported maximum zoom level - * @return maximum zoom level supported by tile source - */ - public int getMaxZoom() { - return maxZoom; - } - - /** - * Request cookies to be sent together with request - * @return cookies to be sent along with request to tile source - */ - public String getCookies() { - return cookies; - } - - /** - * Request tile size of this tile source - * @return tile size provided by this tile source, or -1 when default value should be used - */ - public int getTileSize() { - return tileSize; - } - - /** - * Request metadata headers - * @return mapping <HTTP header name, Metadata key name> for copying HTTP headers to Tile metadata - * @since 31125 - */ - public Map getMetadataHeaders() { - return metadataHeaders; - } - - /** - * Sets the tile size provided by this tile source - * @param tileSize tile size in pixels - */ - public final void setTileSize(int tileSize) { - if (tileSize == 0 || tileSize < -1) { - throw new AssertionError("Invalid tile size: " + tileSize); - } - this.tileSize = tileSize; - } - - /** - * Sets the tile URL. - * @param url tile URL - */ - public final void setUrl(String url) { - this.url = url; - } - - /** - * Sets the tile name. - * @param name tile name - */ - public final void setName(String name) { - this.name = name; - } - - /** - * Sets the tile id. - * @param id tile id - */ - public final void setId(String id) { - this.id = id; - } - - /** - * Determines if this imagery supports "/status" and "/dirty" mode (tile re-rendering). - * @return true if it supports "/status" and "/dirty" mode (tile re-rendering) - */ - public final boolean isModTileFeatures() { - return modTileFeatures; - } - - /** - * Sets whether this imagery supports "/status" and "/dirty" mode (tile re-rendering). - * @param modTileFeatures true if it supports "/status" and "/dirty" mode (tile re-rendering) - */ - public final void setModTileFeatures(boolean modTileFeatures) { - this.modTileFeatures = modTileFeatures; - } -} diff --git a/test/lib/awaitility-3.1.0.jar b/test/lib/awaitility-3.1.0.jar deleted file mode 100644 index de42efc7e46..00000000000 Binary files a/test/lib/awaitility-3.1.0.jar and /dev/null differ diff --git a/test/lib/commons-testing/commons-testing-2.1.0.jar b/test/lib/commons-testing/commons-testing-2.1.0.jar deleted file mode 100644 index bb7a2e5334b..00000000000 Binary files a/test/lib/commons-testing/commons-testing-2.1.0.jar and /dev/null differ diff --git a/test/lib/equalsverifier-2.4.4.jar b/test/lib/equalsverifier-2.4.4.jar deleted file mode 100644 index bcf51ac4cbc..00000000000 Binary files a/test/lib/equalsverifier-2.4.4.jar and /dev/null differ diff --git a/test/lib/fest/MRJToolkitStubs-1.0.jar b/test/lib/fest/MRJToolkitStubs-1.0.jar deleted file mode 100644 index 3cdb47d649a..00000000000 Binary files a/test/lib/fest/MRJToolkitStubs-1.0.jar and /dev/null differ diff --git a/test/lib/fest/debug-1.0.jar b/test/lib/fest/debug-1.0.jar deleted file mode 100644 index 646e94dc8e5..00000000000 Binary files a/test/lib/fest/debug-1.0.jar and /dev/null differ diff --git a/test/lib/fest/fest-assert-1.0.jar b/test/lib/fest/fest-assert-1.0.jar deleted file mode 100644 index ad3a0d8f081..00000000000 Binary files a/test/lib/fest/fest-assert-1.0.jar and /dev/null differ diff --git a/test/lib/fest/fest-reflect-1.1.jar b/test/lib/fest/fest-reflect-1.1.jar deleted file mode 100644 index 8943bb71e10..00000000000 Binary files a/test/lib/fest/fest-reflect-1.1.jar and /dev/null differ diff --git a/test/lib/fest/fest-swing-1.1.jar b/test/lib/fest/fest-swing-1.1.jar deleted file mode 100644 index b2f19a7c94c..00000000000 Binary files a/test/lib/fest/fest-swing-1.1.jar and /dev/null differ diff --git a/test/lib/fest/fest-util-1.0.jar b/test/lib/fest/fest-util-1.0.jar deleted file mode 100644 index 4f4fc9f92cf..00000000000 Binary files a/test/lib/fest/fest-util-1.0.jar and /dev/null differ diff --git a/test/lib/fest/jcip-annotations-1.0.jar b/test/lib/fest/jcip-annotations-1.0.jar deleted file mode 100644 index 9ca41331f9d..00000000000 Binary files a/test/lib/fest/jcip-annotations-1.0.jar and /dev/null differ diff --git a/test/lib/jfcunit.jar b/test/lib/jfcunit.jar deleted file mode 100644 index df3792efd4c..00000000000 Binary files a/test/lib/jfcunit.jar and /dev/null differ diff --git a/test/lib/junit/hamcrest-core-1.3.jar b/test/lib/junit/hamcrest-core-1.3.jar deleted file mode 100644 index 9d5fe16e3dd..00000000000 Binary files a/test/lib/junit/hamcrest-core-1.3.jar and /dev/null differ diff --git a/test/lib/junit/junit-4.12.jar b/test/lib/junit/junit-4.12.jar deleted file mode 100644 index 3a7fc266c3e..00000000000 Binary files a/test/lib/junit/junit-4.12.jar and /dev/null differ diff --git a/test/lib/reflections/guava-21.0.jar b/test/lib/reflections/guava-21.0.jar deleted file mode 100644 index 0618195945f..00000000000 Binary files a/test/lib/reflections/guava-21.0.jar and /dev/null differ diff --git a/test/lib/reflections/javassist-3.21.0-GA.jar b/test/lib/reflections/javassist-3.21.0-GA.jar deleted file mode 100644 index 64549c4adae..00000000000 Binary files a/test/lib/reflections/javassist-3.21.0-GA.jar and /dev/null differ diff --git a/test/lib/reflections/reflections-0.9.10.jar b/test/lib/reflections/reflections-0.9.10.jar deleted file mode 100644 index c255641827d..00000000000 Binary files a/test/lib/reflections/reflections-0.9.10.jar and /dev/null differ diff --git a/test/lib/system-rules-1.16.1.jar b/test/lib/system-rules-1.16.1.jar deleted file mode 100644 index 3ead4d5842d..00000000000 Binary files a/test/lib/system-rules-1.16.1.jar and /dev/null differ diff --git a/test/lib/unitils-core/commons-collections-3.2.2.jar b/test/lib/unitils-core/commons-collections-3.2.2.jar deleted file mode 100644 index fa5df82a630..00000000000 Binary files a/test/lib/unitils-core/commons-collections-3.2.2.jar and /dev/null differ diff --git a/test/lib/unitils-core/commons-lang-2.6.jar b/test/lib/unitils-core/commons-lang-2.6.jar deleted file mode 100644 index 98467d3a653..00000000000 Binary files a/test/lib/unitils-core/commons-lang-2.6.jar and /dev/null differ diff --git a/test/lib/unitils-core/commons-logging-1.1.3.jar b/test/lib/unitils-core/commons-logging-1.1.3.jar deleted file mode 100644 index ab5125407a6..00000000000 Binary files a/test/lib/unitils-core/commons-logging-1.1.3.jar and /dev/null differ diff --git a/test/lib/unitils-core/ognl-2.6.9.jar b/test/lib/unitils-core/ognl-2.6.9.jar deleted file mode 100644 index 0f1c0fb5139..00000000000 Binary files a/test/lib/unitils-core/ognl-2.6.9.jar and /dev/null differ diff --git a/test/lib/unitils-core/unitils-core-3.4.6.jar b/test/lib/unitils-core/unitils-core-3.4.6.jar deleted file mode 100644 index 08c2c939baf..00000000000 Binary files a/test/lib/unitils-core/unitils-core-3.4.6.jar and /dev/null differ diff --git a/test/lib/wiremock-standalone-2.15.0.jar b/test/lib/wiremock-standalone-2.15.0.jar deleted file mode 100644 index 042a051f8f7..00000000000 Binary files a/test/lib/wiremock-standalone-2.15.0.jar and /dev/null differ diff --git a/tools/animal-sniffer-ant-tasks.jar b/tools/animal-sniffer-ant-tasks.jar deleted file mode 100644 index b584df442f4..00000000000 Binary files a/tools/animal-sniffer-ant-tasks.jar and /dev/null differ diff --git a/tools/appbundler-1.0ea.jar b/tools/appbundler-1.0ea.jar deleted file mode 100644 index 65e775a888e..00000000000 Binary files a/tools/appbundler-1.0ea.jar and /dev/null differ diff --git a/tools/checkstyle/checkstyle-all.jar b/tools/checkstyle/checkstyle-all.jar deleted file mode 100644 index a95f81efb1a..00000000000 Binary files a/tools/checkstyle/checkstyle-all.jar and /dev/null differ diff --git a/tools/commons-cli-1.3.1.jar b/tools/commons-cli-1.3.1.jar deleted file mode 100644 index c3e7a1f47f8..00000000000 Binary files a/tools/commons-cli-1.3.1.jar and /dev/null differ diff --git a/tools/error_prone_ant.jar b/tools/error_prone_ant.jar deleted file mode 100644 index 80cf45d0376..00000000000 Binary files a/tools/error_prone_ant.jar and /dev/null differ diff --git a/tools/groovy-all.jar b/tools/groovy-all.jar deleted file mode 100644 index 3c4f8f357d1..00000000000 Binary files a/tools/groovy-all.jar and /dev/null differ diff --git a/tools/ivy/ivy.jar b/tools/ivy/ivy.jar new file mode 100644 index 00000000000..14ff88e2601 Binary files /dev/null and b/tools/ivy/ivy.jar differ diff --git a/tools/jacocoant.jar b/tools/jacocoant.jar deleted file mode 100644 index 34067786385..00000000000 Binary files a/tools/jacocoant.jar and /dev/null differ diff --git a/tools/javacc.jar b/tools/javacc.jar deleted file mode 100644 index 97cba470cc2..00000000000 Binary files a/tools/javacc.jar and /dev/null differ diff --git a/tools/pmd/antlr-runtime-3.5.2.jar b/tools/pmd/antlr-runtime-3.5.2.jar deleted file mode 100644 index d48e3e86796..00000000000 Binary files a/tools/pmd/antlr-runtime-3.5.2.jar and /dev/null differ diff --git a/tools/pmd/asm-6.1.1.jar b/tools/pmd/asm-6.1.1.jar deleted file mode 100644 index 35b934d69d5..00000000000 Binary files a/tools/pmd/asm-6.1.1.jar and /dev/null differ diff --git a/tools/pmd/commons-io-2.4.jar b/tools/pmd/commons-io-2.4.jar deleted file mode 100644 index 90035a4fe06..00000000000 Binary files a/tools/pmd/commons-io-2.4.jar and /dev/null differ diff --git a/tools/pmd/commons-lang3-3.7.jar b/tools/pmd/commons-lang3-3.7.jar deleted file mode 100644 index f37ded60fe6..00000000000 Binary files a/tools/pmd/commons-lang3-3.7.jar and /dev/null differ diff --git a/tools/pmd/flowless-0.6.jar b/tools/pmd/flowless-0.6.jar deleted file mode 100644 index 1c6ae46a2f0..00000000000 Binary files a/tools/pmd/flowless-0.6.jar and /dev/null differ diff --git a/tools/pmd/jaxen-1.1.6.jar b/tools/pmd/jaxen-1.1.6.jar deleted file mode 100644 index 52f47a4f433..00000000000 Binary files a/tools/pmd/jaxen-1.1.6.jar and /dev/null differ diff --git a/tools/pmd/pmd-core-6.4.0-SNAPSHOT.jar b/tools/pmd/pmd-core-6.4.0-SNAPSHOT.jar deleted file mode 100644 index a75a4df65d1..00000000000 Binary files a/tools/pmd/pmd-core-6.4.0-SNAPSHOT.jar and /dev/null differ diff --git a/tools/pmd/pmd-java-6.4.0-SNAPSHOT.jar b/tools/pmd/pmd-java-6.4.0-SNAPSHOT.jar deleted file mode 100644 index 84e24175a58..00000000000 Binary files a/tools/pmd/pmd-java-6.4.0-SNAPSHOT.jar and /dev/null differ diff --git a/tools/pmd/pmd-ui-6.3.0.jar b/tools/pmd/pmd-ui-6.3.0.jar deleted file mode 100644 index e8f5b503040..00000000000 Binary files a/tools/pmd/pmd-ui-6.3.0.jar and /dev/null differ diff --git a/tools/pmd/reactfx-2.0-M5.jar b/tools/pmd/reactfx-2.0-M5.jar deleted file mode 100644 index 14859e1ec67..00000000000 Binary files a/tools/pmd/reactfx-2.0-M5.jar and /dev/null differ diff --git a/tools/pmd/richtextfx-0.8.1.jar b/tools/pmd/richtextfx-0.8.1.jar deleted file mode 100644 index a5ac7ad4cc9..00000000000 Binary files a/tools/pmd/richtextfx-0.8.1.jar and /dev/null differ diff --git a/tools/pmd/saxon-9.1.0.8-dom.jar b/tools/pmd/saxon-9.1.0.8-dom.jar deleted file mode 100644 index 6ded01e446d..00000000000 Binary files a/tools/pmd/saxon-9.1.0.8-dom.jar and /dev/null differ diff --git a/tools/pmd/saxon-9.1.0.8.jar b/tools/pmd/saxon-9.1.0.8.jar deleted file mode 100644 index de236e50a22..00000000000 Binary files a/tools/pmd/saxon-9.1.0.8.jar and /dev/null differ diff --git a/tools/pmd/undofx-1.3.1.jar b/tools/pmd/undofx-1.3.1.jar deleted file mode 100644 index 8f19d542d5a..00000000000 Binary files a/tools/pmd/undofx-1.3.1.jar and /dev/null differ diff --git a/tools/pmd/wellbehavedfx-0.3.jar b/tools/pmd/wellbehavedfx-0.3.jar deleted file mode 100644 index 0e572883ddf..00000000000 Binary files a/tools/pmd/wellbehavedfx-0.3.jar and /dev/null differ diff --git a/tools/proguard.jar b/tools/proguard.jar deleted file mode 100644 index 9a89cb6f845..00000000000 Binary files a/tools/proguard.jar and /dev/null differ diff --git a/tools/spotbugs/asm-6.1.1.jar b/tools/spotbugs/asm-6.1.1.jar deleted file mode 100644 index 35b934d69d5..00000000000 Binary files a/tools/spotbugs/asm-6.1.1.jar and /dev/null differ diff --git a/tools/spotbugs/asm-analysis-6.1.1.jar b/tools/spotbugs/asm-analysis-6.1.1.jar deleted file mode 100644 index 187774fab25..00000000000 Binary files a/tools/spotbugs/asm-analysis-6.1.1.jar and /dev/null differ diff --git a/tools/spotbugs/asm-commons-6.1.1.jar b/tools/spotbugs/asm-commons-6.1.1.jar deleted file mode 100644 index 0cd2d69d243..00000000000 Binary files a/tools/spotbugs/asm-commons-6.1.1.jar and /dev/null differ diff --git a/tools/spotbugs/asm-tree-6.1.1.jar b/tools/spotbugs/asm-tree-6.1.1.jar deleted file mode 100644 index 890c14d1c1c..00000000000 Binary files a/tools/spotbugs/asm-tree-6.1.1.jar and /dev/null differ diff --git a/tools/spotbugs/asm-util-6.1.1.jar b/tools/spotbugs/asm-util-6.1.1.jar deleted file mode 100644 index 3f92ea72f93..00000000000 Binary files a/tools/spotbugs/asm-util-6.1.1.jar and /dev/null differ diff --git a/tools/spotbugs/asm-xml-6.1.1.jar b/tools/spotbugs/asm-xml-6.1.1.jar deleted file mode 100644 index 83239cccba4..00000000000 Binary files a/tools/spotbugs/asm-xml-6.1.1.jar and /dev/null differ diff --git a/tools/spotbugs/bcel-6.2.jar b/tools/spotbugs/bcel-6.2.jar deleted file mode 100644 index 7ff0a9f1c65..00000000000 Binary files a/tools/spotbugs/bcel-6.2.jar and /dev/null differ diff --git a/tools/spotbugs/commons-lang-2.6.jar b/tools/spotbugs/commons-lang-2.6.jar deleted file mode 100644 index 98467d3a653..00000000000 Binary files a/tools/spotbugs/commons-lang-2.6.jar and /dev/null differ diff --git a/tools/spotbugs/dom4j-2.1.0.jar b/tools/spotbugs/dom4j-2.1.0.jar deleted file mode 100644 index 80acf320a12..00000000000 Binary files a/tools/spotbugs/dom4j-2.1.0.jar and /dev/null differ diff --git a/tools/spotbugs/jFormatString-3.0.0.jar b/tools/spotbugs/jFormatString-3.0.0.jar deleted file mode 100644 index bdcb8466ba3..00000000000 Binary files a/tools/spotbugs/jFormatString-3.0.0.jar and /dev/null differ diff --git a/tools/spotbugs/jaxen-1.1.6.jar b/tools/spotbugs/jaxen-1.1.6.jar deleted file mode 100644 index 52f47a4f433..00000000000 Binary files a/tools/spotbugs/jaxen-1.1.6.jar and /dev/null differ diff --git a/tools/spotbugs/jcip-annotations-1.0.jar b/tools/spotbugs/jcip-annotations-1.0.jar deleted file mode 100644 index 06e9066b880..00000000000 Binary files a/tools/spotbugs/jcip-annotations-1.0.jar and /dev/null differ diff --git a/tools/spotbugs/jsr305-3.0.2.jar b/tools/spotbugs/jsr305-3.0.2.jar deleted file mode 100644 index 59222d9ca5e..00000000000 Binary files a/tools/spotbugs/jsr305-3.0.2.jar and /dev/null differ diff --git a/tools/spotbugs/spotbugs-annotations.jar b/tools/spotbugs/spotbugs-annotations.jar deleted file mode 100644 index bc5c83d8bd8..00000000000 Binary files a/tools/spotbugs/spotbugs-annotations.jar and /dev/null differ diff --git a/tools/spotbugs/spotbugs-ant.jar b/tools/spotbugs/spotbugs-ant.jar deleted file mode 100644 index 9fb48dffd84..00000000000 Binary files a/tools/spotbugs/spotbugs-ant.jar and /dev/null differ diff --git a/tools/spotbugs/spotbugs.jar b/tools/spotbugs/spotbugs.jar deleted file mode 100644 index 1cd0da171b4..00000000000 Binary files a/tools/spotbugs/spotbugs.jar and /dev/null differ diff --git a/tools/xmltask.jar b/tools/xmltask.jar deleted file mode 100644 index 76019461503..00000000000 Binary files a/tools/xmltask.jar and /dev/null differ