mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-01 00:00:02 -04:00
Re-added test case lost in large merge
- Removed imageio-jmagick (again) - Removed internal Maven repo - fixed line endings on a number of files to avoid a humongous merge diff when getting changes into upstream - Re-enabled a few tests
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<parent>
|
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
|
||||||
<artifactId>imageio</artifactId>
|
|
||||||
<version>3.0-ece-1</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>imageio-jmagick</artifactId>
|
|
||||||
<name>TwelveMonkeys :: ImageIO :: JMagick Plugin</name>
|
|
||||||
<description>
|
|
||||||
<![CDATA[
|
|
||||||
ImageIO wrapper for JMagick.
|
|
||||||
See the <a href="http://www.yeo.id.au/jmagick/">JMagick Home page</a>
|
|
||||||
for more information.]]>
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
|
||||||
<artifactId>imageio-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
|
||||||
<artifactId>imageio-core</artifactId>
|
|
||||||
<classifier>tests</classifier>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>jmagick</groupId>
|
|
||||||
<artifactId>jmagick</artifactId>
|
|
||||||
<version>6.2.4</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
-2
@@ -951,7 +951,6 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testReadSubsamplingNotSkippingLines1028() throws IOException {
|
public void testReadSubsamplingNotSkippingLines1028() throws IOException {
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/read-error1028.jpg")));
|
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/read-error1028.jpg")));
|
||||||
@@ -1016,7 +1015,6 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testReadSubsamplingNotSkippingLines1025() throws IOException {
|
public void testReadSubsamplingNotSkippingLines1025() throws IOException {
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/read-error1025.jpg")));
|
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/read-error1025.jpg")));
|
||||||
|
|||||||
@@ -234,11 +234,4 @@
|
|||||||
</plugins>
|
</plugins>
|
||||||
</reporting>
|
</reporting>
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<snapshotRepository>
|
|
||||||
<id>central</id>
|
|
||||||
<url>http://repo.dev.escenic.com/content/repositories/thirdparty-snapshots</url>
|
|
||||||
<uniqueVersion>false</uniqueVersion>
|
|
||||||
</snapshotRepository>
|
|
||||||
</distributionManagement>
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,90 +1,90 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.io.enc;
|
package com.twelvemonkeys.io.enc;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code Encoder} implementation for standard DEFLATE encoding.
|
* {@code Encoder} implementation for standard DEFLATE encoding.
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java#2 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DeflateEncoder.java#2 $
|
||||||
*
|
*
|
||||||
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
|
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
|
||||||
* @see Deflater
|
* @see Deflater
|
||||||
* @see InflateDecoder
|
* @see InflateDecoder
|
||||||
* @see java.util.zip.DeflaterOutputStream
|
* @see java.util.zip.DeflaterOutputStream
|
||||||
*/
|
*/
|
||||||
final class DeflateEncoder implements Encoder {
|
final class DeflateEncoder implements Encoder {
|
||||||
|
|
||||||
private final Deflater deflater;
|
private final Deflater deflater;
|
||||||
private final byte[] buffer = new byte[1024];
|
private final byte[] buffer = new byte[1024];
|
||||||
|
|
||||||
public DeflateEncoder() {
|
public DeflateEncoder() {
|
||||||
this(new Deflater(Deflater.DEFAULT_COMPRESSION, true)); // TODO: Should we use "no wrap"?
|
this(new Deflater(Deflater.DEFAULT_COMPRESSION, true)); // TODO: Should we use "no wrap"?
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeflateEncoder(final Deflater pDeflater) {
|
public DeflateEncoder(final Deflater pDeflater) {
|
||||||
if (pDeflater == null) {
|
if (pDeflater == null) {
|
||||||
throw new IllegalArgumentException("deflater == null");
|
throw new IllegalArgumentException("deflater == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
deflater = pDeflater;
|
deflater = pDeflater;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void encode(final OutputStream stream, ByteBuffer buffer)
|
public void encode(final OutputStream stream, ByteBuffer buffer)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
System.out.println("DeflateEncoder.encode");
|
System.out.println("DeflateEncoder.encode");
|
||||||
deflater.setInput(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
|
deflater.setInput(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
|
||||||
flushInputToStream(stream);
|
flushInputToStream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void flushInputToStream(final OutputStream pStream) throws IOException {
|
private void flushInputToStream(final OutputStream pStream) throws IOException {
|
||||||
System.out.println("DeflateEncoder.flushInputToStream");
|
System.out.println("DeflateEncoder.flushInputToStream");
|
||||||
|
|
||||||
if (deflater.needsInput()) {
|
if (deflater.needsInput()) {
|
||||||
System.out.println("Foo");
|
System.out.println("Foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!deflater.needsInput()) {
|
while (!deflater.needsInput()) {
|
||||||
int deflated = deflater.deflate(buffer, 0, buffer.length);
|
int deflated = deflater.deflate(buffer, 0, buffer.length);
|
||||||
pStream.write(buffer, 0, deflated);
|
pStream.write(buffer, 0, deflated);
|
||||||
System.out.println("flushed " + deflated);
|
System.out.println("flushed " + deflated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void flush() {
|
// public void flush() {
|
||||||
// deflater.finish();
|
// deflater.finish();
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
+109
-109
@@ -1,110 +1,110 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.io.enc;
|
package com.twelvemonkeys.io.enc;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code Decoder} implementation for standard DEFLATE encoding.
|
* {@code Decoder} implementation for standard DEFLATE encoding.
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
|
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
|
||||||
*
|
*
|
||||||
* @see Inflater
|
* @see Inflater
|
||||||
* @see DeflateEncoder
|
* @see DeflateEncoder
|
||||||
* @see java.util.zip.InflaterInputStream
|
* @see java.util.zip.InflaterInputStream
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java#2 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java#2 $
|
||||||
*/
|
*/
|
||||||
final class InflateDecoder implements Decoder {
|
final class InflateDecoder implements Decoder {
|
||||||
|
|
||||||
private final Inflater inflater;
|
private final Inflater inflater;
|
||||||
|
|
||||||
private final byte[] buffer;
|
private final byte[] buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@code InflateDecoder}
|
* Creates an {@code InflateDecoder}
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public InflateDecoder() {
|
public InflateDecoder() {
|
||||||
this(new Inflater(true));
|
this(new Inflater(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@code InflateDecoder}
|
* Creates an {@code InflateDecoder}
|
||||||
*
|
*
|
||||||
* @param pInflater the inflater instance to use
|
* @param pInflater the inflater instance to use
|
||||||
*/
|
*/
|
||||||
public InflateDecoder(final Inflater pInflater) {
|
public InflateDecoder(final Inflater pInflater) {
|
||||||
if (pInflater == null) {
|
if (pInflater == null) {
|
||||||
throw new IllegalArgumentException("inflater == null");
|
throw new IllegalArgumentException("inflater == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
inflater = pInflater;
|
inflater = pInflater;
|
||||||
buffer = new byte[1024];
|
buffer = new byte[1024];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int decode(final InputStream stream, final ByteBuffer buffer) throws IOException {
|
public int decode(final InputStream stream, final ByteBuffer buffer) throws IOException {
|
||||||
try {
|
try {
|
||||||
int decoded;
|
int decoded;
|
||||||
|
|
||||||
while ((decoded = inflater.inflate(buffer.array(), buffer.arrayOffset(), buffer.capacity())) == 0) {
|
while ((decoded = inflater.inflate(buffer.array(), buffer.arrayOffset(), buffer.capacity())) == 0) {
|
||||||
if (inflater.finished() || inflater.needsDictionary()) {
|
if (inflater.finished() || inflater.needsDictionary()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inflater.needsInput()) {
|
if (inflater.needsInput()) {
|
||||||
fill(stream);
|
fill(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
catch (DataFormatException e) {
|
catch (DataFormatException e) {
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
throw new DecodeException(message != null ? message : "Invalid ZLIB data format", e);
|
throw new DecodeException(message != null ? message : "Invalid ZLIB data format", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fill(final InputStream pStream) throws IOException {
|
private void fill(final InputStream pStream) throws IOException {
|
||||||
int available = pStream.read(buffer, 0, buffer.length);
|
int available = pStream.read(buffer, 0, buffer.length);
|
||||||
|
|
||||||
if (available == -1) {
|
if (available == -1) {
|
||||||
throw new EOFException("Unexpected end of ZLIB stream");
|
throw new EOFException("Unexpected end of ZLIB stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
inflater.setInput(buffer, 0, available);
|
inflater.setInput(buffer, 0, available);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,401 +1,401 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.lang;
|
package com.twelvemonkeys.lang;
|
||||||
|
|
||||||
import com.twelvemonkeys.io.FileUtil;
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
import com.twelvemonkeys.util.FilterIterator;
|
import com.twelvemonkeys.util.FilterIterator;
|
||||||
import com.twelvemonkeys.util.service.ServiceRegistry;
|
import com.twelvemonkeys.util.service.ServiceRegistry;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NativeLoader
|
* NativeLoader
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/lang/NativeLoader.java#2 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/lang/NativeLoader.java#2 $
|
||||||
*/
|
*/
|
||||||
final class NativeLoader {
|
final class NativeLoader {
|
||||||
// TODO: Considerations:
|
// TODO: Considerations:
|
||||||
// - Rename all libs like the current code, to <library>.(so|dll|dylib)?
|
// - Rename all libs like the current code, to <library>.(so|dll|dylib)?
|
||||||
// - Keep library filename from jar, and rather store a separate
|
// - Keep library filename from jar, and rather store a separate
|
||||||
// properties-file with the library->library-file mappings?
|
// properties-file with the library->library-file mappings?
|
||||||
// - As all invocations are with library file name, we could probably skip
|
// - As all invocations are with library file name, we could probably skip
|
||||||
// both renaming and properties-file altogether...
|
// both renaming and properties-file altogether...
|
||||||
|
|
||||||
// TODO: The real trick here, is how to load the correct library for the
|
// TODO: The real trick here, is how to load the correct library for the
|
||||||
// current platform...
|
// current platform...
|
||||||
// - Change String pResource to String[] pResources?
|
// - Change String pResource to String[] pResources?
|
||||||
// - NativeResource class, that has a list of multiple resources?
|
// - NativeResource class, that has a list of multiple resources?
|
||||||
// NativeResource(Map<String, String>) os->native lib mapping
|
// NativeResource(Map<String, String>) os->native lib mapping
|
||||||
|
|
||||||
// TODO: Consider exposing the method from SystemUtil
|
// TODO: Consider exposing the method from SystemUtil
|
||||||
|
|
||||||
// TODO: How about a SPI based solution?!
|
// TODO: How about a SPI based solution?!
|
||||||
// public interface com.twelvemonkeys.lang.NativeResourceProvider
|
// public interface com.twelvemonkeys.lang.NativeResourceProvider
|
||||||
//
|
//
|
||||||
// imlementations return a pointer to the correct resource for a given (by
|
// imlementations return a pointer to the correct resource for a given (by
|
||||||
// this class) OS.
|
// this class) OS.
|
||||||
//
|
//
|
||||||
// String getResourceName(...)
|
// String getResourceName(...)
|
||||||
//
|
//
|
||||||
// See http://tolstoy.com/samizdat/sysprops.html
|
// See http://tolstoy.com/samizdat/sysprops.html
|
||||||
// System properties:
|
// System properties:
|
||||||
// "os.name"
|
// "os.name"
|
||||||
// Windows, Linux, Solaris/SunOS,
|
// Windows, Linux, Solaris/SunOS,
|
||||||
// Mac OS/Mac OS X/Rhapsody (aka Mac OS X Server)
|
// Mac OS/Mac OS X/Rhapsody (aka Mac OS X Server)
|
||||||
// General Unix (AIX, Digital Unix, FreeBSD, HP-UX, Irix)
|
// General Unix (AIX, Digital Unix, FreeBSD, HP-UX, Irix)
|
||||||
// OS/2
|
// OS/2
|
||||||
// "os.arch"
|
// "os.arch"
|
||||||
// Windows: x86
|
// Windows: x86
|
||||||
// Linux: x86, i386, i686, x86_64, ia64,
|
// Linux: x86, i386, i686, x86_64, ia64,
|
||||||
// Solaris: sparc, sparcv9, x86
|
// Solaris: sparc, sparcv9, x86
|
||||||
// Mac OS: PowerPC, ppc, i386
|
// Mac OS: PowerPC, ppc, i386
|
||||||
// AIX: x86, ppc
|
// AIX: x86, ppc
|
||||||
// Digital Unix: alpha
|
// Digital Unix: alpha
|
||||||
// FreeBSD: x86, sparc
|
// FreeBSD: x86, sparc
|
||||||
// HP-UX: PA-RISC
|
// HP-UX: PA-RISC
|
||||||
// Irix: mips
|
// Irix: mips
|
||||||
// OS/2: x86
|
// OS/2: x86
|
||||||
// "os.version"
|
// "os.version"
|
||||||
// Windows: 4.0 -> NT/95, 5.0 -> 2000, 5.1 -> XP (don't care about old versions, CE etc)
|
// Windows: 4.0 -> NT/95, 5.0 -> 2000, 5.1 -> XP (don't care about old versions, CE etc)
|
||||||
// Mac OS: 8.0, 8.1, 10.0 -> OS X, 10.x.x -> OS X, 5.6 -> Rhapsody (!)
|
// Mac OS: 8.0, 8.1, 10.0 -> OS X, 10.x.x -> OS X, 5.6 -> Rhapsody (!)
|
||||||
//
|
//
|
||||||
// Normalize os.name, os.arch and os.version?!
|
// Normalize os.name, os.arch and os.version?!
|
||||||
|
|
||||||
|
|
||||||
///** Normalized operating system constant */
|
///** Normalized operating system constant */
|
||||||
//static final OperatingSystem OS_NAME = normalizeOperatingSystem();
|
//static final OperatingSystem OS_NAME = normalizeOperatingSystem();
|
||||||
//
|
//
|
||||||
///** Normalized system architecture constant */
|
///** Normalized system architecture constant */
|
||||||
//static final Architecture OS_ARCHITECTURE = normalizeArchitecture();
|
//static final Architecture OS_ARCHITECTURE = normalizeArchitecture();
|
||||||
//
|
//
|
||||||
///** Unormalized operating system version constant (for completeness) */
|
///** Unormalized operating system version constant (for completeness) */
|
||||||
//static final String OS_VERSION = System.getProperty("os.version");
|
//static final String OS_VERSION = System.getProperty("os.version");
|
||||||
|
|
||||||
static final NativeResourceRegistry sRegistry = new NativeResourceRegistry();
|
static final NativeResourceRegistry sRegistry = new NativeResourceRegistry();
|
||||||
|
|
||||||
private NativeLoader() {
|
private NativeLoader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private static Architecture normalizeArchitecture() {
|
private static Architecture normalizeArchitecture() {
|
||||||
String arch = System.getProperty("os.arch");
|
String arch = System.getProperty("os.arch");
|
||||||
if (arch == null) {
|
if (arch == null) {
|
||||||
throw new IllegalStateException("System property \"os.arch\" == null");
|
throw new IllegalStateException("System property \"os.arch\" == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
arch = arch.toLowerCase();
|
arch = arch.toLowerCase();
|
||||||
if (OS_NAME == OperatingSystem.Windows
|
if (OS_NAME == OperatingSystem.Windows
|
||||||
&& (arch.startsWith("x86") || arch.startsWith("i386"))) {
|
&& (arch.startsWith("x86") || arch.startsWith("i386"))) {
|
||||||
return Architecture.X86;
|
return Architecture.X86;
|
||||||
// TODO: 64 bit
|
// TODO: 64 bit
|
||||||
}
|
}
|
||||||
else if (OS_NAME == OperatingSystem.Linux) {
|
else if (OS_NAME == OperatingSystem.Linux) {
|
||||||
if (arch.startsWith("x86") || arch.startsWith("i386")) {
|
if (arch.startsWith("x86") || arch.startsWith("i386")) {
|
||||||
return Architecture.I386;
|
return Architecture.I386;
|
||||||
}
|
}
|
||||||
else if (arch.startsWith("i686")) {
|
else if (arch.startsWith("i686")) {
|
||||||
return Architecture.I686;
|
return Architecture.I686;
|
||||||
}
|
}
|
||||||
// TODO: More Linux options?
|
// TODO: More Linux options?
|
||||||
// TODO: 64 bit
|
// TODO: 64 bit
|
||||||
}
|
}
|
||||||
else if (OS_NAME == OperatingSystem.MacOS) {
|
else if (OS_NAME == OperatingSystem.MacOS) {
|
||||||
if (arch.startsWith("power") || arch.startsWith("ppc")) {
|
if (arch.startsWith("power") || arch.startsWith("ppc")) {
|
||||||
return Architecture.PPC;
|
return Architecture.PPC;
|
||||||
}
|
}
|
||||||
else if (arch.startsWith("i386")) {
|
else if (arch.startsWith("i386")) {
|
||||||
return Architecture.I386;
|
return Architecture.I386;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (OS_NAME == OperatingSystem.Solaris) {
|
else if (OS_NAME == OperatingSystem.Solaris) {
|
||||||
if (arch.startsWith("sparc")) {
|
if (arch.startsWith("sparc")) {
|
||||||
return Architecture.SPARC;
|
return Architecture.SPARC;
|
||||||
}
|
}
|
||||||
if (arch.startsWith("x86")) {
|
if (arch.startsWith("x86")) {
|
||||||
// TODO: Should we use i386 as Linux and Mac does?
|
// TODO: Should we use i386 as Linux and Mac does?
|
||||||
return Architecture.X86;
|
return Architecture.X86;
|
||||||
}
|
}
|
||||||
// TODO: 64 bit
|
// TODO: 64 bit
|
||||||
}
|
}
|
||||||
|
|
||||||
return Architecture.Unknown;
|
return Architecture.Unknown;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private static OperatingSystem normalizeOperatingSystem() {
|
private static OperatingSystem normalizeOperatingSystem() {
|
||||||
String os = System.getProperty("os.name");
|
String os = System.getProperty("os.name");
|
||||||
if (os == null) {
|
if (os == null) {
|
||||||
throw new IllegalStateException("System property \"os.name\" == null");
|
throw new IllegalStateException("System property \"os.name\" == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
os = os.toLowerCase();
|
os = os.toLowerCase();
|
||||||
if (os.startsWith("windows")) {
|
if (os.startsWith("windows")) {
|
||||||
return OperatingSystem.Windows;
|
return OperatingSystem.Windows;
|
||||||
}
|
}
|
||||||
else if (os.startsWith("linux")) {
|
else if (os.startsWith("linux")) {
|
||||||
return OperatingSystem.Linux;
|
return OperatingSystem.Linux;
|
||||||
}
|
}
|
||||||
else if (os.startsWith("mac os")) {
|
else if (os.startsWith("mac os")) {
|
||||||
return OperatingSystem.MacOS;
|
return OperatingSystem.MacOS;
|
||||||
}
|
}
|
||||||
else if (os.startsWith("solaris") || os.startsWith("sunos")) {
|
else if (os.startsWith("solaris") || os.startsWith("sunos")) {
|
||||||
return OperatingSystem.Solaris;
|
return OperatingSystem.Solaris;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OperatingSystem.Unknown;
|
return OperatingSystem.Unknown;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: We could actually have more than one resource for each lib...
|
// TODO: We could actually have more than one resource for each lib...
|
||||||
private static String getResourceFor(String pLibrary) {
|
private static String getResourceFor(String pLibrary) {
|
||||||
Iterator<NativeResourceSPI> providers = sRegistry.providers(pLibrary);
|
Iterator<NativeResourceSPI> providers = sRegistry.providers(pLibrary);
|
||||||
while (providers.hasNext()) {
|
while (providers.hasNext()) {
|
||||||
NativeResourceSPI resourceSPI = providers.next();
|
NativeResourceSPI resourceSPI = providers.next();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return resourceSPI.getClassPathResource(Platform.get());
|
return resourceSPI.getClassPathResource(Platform.get());
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
// Dergister and try next
|
// Dergister and try next
|
||||||
sRegistry.deregister(resourceSPI);
|
sRegistry.deregister(resourceSPI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a native library.
|
* Loads a native library.
|
||||||
*
|
*
|
||||||
* @param pLibrary name of the library
|
* @param pLibrary name of the library
|
||||||
*
|
*
|
||||||
* @throws UnsatisfiedLinkError
|
* @throws UnsatisfiedLinkError
|
||||||
*/
|
*/
|
||||||
public static void loadLibrary(String pLibrary) {
|
public static void loadLibrary(String pLibrary) {
|
||||||
loadLibrary0(pLibrary, null, null);
|
loadLibrary0(pLibrary, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a native library.
|
* Loads a native library.
|
||||||
*
|
*
|
||||||
* @param pLibrary name of the library
|
* @param pLibrary name of the library
|
||||||
* @param pLoader the class loader to use
|
* @param pLoader the class loader to use
|
||||||
*
|
*
|
||||||
* @throws UnsatisfiedLinkError
|
* @throws UnsatisfiedLinkError
|
||||||
*/
|
*/
|
||||||
public static void loadLibrary(String pLibrary, ClassLoader pLoader) {
|
public static void loadLibrary(String pLibrary, ClassLoader pLoader) {
|
||||||
loadLibrary0(pLibrary, null, pLoader);
|
loadLibrary0(pLibrary, null, pLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a native library.
|
* Loads a native library.
|
||||||
*
|
*
|
||||||
* @param pLibrary name of the library
|
* @param pLibrary name of the library
|
||||||
* @param pResource name of the resource
|
* @param pResource name of the resource
|
||||||
* @param pLoader the class loader to use
|
* @param pLoader the class loader to use
|
||||||
*
|
*
|
||||||
* @throws UnsatisfiedLinkError
|
* @throws UnsatisfiedLinkError
|
||||||
*/
|
*/
|
||||||
static void loadLibrary0(String pLibrary, String pResource, ClassLoader pLoader) {
|
static void loadLibrary0(String pLibrary, String pResource, ClassLoader pLoader) {
|
||||||
if (pLibrary == null) {
|
if (pLibrary == null) {
|
||||||
throw new IllegalArgumentException("library == null");
|
throw new IllegalArgumentException("library == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try loading normal way
|
// Try loading normal way
|
||||||
UnsatisfiedLinkError unsatisfied;
|
UnsatisfiedLinkError unsatisfied;
|
||||||
try {
|
try {
|
||||||
System.loadLibrary(pLibrary);
|
System.loadLibrary(pLibrary);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (UnsatisfiedLinkError err) {
|
catch (UnsatisfiedLinkError err) {
|
||||||
// Ignore
|
// Ignore
|
||||||
unsatisfied = err;
|
unsatisfied = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ClassLoader loader = pLoader != null ? pLoader : Thread.currentThread().getContextClassLoader();
|
final ClassLoader loader = pLoader != null ? pLoader : Thread.currentThread().getContextClassLoader();
|
||||||
final String resource = pResource != null ? pResource : getResourceFor(pLibrary);
|
final String resource = pResource != null ? pResource : getResourceFor(pLibrary);
|
||||||
|
|
||||||
// TODO: resource may be null, and that MIGHT be okay, IFF the resource
|
// TODO: resource may be null, and that MIGHT be okay, IFF the resource
|
||||||
// is allready unpacked to the user dir... However, we then need another
|
// is allready unpacked to the user dir... However, we then need another
|
||||||
// way to resolve the library extension...
|
// way to resolve the library extension...
|
||||||
// Right now we just fail in a predictable way (no NPE)!
|
// Right now we just fail in a predictable way (no NPE)!
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
throw unsatisfied;
|
throw unsatisfied;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to load/store from user.home
|
// Default to load/store from user.home
|
||||||
File dir = new File(System.getProperty("user.home") + "/.twelvemonkeys/lib");
|
File dir = new File(System.getProperty("user.home") + "/.twelvemonkeys/lib");
|
||||||
dir.mkdirs();
|
dir.mkdirs();
|
||||||
//File libraryFile = new File(dir.getAbsolutePath(), pLibrary + LIBRARY_EXTENSION);
|
//File libraryFile = new File(dir.getAbsolutePath(), pLibrary + LIBRARY_EXTENSION);
|
||||||
File libraryFile = new File(dir.getAbsolutePath(), pLibrary + "." + FileUtil.getExtension(resource));
|
File libraryFile = new File(dir.getAbsolutePath(), pLibrary + "." + FileUtil.getExtension(resource));
|
||||||
|
|
||||||
if (!libraryFile.exists()) {
|
if (!libraryFile.exists()) {
|
||||||
try {
|
try {
|
||||||
extractToUserDir(resource, libraryFile, loader);
|
extractToUserDir(resource, libraryFile, loader);
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
UnsatisfiedLinkError err = new UnsatisfiedLinkError("Unable to extract resource to dir: " + libraryFile.getAbsolutePath());
|
UnsatisfiedLinkError err = new UnsatisfiedLinkError("Unable to extract resource to dir: " + libraryFile.getAbsolutePath());
|
||||||
err.initCause(ioe);
|
err.initCause(ioe);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load the library from the file we just wrote
|
// Try to load the library from the file we just wrote
|
||||||
System.load(libraryFile.getAbsolutePath());
|
System.load(libraryFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void extractToUserDir(String pResource, File pLibraryFile, ClassLoader pLoader) throws IOException {
|
private static void extractToUserDir(String pResource, File pLibraryFile, ClassLoader pLoader) throws IOException {
|
||||||
// Get resource from classpath
|
// Get resource from classpath
|
||||||
InputStream in = pLoader.getResourceAsStream(pResource);
|
InputStream in = pLoader.getResourceAsStream(pResource);
|
||||||
if (in == null) {
|
if (in == null) {
|
||||||
throw new FileNotFoundException("Unable to locate classpath resource: " + pResource);
|
throw new FileNotFoundException("Unable to locate classpath resource: " + pResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to file in user dir
|
// Write to file in user dir
|
||||||
FileOutputStream fileOut = null;
|
FileOutputStream fileOut = null;
|
||||||
try {
|
try {
|
||||||
fileOut = new FileOutputStream(pLibraryFile);
|
fileOut = new FileOutputStream(pLibraryFile);
|
||||||
|
|
||||||
byte[] tmp = new byte[1024];
|
byte[] tmp = new byte[1024];
|
||||||
// copy the contents of our resource out to the destination
|
// copy the contents of our resource out to the destination
|
||||||
// dir 1K at a time. 1K may seem arbitrary at first, but today
|
// dir 1K at a time. 1K may seem arbitrary at first, but today
|
||||||
// is a Tuesday, so it makes perfect sense.
|
// is a Tuesday, so it makes perfect sense.
|
||||||
int bytesRead = in.read(tmp);
|
int bytesRead = in.read(tmp);
|
||||||
while (bytesRead != -1) {
|
while (bytesRead != -1) {
|
||||||
fileOut.write(tmp, 0, bytesRead);
|
fileOut.write(tmp, 0, bytesRead);
|
||||||
bytesRead = in.read(tmp);
|
bytesRead = in.read(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
FileUtil.close(fileOut);
|
FileUtil.close(fileOut);
|
||||||
FileUtil.close(in);
|
FileUtil.close(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Validate OS names?
|
// TODO: Validate OS names?
|
||||||
// Windows
|
// Windows
|
||||||
// Linux
|
// Linux
|
||||||
// Solaris
|
// Solaris
|
||||||
// Mac OS (OSX+)
|
// Mac OS (OSX+)
|
||||||
// Generic Unix?
|
// Generic Unix?
|
||||||
// Others?
|
// Others?
|
||||||
|
|
||||||
// TODO: OSes that support different architectures might require different
|
// TODO: OSes that support different architectures might require different
|
||||||
// resources for each architecture.. Need a namespace/flavour system
|
// resources for each architecture.. Need a namespace/flavour system
|
||||||
// TODO: 32 bit/64 bit issues?
|
// TODO: 32 bit/64 bit issues?
|
||||||
// Eg: Windows, Windows/32, Windows/64, Windows/Intel/64?
|
// Eg: Windows, Windows/32, Windows/64, Windows/Intel/64?
|
||||||
// Solaris/Sparc, Solaris/Intel/64
|
// Solaris/Sparc, Solaris/Intel/64
|
||||||
// MacOS/PowerPC, MacOS/Intel
|
// MacOS/PowerPC, MacOS/Intel
|
||||||
/*
|
/*
|
||||||
public static class NativeResource {
|
public static class NativeResource {
|
||||||
private Map mMap;
|
private Map mMap;
|
||||||
|
|
||||||
public NativeResource(String[] pOSNames, String[] pReourceNames) {
|
public NativeResource(String[] pOSNames, String[] pReourceNames) {
|
||||||
if (pOSNames == null) {
|
if (pOSNames == null) {
|
||||||
throw new IllegalArgumentException("osNames == null");
|
throw new IllegalArgumentException("osNames == null");
|
||||||
}
|
}
|
||||||
if (pReourceNames == null) {
|
if (pReourceNames == null) {
|
||||||
throw new IllegalArgumentException("resourceNames == null");
|
throw new IllegalArgumentException("resourceNames == null");
|
||||||
}
|
}
|
||||||
if (pOSNames.length != pReourceNames.length) {
|
if (pOSNames.length != pReourceNames.length) {
|
||||||
throw new IllegalArgumentException("osNames.length != resourceNames.length");
|
throw new IllegalArgumentException("osNames.length != resourceNames.length");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map map = new HashMap();
|
Map map = new HashMap();
|
||||||
for (int i = 0; i < pOSNames.length; i++) {
|
for (int i = 0; i < pOSNames.length; i++) {
|
||||||
map.put(pOSNames[i], pReourceNames[i]);
|
map.put(pOSNames[i], pReourceNames[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mMap = Collections.unmodifiableMap(map);
|
mMap = Collections.unmodifiableMap(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeResource(Map pMap) {
|
public NativeResource(Map pMap) {
|
||||||
if (pMap == null) {
|
if (pMap == null) {
|
||||||
throw new IllegalArgumentException("map == null");
|
throw new IllegalArgumentException("map == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map map = new HashMap(pMap);
|
Map map = new HashMap(pMap);
|
||||||
|
|
||||||
Iterator it = map.keySet().iterator();
|
Iterator it = map.keySet().iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Map.Entry entry = (Map.Entry) it.next();
|
Map.Entry entry = (Map.Entry) it.next();
|
||||||
if (!(entry.getKey() instanceof String && entry.getValue() instanceof String)) {
|
if (!(entry.getKey() instanceof String && entry.getValue() instanceof String)) {
|
||||||
throw new IllegalArgumentException("map contains non-string entries: " + entry);
|
throw new IllegalArgumentException("map contains non-string entries: " + entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mMap = Collections.unmodifiableMap(map);
|
mMap = Collections.unmodifiableMap(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected NativeResource() {
|
protected NativeResource() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String resourceForCurrentOS() {
|
public final String resourceForCurrentOS() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getResourceName(String pOSName) {
|
protected String getResourceName(String pOSName) {
|
||||||
return (String) mMap.get(pOSName);
|
return (String) mMap.get(pOSName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private static class NativeResourceRegistry extends ServiceRegistry {
|
private static class NativeResourceRegistry extends ServiceRegistry {
|
||||||
public NativeResourceRegistry() {
|
public NativeResourceRegistry() {
|
||||||
super(Collections.singletonList(NativeResourceSPI.class).iterator());
|
super(Collections.singletonList(NativeResourceSPI.class).iterator());
|
||||||
registerApplicationClasspathSPIs();
|
registerApplicationClasspathSPIs();
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<NativeResourceSPI> providers(final String nativeResource) {
|
Iterator<NativeResourceSPI> providers(final String nativeResource) {
|
||||||
return new FilterIterator<NativeResourceSPI>(
|
return new FilterIterator<NativeResourceSPI>(
|
||||||
providers(NativeResourceSPI.class),
|
providers(NativeResourceSPI.class),
|
||||||
new NameFilter(nativeResource)
|
new NameFilter(nativeResource)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NameFilter implements FilterIterator.Filter<NativeResourceSPI> {
|
private static class NameFilter implements FilterIterator.Filter<NativeResourceSPI> {
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
NameFilter(String pName) {
|
NameFilter(String pName) {
|
||||||
if (pName == null) {
|
if (pName == null) {
|
||||||
throw new IllegalArgumentException("name == null");
|
throw new IllegalArgumentException("name == null");
|
||||||
}
|
}
|
||||||
name = pName;
|
name = pName;
|
||||||
}
|
}
|
||||||
public boolean accept(NativeResourceSPI pElement) {
|
public boolean accept(NativeResourceSPI pElement) {
|
||||||
return name.equals(pElement.getResourceName());
|
return name.equals(pElement.getResourceName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+398
-398
@@ -1,398 +1,398 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.util.regex;
|
package com.twelvemonkeys.util.regex;
|
||||||
|
|
||||||
import com.twelvemonkeys.util.DebugUtil;
|
import com.twelvemonkeys.util.DebugUtil;
|
||||||
|
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.regex.PatternSyntaxException;
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class parses arbitrary strings against a wildcard string mask provided.
|
* This class parses arbitrary strings against a wildcard string mask provided.
|
||||||
* The wildcard characters are '*' and '?'.
|
* The wildcard characters are '*' and '?'.
|
||||||
* <p>
|
* <p>
|
||||||
* The string masks provided are treated as case sensitive.<br>
|
* The string masks provided are treated as case sensitive.<br>
|
||||||
* Null-valued string masks as well as null valued strings to be parsed, will lead to rejection.
|
* Null-valued string masks as well as null valued strings to be parsed, will lead to rejection.
|
||||||
*
|
*
|
||||||
* <p><hr style="height=1"><p>
|
* <p><hr style="height=1"><p>
|
||||||
*
|
*
|
||||||
* This task is performed based on regular expression techniques.
|
* This task is performed based on regular expression techniques.
|
||||||
* The possibilities of string generation with the well-known wildcard characters stated above,
|
* The possibilities of string generation with the well-known wildcard characters stated above,
|
||||||
* represent a subset of the possibilities of string generation with regular expressions.<br>
|
* represent a subset of the possibilities of string generation with regular expressions.<br>
|
||||||
* The '*' corresponds to ([Union of all characters in the alphabet])*<br>
|
* The '*' corresponds to ([Union of all characters in the alphabet])*<br>
|
||||||
* The '?' corresponds to ([Union of all characters in the alphabet])<br>
|
* The '?' corresponds to ([Union of all characters in the alphabet])<br>
|
||||||
* <small>These expressions are not suited for textual representation at all, I must say. Is there any math tags included in HTML?</small>
|
* <small>These expressions are not suited for textual representation at all, I must say. Is there any math tags included in HTML?</small>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This class uses the Regexp package from Apache's Jakarta Project, links below.
|
* This class uses the Regexp package from Apache's Jakarta Project, links below.
|
||||||
*
|
*
|
||||||
* <p><hr style="height=1"><p>
|
* <p><hr style="height=1"><p>
|
||||||
*
|
*
|
||||||
* Examples of usage:<br>
|
* Examples of usage:<br>
|
||||||
* This example will return "Accepted!".
|
* This example will return "Accepted!".
|
||||||
* <pre>
|
* <pre>
|
||||||
* REWildcardStringParser parser = new REWildcardStringParser("*_28????.jp*");
|
* REWildcardStringParser parser = new REWildcardStringParser("*_28????.jp*");
|
||||||
* if (parser.parseString("gupu_280915.jpg")) {
|
* if (parser.parseString("gupu_280915.jpg")) {
|
||||||
* System.out.println("Accepted!");
|
* System.out.println("Accepted!");
|
||||||
* } else {
|
* } else {
|
||||||
* System.out.println("Not accepted!");
|
* System.out.println("Not accepted!");
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* <p><hr style="height=1"><p>
|
* <p><hr style="height=1"><p>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:eirik.torske@iconmedialab.no">Eirik Torske</a>
|
* @author <a href="mailto:eirik.torske@iconmedialab.no">Eirik Torske</a>
|
||||||
* @see <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a>
|
* @see <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a>
|
||||||
* @see <a href="http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html">{@code org.apache.regexp.RE}</a>
|
* @see <a href="http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html">{@code org.apache.regexp.RE}</a>
|
||||||
* @see com.twelvemonkeys.util.regex.WildcardStringParser
|
* @see com.twelvemonkeys.util.regex.WildcardStringParser
|
||||||
*
|
*
|
||||||
* @todo Rewrite to use this regex package, and not Jakarta directly!
|
* @todo Rewrite to use this regex package, and not Jakarta directly!
|
||||||
*/
|
*/
|
||||||
public class REWildcardStringParser /*extends EntityObject*/ {
|
public class REWildcardStringParser /*extends EntityObject*/ {
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
|
|
||||||
/** Field ALPHABET */
|
/** Field ALPHABET */
|
||||||
public static final char[] ALPHABET = {
|
public static final char[] ALPHABET = {
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\u00e6',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\u00e6',
|
||||||
'\u00f8', '\u00e5', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'N', 'M', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
'\u00f8', '\u00e5', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'N', 'M', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
||||||
'Z', '\u00c6', '\u00d8', '\u00c5', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_', '-'
|
'Z', '\u00c6', '\u00d8', '\u00c5', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_', '-'
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Field FREE_RANGE_CHARACTER */
|
/** Field FREE_RANGE_CHARACTER */
|
||||||
public static final char FREE_RANGE_CHARACTER = '*';
|
public static final char FREE_RANGE_CHARACTER = '*';
|
||||||
|
|
||||||
/** Field FREE_PASS_CHARACTER */
|
/** Field FREE_PASS_CHARACTER */
|
||||||
public static final char FREE_PASS_CHARACTER = '?';
|
public static final char FREE_PASS_CHARACTER = '?';
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
Pattern mRegexpParser;
|
Pattern mRegexpParser;
|
||||||
String mStringMask;
|
String mStringMask;
|
||||||
boolean mInitialized = false;
|
boolean mInitialized = false;
|
||||||
int mTotalNumberOfStringsParsed;
|
int mTotalNumberOfStringsParsed;
|
||||||
boolean mDebugging;
|
boolean mDebugging;
|
||||||
PrintStream out;
|
PrintStream out;
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a wildcard string parser.
|
* Creates a wildcard string parser.
|
||||||
* <p>
|
* <p>
|
||||||
* @param pStringMask the wildcard string mask.
|
* @param pStringMask the wildcard string mask.
|
||||||
*/
|
*/
|
||||||
public REWildcardStringParser(final String pStringMask) {
|
public REWildcardStringParser(final String pStringMask) {
|
||||||
this(pStringMask, false);
|
this(pStringMask, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a wildcard string parser.
|
* Creates a wildcard string parser.
|
||||||
* <p>
|
* <p>
|
||||||
* @param pStringMask the wildcard string mask.
|
* @param pStringMask the wildcard string mask.
|
||||||
* @param pDebugging {@code true} will cause debug messages to be emitted to {@code System.out}.
|
* @param pDebugging {@code true} will cause debug messages to be emitted to {@code System.out}.
|
||||||
*/
|
*/
|
||||||
public REWildcardStringParser(final String pStringMask, final boolean pDebugging) {
|
public REWildcardStringParser(final String pStringMask, final boolean pDebugging) {
|
||||||
this(pStringMask, pDebugging, System.out);
|
this(pStringMask, pDebugging, System.out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a wildcard string parser.
|
* Creates a wildcard string parser.
|
||||||
* <p>
|
* <p>
|
||||||
* @param pStringMask the wildcard string mask.
|
* @param pStringMask the wildcard string mask.
|
||||||
* @param pDebugging {@code true} will cause debug messages to be emitted.
|
* @param pDebugging {@code true} will cause debug messages to be emitted.
|
||||||
* @param pDebuggingPrintStream the {@code java.io.PrintStream} to which the debug messages will be emitted.
|
* @param pDebuggingPrintStream the {@code java.io.PrintStream} to which the debug messages will be emitted.
|
||||||
*/
|
*/
|
||||||
public REWildcardStringParser(final String pStringMask, final boolean pDebugging, final PrintStream pDebuggingPrintStream) {
|
public REWildcardStringParser(final String pStringMask, final boolean pDebugging, final PrintStream pDebuggingPrintStream) {
|
||||||
|
|
||||||
this.mStringMask = pStringMask;
|
this.mStringMask = pStringMask;
|
||||||
this.mDebugging = pDebugging;
|
this.mDebugging = pDebugging;
|
||||||
this.out = pDebuggingPrintStream;
|
this.out = pDebuggingPrintStream;
|
||||||
mInitialized = buildRegexpParser();
|
mInitialized = buildRegexpParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts wildcard string mask to regular expression.
|
* Converts wildcard string mask to regular expression.
|
||||||
* This method should reside in som utility class, but I don't know how proprietary the regular expression format is...
|
* This method should reside in som utility class, but I don't know how proprietary the regular expression format is...
|
||||||
* @return the corresponding regular expression or {@code null} if an error occurred.
|
* @return the corresponding regular expression or {@code null} if an error occurred.
|
||||||
*/
|
*/
|
||||||
private String convertWildcardExpressionToRegularExpression(final String pWildcardExpression) {
|
private String convertWildcardExpressionToRegularExpression(final String pWildcardExpression) {
|
||||||
|
|
||||||
if (pWildcardExpression == null) {
|
if (pWildcardExpression == null) {
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println(DebugUtil.getPrefixDebugMessage(this) + "wildcard expression is null - also returning null as regexp!");
|
out.println(DebugUtil.getPrefixDebugMessage(this) + "wildcard expression is null - also returning null as regexp!");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
StringBuilder regexpBuffer = new StringBuilder();
|
StringBuilder regexpBuffer = new StringBuilder();
|
||||||
boolean convertingError = false;
|
boolean convertingError = false;
|
||||||
|
|
||||||
for (int i = 0; i < pWildcardExpression.length(); i++) {
|
for (int i = 0; i < pWildcardExpression.length(); i++) {
|
||||||
if (convertingError) {
|
if (convertingError) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free-range character '*'
|
// Free-range character '*'
|
||||||
char stringMaskChar = pWildcardExpression.charAt(i);
|
char stringMaskChar = pWildcardExpression.charAt(i);
|
||||||
|
|
||||||
if (isFreeRangeCharacter(stringMaskChar)) {
|
if (isFreeRangeCharacter(stringMaskChar)) {
|
||||||
regexpBuffer.append("(([a-�A-�0-9]|.|_|-)*)");
|
regexpBuffer.append("(([a-�A-�0-9]|.|_|-)*)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free-pass character '?'
|
// Free-pass character '?'
|
||||||
else if (isFreePassCharacter(stringMaskChar)) {
|
else if (isFreePassCharacter(stringMaskChar)) {
|
||||||
regexpBuffer.append("([a-�A_�0-9]|.|_|-)");
|
regexpBuffer.append("([a-�A_�0-9]|.|_|-)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid characters
|
// Valid characters
|
||||||
else if (isInAlphabet(stringMaskChar)) {
|
else if (isInAlphabet(stringMaskChar)) {
|
||||||
regexpBuffer.append(stringMaskChar);
|
regexpBuffer.append(stringMaskChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid character - aborting
|
// Invalid character - aborting
|
||||||
else {
|
else {
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println(DebugUtil.getPrefixDebugMessage(this)
|
out.println(DebugUtil.getPrefixDebugMessage(this)
|
||||||
+ "one or more characters in string mask are not legal characters - returning null as regexp!");
|
+ "one or more characters in string mask are not legal characters - returning null as regexp!");
|
||||||
}
|
}
|
||||||
convertingError = true;
|
convertingError = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return regexpBuffer.toString();
|
return regexpBuffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the regexp parser.
|
* Builds the regexp parser.
|
||||||
*/
|
*/
|
||||||
private boolean buildRegexpParser() {
|
private boolean buildRegexpParser() {
|
||||||
|
|
||||||
// Convert wildcard string mask to regular expression
|
// Convert wildcard string mask to regular expression
|
||||||
String regexp = convertWildcardExpressionToRegularExpression(mStringMask);
|
String regexp = convertWildcardExpressionToRegularExpression(mStringMask);
|
||||||
|
|
||||||
if (regexp == null) {
|
if (regexp == null) {
|
||||||
out.println(DebugUtil.getPrefixErrorMessage(this)
|
out.println(DebugUtil.getPrefixErrorMessage(this)
|
||||||
+ "irregularity in regexp conversion - now not able to parse any strings, all strings will be rejected!");
|
+ "irregularity in regexp conversion - now not able to parse any strings, all strings will be rejected!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate a regular expression parser
|
// Instantiate a regular expression parser
|
||||||
try {
|
try {
|
||||||
mRegexpParser = Pattern.compile(regexp);
|
mRegexpParser = Pattern.compile(regexp);
|
||||||
}
|
}
|
||||||
catch (PatternSyntaxException e) {
|
catch (PatternSyntaxException e) {
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println(DebugUtil.getPrefixErrorMessage(this) + "RESyntaxException \"" + e.getMessage()
|
out.println(DebugUtil.getPrefixErrorMessage(this) + "RESyntaxException \"" + e.getMessage()
|
||||||
+ "\" caught - now not able to parse any strings, all strings will be rejected!");
|
+ "\" caught - now not able to parse any strings, all strings will be rejected!");
|
||||||
}
|
}
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
e.printStackTrace(System.err);
|
e.printStackTrace(System.err);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println(DebugUtil.getPrefixDebugMessage(this) + "regular expression parser from regular expression " + regexp
|
out.println(DebugUtil.getPrefixDebugMessage(this) + "regular expression parser from regular expression " + regexp
|
||||||
+ " extracted from wildcard string mask " + mStringMask + ".");
|
+ " extracted from wildcard string mask " + mStringMask + ".");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple check of the string to be parsed.
|
* Simple check of the string to be parsed.
|
||||||
*/
|
*/
|
||||||
private boolean checkStringToBeParsed(final String pStringToBeParsed) {
|
private boolean checkStringToBeParsed(final String pStringToBeParsed) {
|
||||||
|
|
||||||
// Check for nullness
|
// Check for nullness
|
||||||
if (pStringToBeParsed == null) {
|
if (pStringToBeParsed == null) {
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println(DebugUtil.getPrefixDebugMessage(this) + "string to be parsed is null - rejection!");
|
out.println(DebugUtil.getPrefixDebugMessage(this) + "string to be parsed is null - rejection!");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if valid character (element in alphabet)
|
// Check if valid character (element in alphabet)
|
||||||
for (int i = 0; i < pStringToBeParsed.length(); i++) {
|
for (int i = 0; i < pStringToBeParsed.length(); i++) {
|
||||||
if (!isInAlphabet(pStringToBeParsed.charAt(i))) {
|
if (!isInAlphabet(pStringToBeParsed.charAt(i))) {
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println(DebugUtil.getPrefixDebugMessage(this)
|
out.println(DebugUtil.getPrefixDebugMessage(this)
|
||||||
+ "one or more characters in string to be parsed are not legal characters - rejection!");
|
+ "one or more characters in string to be parsed are not legal characters - rejection!");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if a certain character is a valid character in the alphabet that is applying for this automaton.
|
* Tests if a certain character is a valid character in the alphabet that is applying for this automaton.
|
||||||
*/
|
*/
|
||||||
public static boolean isInAlphabet(final char pCharToCheck) {
|
public static boolean isInAlphabet(final char pCharToCheck) {
|
||||||
|
|
||||||
for (int i = 0; i < ALPHABET.length; i++) {
|
for (int i = 0; i < ALPHABET.length; i++) {
|
||||||
if (pCharToCheck == ALPHABET[i]) {
|
if (pCharToCheck == ALPHABET[i]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if a certain character is the designated "free-range" character ('*').
|
* Tests if a certain character is the designated "free-range" character ('*').
|
||||||
*/
|
*/
|
||||||
public static boolean isFreeRangeCharacter(final char pCharToCheck) {
|
public static boolean isFreeRangeCharacter(final char pCharToCheck) {
|
||||||
return pCharToCheck == FREE_RANGE_CHARACTER;
|
return pCharToCheck == FREE_RANGE_CHARACTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if a certain character is the designated "free-pass" character ('?').
|
* Tests if a certain character is the designated "free-pass" character ('?').
|
||||||
*/
|
*/
|
||||||
public static boolean isFreePassCharacter(final char pCharToCheck) {
|
public static boolean isFreePassCharacter(final char pCharToCheck) {
|
||||||
return pCharToCheck == FREE_PASS_CHARACTER;
|
return pCharToCheck == FREE_PASS_CHARACTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if a certain character is a wildcard character ('*' or '?').
|
* Tests if a certain character is a wildcard character ('*' or '?').
|
||||||
*/
|
*/
|
||||||
public static boolean isWildcardCharacter(final char pCharToCheck) {
|
public static boolean isWildcardCharacter(final char pCharToCheck) {
|
||||||
return ((isFreeRangeCharacter(pCharToCheck)) || (isFreePassCharacter(pCharToCheck)));
|
return ((isFreeRangeCharacter(pCharToCheck)) || (isFreePassCharacter(pCharToCheck)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the string mask that was used when building the parser atomaton.
|
* Gets the string mask that was used when building the parser atomaton.
|
||||||
* <p>
|
* <p>
|
||||||
* @return the string mask used for building the parser automaton.
|
* @return the string mask used for building the parser automaton.
|
||||||
*/
|
*/
|
||||||
public String getStringMask() {
|
public String getStringMask() {
|
||||||
return mStringMask;
|
return mStringMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a string.
|
* Parses a string.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* @param pStringToBeParsed
|
* @param pStringToBeParsed
|
||||||
* @return {@code true} if and only if the string are accepted by the parser.
|
* @return {@code true} if and only if the string are accepted by the parser.
|
||||||
*/
|
*/
|
||||||
public boolean parseString(final String pStringToBeParsed) {
|
public boolean parseString(final String pStringToBeParsed) {
|
||||||
|
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println();
|
out.println();
|
||||||
}
|
}
|
||||||
if (mDebugging) {
|
if (mDebugging) {
|
||||||
out.println(DebugUtil.getPrefixDebugMessage(this) + "parsing \"" + pStringToBeParsed + "\"...");
|
out.println(DebugUtil.getPrefixDebugMessage(this) + "parsing \"" + pStringToBeParsed + "\"...");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update statistics
|
// Update statistics
|
||||||
mTotalNumberOfStringsParsed++;
|
mTotalNumberOfStringsParsed++;
|
||||||
|
|
||||||
// Check string to be parsed
|
// Check string to be parsed
|
||||||
if (!checkStringToBeParsed(pStringToBeParsed)) {
|
if (!checkStringToBeParsed(pStringToBeParsed)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform parsing and return accetance/rejection flag
|
// Perform parsing and return accetance/rejection flag
|
||||||
if (mInitialized) {
|
if (mInitialized) {
|
||||||
return mRegexpParser.matcher(pStringToBeParsed).matches();
|
return mRegexpParser.matcher(pStringToBeParsed).matches();
|
||||||
} else {
|
} else {
|
||||||
out.println(DebugUtil.getPrefixErrorMessage(this) + "trying to use non-initialized parser - string rejected!");
|
out.println(DebugUtil.getPrefixErrorMessage(this) + "trying to use non-initialized parser - string rejected!");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Overriding mandatory methods from EntityObject's.
|
* Overriding mandatory methods from EntityObject's.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method toString
|
* Method toString
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
||||||
StringBuilder buffer = new StringBuilder();
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
|
||||||
buffer.append(DebugUtil.getClassName(this));
|
buffer.append(DebugUtil.getClassName(this));
|
||||||
buffer.append(": String mask ");
|
buffer.append(": String mask ");
|
||||||
buffer.append(mStringMask);
|
buffer.append(mStringMask);
|
||||||
buffer.append("\n");
|
buffer.append("\n");
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just taking the lazy, easy and dangerous way out
|
// Just taking the lazy, easy and dangerous way out
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method equals
|
* Method equals
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param pObject
|
* @param pObject
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public boolean equals(Object pObject) {
|
public boolean equals(Object pObject) {
|
||||||
|
|
||||||
if (pObject instanceof REWildcardStringParser) {
|
if (pObject instanceof REWildcardStringParser) {
|
||||||
REWildcardStringParser externalParser = (REWildcardStringParser) pObject;
|
REWildcardStringParser externalParser = (REWildcardStringParser) pObject;
|
||||||
|
|
||||||
return (externalParser.mStringMask == this.mStringMask);
|
return (externalParser.mStringMask == this.mStringMask);
|
||||||
}
|
}
|
||||||
return ((Object) this).equals(pObject);
|
return ((Object) this).equals(pObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just taking the lazy, easy and dangerous way out
|
// Just taking the lazy, easy and dangerous way out
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method hashCode
|
* Method hashCode
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return ((Object) this).hashCode();
|
return ((Object) this).hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object clone() throws CloneNotSupportedException {
|
protected Object clone() throws CloneNotSupportedException {
|
||||||
return new REWildcardStringParser(mStringMask);
|
return new REWildcardStringParser(mStringMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just taking the lazy, easy and dangerous way out
|
// Just taking the lazy, easy and dangerous way out
|
||||||
protected void finalize() throws Throwable {}
|
protected void finalize() throws Throwable {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*--- Formatted in Sun Java Convention Style on ma, des 1, '03 ---*/
|
/*--- Formatted in Sun Java Convention Style on ma, des 1, '03 ---*/
|
||||||
|
|
||||||
|
|
||||||
/*------ Formatted by Jindent 3.23 Basic 1.0 --- http://www.jindent.de ------*/
|
/*------ Formatted by Jindent 3.23 Basic 1.0 --- http://www.jindent.de ------*/
|
||||||
|
|||||||
+335
-335
@@ -1,336 +1,336 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.servlet.ServletUtil;
|
import com.twelvemonkeys.servlet.ServletUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This servlet is capable of rendereing a text string and output it as an
|
* This servlet is capable of rendereing a text string and output it as an
|
||||||
* image. The text can be rendered in any given font, size,
|
* image. The text can be rendered in any given font, size,
|
||||||
* style or color, into an image, and output it as a GIF, JPEG or PNG image,
|
* style or color, into an image, and output it as a GIF, JPEG or PNG image,
|
||||||
* with optional caching of the rendered image files.
|
* with optional caching of the rendered image files.
|
||||||
*
|
*
|
||||||
* <P><HR><P>
|
* <P><HR><P>
|
||||||
*
|
*
|
||||||
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
||||||
* <DL>
|
* <DL>
|
||||||
* <DT>{@code text}</DT>
|
* <DT>{@code text}</DT>
|
||||||
* <DD>string, the text string to render.
|
* <DD>string, the text string to render.
|
||||||
* <DT>{@code width}</DT>
|
* <DT>{@code width}</DT>
|
||||||
* <DD>integer, the width of the image
|
* <DD>integer, the width of the image
|
||||||
* <DT>{@code height}</DT>
|
* <DT>{@code height}</DT>
|
||||||
* <DD>integer, the height of the image
|
* <DD>integer, the height of the image
|
||||||
* <DT>{@code fontFamily}</DT>
|
* <DT>{@code fontFamily}</DT>
|
||||||
* <DD>string, the name of the font family.
|
* <DD>string, the name of the font family.
|
||||||
* Default is {@code "Helvetica"}.
|
* Default is {@code "Helvetica"}.
|
||||||
* <DT>{@code fontSize}</DT>
|
* <DT>{@code fontSize}</DT>
|
||||||
* <DD>integer, the size of the font. Default is {@code 12}.
|
* <DD>integer, the size of the font. Default is {@code 12}.
|
||||||
* <DT>{@code fontStyle}</DT>
|
* <DT>{@code fontStyle}</DT>
|
||||||
* <DD>string, the tyle of the font. Can be one of the constants
|
* <DD>string, the tyle of the font. Can be one of the constants
|
||||||
* {@code plain} (default), {@code bold}, {@code italic} or
|
* {@code plain} (default), {@code bold}, {@code italic} or
|
||||||
* {@code bolditalic}. Any other will result in {@code plain}.
|
* {@code bolditalic}. Any other will result in {@code plain}.
|
||||||
* <DT>{@code fgcolor}</DT>
|
* <DT>{@code fgcolor}</DT>
|
||||||
* <DD>color (HTML form, {@code #RRGGBB}), or color constant from
|
* <DD>color (HTML form, {@code #RRGGBB}), or color constant from
|
||||||
* {@link java.awt.Color}, default is {@code "black"}.
|
* {@link java.awt.Color}, default is {@code "black"}.
|
||||||
* <DT>{@code bgcolor}</DT>
|
* <DT>{@code bgcolor}</DT>
|
||||||
* <DD>color (HTML form, {@code #RRGGBB}), or color constant from
|
* <DD>color (HTML form, {@code #RRGGBB}), or color constant from
|
||||||
* {@link java.awt.Color}, default is {@code "transparent"}.
|
* {@link java.awt.Color}, default is {@code "transparent"}.
|
||||||
* Note that the hash character ({@code "#"}) used in colors must be
|
* Note that the hash character ({@code "#"}) used in colors must be
|
||||||
* escaped as {@code %23} in the query string. See
|
* escaped as {@code %23} in the query string. See
|
||||||
* {@link StringUtil#toColor(String)}, <A href="#examples">examples</A>.
|
* {@link StringUtil#toColor(String)}, <A href="#examples">examples</A>.
|
||||||
*
|
*
|
||||||
* <!-- inherited from ImageServlet below: -->
|
* <!-- inherited from ImageServlet below: -->
|
||||||
*
|
*
|
||||||
* <DT>{@code cache}</DT>
|
* <DT>{@code cache}</DT>
|
||||||
* <DD>boolean, {@code true} if you want to cache the result
|
* <DD>boolean, {@code true} if you want to cache the result
|
||||||
* to disk (default).
|
* to disk (default).
|
||||||
*
|
*
|
||||||
* <DT>{@code compression}</DT>
|
* <DT>{@code compression}</DT>
|
||||||
* <DD>float, the optional compression ratio for the output image. For JPEG
|
* <DD>float, the optional compression ratio for the output image. For JPEG
|
||||||
* images, the quality is the inverse of the compression ratio. See
|
* images, the quality is the inverse of the compression ratio. See
|
||||||
* {@link #JPEG_DEFAULT_COMPRESSION_LEVEL},
|
* {@link #JPEG_DEFAULT_COMPRESSION_LEVEL},
|
||||||
* {@link #PNG_DEFAULT_COMPRESSION_LEVEL}.
|
* {@link #PNG_DEFAULT_COMPRESSION_LEVEL}.
|
||||||
* <DD>Applies to JPEG and PNG images only.
|
* <DD>Applies to JPEG and PNG images only.
|
||||||
*
|
*
|
||||||
* <DT>{@code dither}</DT>
|
* <DT>{@code dither}</DT>
|
||||||
* <DD>enumerated, one of {@code NONE}, {@code DEFAULT} or
|
* <DD>enumerated, one of {@code NONE}, {@code DEFAULT} or
|
||||||
* {@code FS}, if you want to dither the result ({@code DEFAULT} is
|
* {@code FS}, if you want to dither the result ({@code DEFAULT} is
|
||||||
* default).
|
* default).
|
||||||
* {@code FS} will produce the best results, but it's slower.
|
* {@code FS} will produce the best results, but it's slower.
|
||||||
* <DD>Use in conjuction with {@code indexed}, {@code palette}
|
* <DD>Use in conjuction with {@code indexed}, {@code palette}
|
||||||
* and {@code websafe}.
|
* and {@code websafe}.
|
||||||
* <DD>Applies to GIF and PNG images only.
|
* <DD>Applies to GIF and PNG images only.
|
||||||
*
|
*
|
||||||
* <DT>{@code fileName}</DT>
|
* <DT>{@code fileName}</DT>
|
||||||
* <DD>string, an optional filename. If not set, the path after the servlet
|
* <DD>string, an optional filename. If not set, the path after the servlet
|
||||||
* ({@link HttpServletRequest#getPathInfo}) will be used for the cache
|
* ({@link HttpServletRequest#getPathInfo}) will be used for the cache
|
||||||
* filename. See {@link #getCacheFile(ServletRequest)},
|
* filename. See {@link #getCacheFile(ServletRequest)},
|
||||||
* {@link #getCacheRoot}.
|
* {@link #getCacheRoot}.
|
||||||
*
|
*
|
||||||
* <DT>{@code height}</DT>
|
* <DT>{@code height}</DT>
|
||||||
* <DD>integer, the height of the image.
|
* <DD>integer, the height of the image.
|
||||||
*
|
*
|
||||||
* <DT>{@code width}</DT>
|
* <DT>{@code width}</DT>
|
||||||
* <DD>integer, the width of the image.
|
* <DD>integer, the width of the image.
|
||||||
*
|
*
|
||||||
* <DT>{@code indexed}</DT>
|
* <DT>{@code indexed}</DT>
|
||||||
* <DD>integer, the number of colors in the resulting image, or -1 (default).
|
* <DD>integer, the number of colors in the resulting image, or -1 (default).
|
||||||
* If the value is set and positive, the image will use an
|
* If the value is set and positive, the image will use an
|
||||||
* {@code IndexColorModel} with
|
* {@code IndexColorModel} with
|
||||||
* the number of colors specified. Otherwise the image will be true color.
|
* the number of colors specified. Otherwise the image will be true color.
|
||||||
* <DD>Applies to GIF and PNG images only.
|
* <DD>Applies to GIF and PNG images only.
|
||||||
*
|
*
|
||||||
* <DT>{@code palette}</DT>
|
* <DT>{@code palette}</DT>
|
||||||
* <DD>string, an optional filename. If set, the image will use IndexColorModel
|
* <DD>string, an optional filename. If set, the image will use IndexColorModel
|
||||||
* with a palette read from the given file.
|
* with a palette read from the given file.
|
||||||
* <DD>Applies to GIF and PNG images only.
|
* <DD>Applies to GIF and PNG images only.
|
||||||
*
|
*
|
||||||
* <DT>{@code websafe}</DT>
|
* <DT>{@code websafe}</DT>
|
||||||
* <DD>boolean, {@code true} if you want the result to use the 216 color
|
* <DD>boolean, {@code true} if you want the result to use the 216 color
|
||||||
* websafe palette (default is false).
|
* websafe palette (default is false).
|
||||||
* <DD>Applies to GIF and PNG images only.
|
* <DD>Applies to GIF and PNG images only.
|
||||||
* </DL>
|
* </DL>
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* <IMG src="/text/test.gif?height=40&width=600
|
* <IMG src="/text/test.gif?height=40&width=600
|
||||||
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=%23990033
|
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=%23990033
|
||||||
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
||||||
* %20lazy%20dog&cache=false" />
|
* %20lazy%20dog&cache=false" />
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* <IMG src="/text/test.jpg?height=40&width=600
|
* <IMG src="/text/test.jpg?height=40&width=600
|
||||||
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=black
|
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=black
|
||||||
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
||||||
* %20lazy%20dog&compression=3&cache=false" />
|
* %20lazy%20dog&compression=3&cache=false" />
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* <IMG src="/text/test.png?height=40&width=600
|
* <IMG src="/text/test.png?height=40&width=600
|
||||||
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=%23336699
|
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=%23336699
|
||||||
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
||||||
* %20lazy%20dog&cache=true" />
|
* %20lazy%20dog&cache=true" />
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: TextRenderer.java#2 $
|
* @version $Id: TextRenderer.java#2 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class TextRenderer /*extends ImageServlet implements ImagePainterServlet*/ {
|
class TextRenderer /*extends ImageServlet implements ImagePainterServlet*/ {
|
||||||
// TODO: Create something usable out of this piece of old junk.. ;-)
|
// TODO: Create something usable out of this piece of old junk.. ;-)
|
||||||
// It just needs a graphics object to write onto
|
// It just needs a graphics object to write onto
|
||||||
// Alternatively, defer, and compute the size needed
|
// Alternatively, defer, and compute the size needed
|
||||||
// Or, make it a filter...
|
// Or, make it a filter...
|
||||||
|
|
||||||
/** {@code "italic"} */
|
/** {@code "italic"} */
|
||||||
public final static String FONT_STYLE_ITALIC = "italic";
|
public final static String FONT_STYLE_ITALIC = "italic";
|
||||||
/** {@code "plain"} */
|
/** {@code "plain"} */
|
||||||
public final static String FONT_STYLE_PLAIN = "plain";
|
public final static String FONT_STYLE_PLAIN = "plain";
|
||||||
/** {@code "bold"} */
|
/** {@code "bold"} */
|
||||||
public final static String FONT_STYLE_BOLD = "bold";
|
public final static String FONT_STYLE_BOLD = "bold";
|
||||||
|
|
||||||
/** {@code text} */
|
/** {@code text} */
|
||||||
public final static String PARAM_TEXT = "text";
|
public final static String PARAM_TEXT = "text";
|
||||||
/** {@code marginLeft} */
|
/** {@code marginLeft} */
|
||||||
public final static String PARAM_MARGIN_LEFT = "marginLeft";
|
public final static String PARAM_MARGIN_LEFT = "marginLeft";
|
||||||
/** {@code marginTop} */
|
/** {@code marginTop} */
|
||||||
public final static String PARAM_MARGIN_TOP = "marginTop";
|
public final static String PARAM_MARGIN_TOP = "marginTop";
|
||||||
/** {@code fontFamily} */
|
/** {@code fontFamily} */
|
||||||
public final static String PARAM_FONT_FAMILY = "fontFamily";
|
public final static String PARAM_FONT_FAMILY = "fontFamily";
|
||||||
/** {@code fontSize} */
|
/** {@code fontSize} */
|
||||||
public final static String PARAM_FONT_SIZE = "fontSize";
|
public final static String PARAM_FONT_SIZE = "fontSize";
|
||||||
/** {@code fontStyle} */
|
/** {@code fontStyle} */
|
||||||
public final static String PARAM_FONT_STYLE = "fontStyle";
|
public final static String PARAM_FONT_STYLE = "fontStyle";
|
||||||
/** {@code textRotation} */
|
/** {@code textRotation} */
|
||||||
public final static String PARAM_TEXT_ROTATION = "textRotation";
|
public final static String PARAM_TEXT_ROTATION = "textRotation";
|
||||||
/** {@code textRotation} */
|
/** {@code textRotation} */
|
||||||
public final static String PARAM_TEXT_ROTATION_UNITS = "textRotationUnits";
|
public final static String PARAM_TEXT_ROTATION_UNITS = "textRotationUnits";
|
||||||
|
|
||||||
/** {@code bgcolor} */
|
/** {@code bgcolor} */
|
||||||
public final static String PARAM_BGCOLOR = "bgcolor";
|
public final static String PARAM_BGCOLOR = "bgcolor";
|
||||||
/** {@code fgcolor} */
|
/** {@code fgcolor} */
|
||||||
public final static String PARAM_FGCOLOR = "fgcolor";
|
public final static String PARAM_FGCOLOR = "fgcolor";
|
||||||
|
|
||||||
protected final static String ROTATION_DEGREES = "DEGREES";
|
protected final static String ROTATION_DEGREES = "DEGREES";
|
||||||
protected final static String ROTATION_RADIANS = "RADIANS";
|
protected final static String ROTATION_RADIANS = "RADIANS";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the TextRender servlet.
|
* Creates the TextRender servlet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public TextRenderer() {
|
public TextRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the text string for this servlet request.
|
* Renders the text string for this servlet request.
|
||||||
*/
|
*/
|
||||||
private void paint(ServletRequest pReq, Graphics2D pRes, int pWidth, int pHeight)
|
private void paint(ServletRequest pReq, Graphics2D pRes, int pWidth, int pHeight)
|
||||||
throws ImageServletException {
|
throws ImageServletException {
|
||||||
|
|
||||||
// Get parameters
|
// Get parameters
|
||||||
String text = pReq.getParameter(PARAM_TEXT);
|
String text = pReq.getParameter(PARAM_TEXT);
|
||||||
String[] lines = StringUtil.toStringArray(text, "\n\r");
|
String[] lines = StringUtil.toStringArray(text, "\n\r");
|
||||||
|
|
||||||
String fontFamily = pReq.getParameter(PARAM_FONT_FAMILY);
|
String fontFamily = pReq.getParameter(PARAM_FONT_FAMILY);
|
||||||
String fontSize = pReq.getParameter(PARAM_FONT_SIZE);
|
String fontSize = pReq.getParameter(PARAM_FONT_SIZE);
|
||||||
String fontStyle = pReq.getParameter(PARAM_FONT_STYLE);
|
String fontStyle = pReq.getParameter(PARAM_FONT_STYLE);
|
||||||
|
|
||||||
String bgcolor = pReq.getParameter(PARAM_BGCOLOR);
|
String bgcolor = pReq.getParameter(PARAM_BGCOLOR);
|
||||||
String fgcolor = pReq.getParameter(PARAM_FGCOLOR);
|
String fgcolor = pReq.getParameter(PARAM_FGCOLOR);
|
||||||
|
|
||||||
// TODO: Make them static..
|
// TODO: Make them static..
|
||||||
pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
|
pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
|
||||||
pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
|
pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
|
||||||
pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY));
|
pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY));
|
||||||
// pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
|
// pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
|
||||||
|
|
||||||
//System.out.println(pRes.getBackground());
|
//System.out.println(pRes.getBackground());
|
||||||
|
|
||||||
// Clear area with bgcolor
|
// Clear area with bgcolor
|
||||||
if (!StringUtil.isEmpty(bgcolor)) {
|
if (!StringUtil.isEmpty(bgcolor)) {
|
||||||
pRes.setBackground(StringUtil.toColor(bgcolor));
|
pRes.setBackground(StringUtil.toColor(bgcolor));
|
||||||
pRes.clearRect(0, 0, pWidth, pHeight);
|
pRes.clearRect(0, 0, pWidth, pHeight);
|
||||||
|
|
||||||
//System.out.println(pRes.getBackground());
|
//System.out.println(pRes.getBackground());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and set font
|
// Create and set font
|
||||||
Font font = new Font(
|
Font font = new Font(
|
||||||
fontFamily != null ? fontFamily : "Helvetica",
|
fontFamily != null ? fontFamily : "Helvetica",
|
||||||
getFontStyle(fontStyle),
|
getFontStyle(fontStyle),
|
||||||
fontSize != null ? Integer.parseInt(fontSize) : 12
|
fontSize != null ? Integer.parseInt(fontSize) : 12
|
||||||
);
|
);
|
||||||
pRes.setFont(font);
|
pRes.setFont(font);
|
||||||
|
|
||||||
// Set rotation
|
// Set rotation
|
||||||
double angle = getAngle(pReq);
|
double angle = getAngle(pReq);
|
||||||
pRes.rotate(angle, pWidth / 2.0, pHeight / 2.0);
|
pRes.rotate(angle, pWidth / 2.0, pHeight / 2.0);
|
||||||
|
|
||||||
// Draw string in fgcolor
|
// Draw string in fgcolor
|
||||||
pRes.setColor(fgcolor != null ? StringUtil.toColor(fgcolor) : Color.black);
|
pRes.setColor(fgcolor != null ? StringUtil.toColor(fgcolor) : Color.black);
|
||||||
|
|
||||||
float x = ServletUtil.getFloatParameter(pReq, PARAM_MARGIN_LEFT, Float.MIN_VALUE);
|
float x = ServletUtil.getFloatParameter(pReq, PARAM_MARGIN_LEFT, Float.MIN_VALUE);
|
||||||
Rectangle2D[] bounds = new Rectangle2D[lines.length];
|
Rectangle2D[] bounds = new Rectangle2D[lines.length];
|
||||||
if (x <= Float.MIN_VALUE) {
|
if (x <= Float.MIN_VALUE) {
|
||||||
// Center
|
// Center
|
||||||
float longest = 0f;
|
float longest = 0f;
|
||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
bounds[i] = font.getStringBounds(lines[i], pRes.getFontRenderContext());
|
bounds[i] = font.getStringBounds(lines[i], pRes.getFontRenderContext());
|
||||||
if (bounds[i].getWidth() > longest) {
|
if (bounds[i].getWidth() > longest) {
|
||||||
longest = (float) bounds[i].getWidth();
|
longest = (float) bounds[i].getWidth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//x = (float) ((pWidth - bounds.getWidth()) / 2f);
|
//x = (float) ((pWidth - bounds.getWidth()) / 2f);
|
||||||
x = (float) ((pWidth - longest) / 2f);
|
x = (float) ((pWidth - longest) / 2f);
|
||||||
|
|
||||||
//System.out.println("marginLeft: " + x);
|
//System.out.println("marginLeft: " + x);
|
||||||
}
|
}
|
||||||
//else {
|
//else {
|
||||||
//System.out.println("marginLeft (from param): " + x);
|
//System.out.println("marginLeft (from param): " + x);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
float y = ServletUtil.getFloatParameter(pReq, PARAM_MARGIN_TOP, Float.MIN_VALUE);
|
float y = ServletUtil.getFloatParameter(pReq, PARAM_MARGIN_TOP, Float.MIN_VALUE);
|
||||||
float lineHeight = (float) (bounds[0] != null ?
|
float lineHeight = (float) (bounds[0] != null ?
|
||||||
bounds[0].getHeight() : font.getStringBounds(lines[0], pRes.getFontRenderContext()).getHeight());
|
bounds[0].getHeight() : font.getStringBounds(lines[0], pRes.getFontRenderContext()).getHeight());
|
||||||
|
|
||||||
if (y <= Float.MIN_VALUE) {
|
if (y <= Float.MIN_VALUE) {
|
||||||
// Center
|
// Center
|
||||||
y = (float) ((pHeight - lineHeight) / 2f)
|
y = (float) ((pHeight - lineHeight) / 2f)
|
||||||
- (lineHeight * (lines.length - 2.5f) / 2f);
|
- (lineHeight * (lines.length - 2.5f) / 2f);
|
||||||
|
|
||||||
//System.out.println("marginTop: " + y);
|
//System.out.println("marginTop: " + y);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Todo: Correct for font height?
|
// Todo: Correct for font height?
|
||||||
y += font.getSize2D();
|
y += font.getSize2D();
|
||||||
//System.out.println("marginTop (from param):" + y);
|
//System.out.println("marginTop (from param):" + y);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//System.out.println("Font size: " + font.getSize2D());
|
//System.out.println("Font size: " + font.getSize2D());
|
||||||
//System.out.println("Line height: " + lineHeight);
|
//System.out.println("Line height: " + lineHeight);
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
pRes.drawString(lines[i], x, y + lineHeight * i);
|
pRes.drawString(lines[i], x, y + lineHeight * i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the font style constant.
|
* Returns the font style constant.
|
||||||
*
|
*
|
||||||
* @param pStyle a string containing either the word {@code "plain"} or one
|
* @param pStyle a string containing either the word {@code "plain"} or one
|
||||||
* or more of {@code "bold"} and {@code italic}.
|
* or more of {@code "bold"} and {@code italic}.
|
||||||
* @return the font style constant as defined in {@link Font}.
|
* @return the font style constant as defined in {@link Font}.
|
||||||
*
|
*
|
||||||
* @see Font#PLAIN
|
* @see Font#PLAIN
|
||||||
* @see Font#BOLD
|
* @see Font#BOLD
|
||||||
* @see Font#ITALIC
|
* @see Font#ITALIC
|
||||||
*/
|
*/
|
||||||
private int getFontStyle(String pStyle) {
|
private int getFontStyle(String pStyle) {
|
||||||
if (pStyle == null || StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_PLAIN)) {
|
if (pStyle == null || StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_PLAIN)) {
|
||||||
return Font.PLAIN;
|
return Font.PLAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find bold/italic
|
// Try to find bold/italic
|
||||||
int style = Font.PLAIN;
|
int style = Font.PLAIN;
|
||||||
if (StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_BOLD)) {
|
if (StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_BOLD)) {
|
||||||
style |= Font.BOLD;
|
style |= Font.BOLD;
|
||||||
}
|
}
|
||||||
if (StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_ITALIC)) {
|
if (StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_ITALIC)) {
|
||||||
style |= Font.ITALIC;
|
style |= Font.ITALIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the angle of rotation from the request.
|
* Gets the angle of rotation from the request.
|
||||||
*
|
*
|
||||||
* @param pRequest the servlet request to get parameters from
|
* @param pRequest the servlet request to get parameters from
|
||||||
* @return the angle in radians.
|
* @return the angle in radians.
|
||||||
*/
|
*/
|
||||||
private double getAngle(ServletRequest pRequest) {
|
private double getAngle(ServletRequest pRequest) {
|
||||||
// Get angle
|
// Get angle
|
||||||
double angle = ServletUtil.getDoubleParameter(pRequest, PARAM_TEXT_ROTATION, 0.0);
|
double angle = ServletUtil.getDoubleParameter(pRequest, PARAM_TEXT_ROTATION, 0.0);
|
||||||
|
|
||||||
// Convert to radians, if needed
|
// Convert to radians, if needed
|
||||||
String units = pRequest.getParameter(PARAM_TEXT_ROTATION_UNITS);
|
String units = pRequest.getParameter(PARAM_TEXT_ROTATION_UNITS);
|
||||||
if (!StringUtil.isEmpty(units) && ROTATION_DEGREES.equalsIgnoreCase(units)) {
|
if (!StringUtil.isEmpty(units) && ROTATION_DEGREES.equalsIgnoreCase(units)) {
|
||||||
angle = Math.toRadians(angle);
|
angle = Math.toRadians(angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+76
-76
@@ -1,76 +1,76 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: Droplet.java,v $
|
* $Log: Droplet.java,v $
|
||||||
* Revision 1.3 2003/10/06 14:25:19 WMHAKUR
|
* Revision 1.3 2003/10/06 14:25:19 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/10/18 14:12:16 WMHAKUR
|
* Revision 1.2 2002/10/18 14:12:16 WMHAKUR
|
||||||
* Now, it even compiles. :-/
|
* Now, it even compiles. :-/
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:02:16 WMHAKUR
|
* Revision 1.1 2002/10/18 14:02:16 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.jsp.droplet.taglib.IncludeTag;
|
import com.twelvemonkeys.servlet.jsp.droplet.taglib.IncludeTag;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dynamo Droplet like Servlet.
|
* Dynamo Droplet like Servlet.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class Droplet extends HttpServlet implements JspFragment {
|
public abstract class Droplet extends HttpServlet implements JspFragment {
|
||||||
|
|
||||||
public abstract void service(PageContext pPageContext)
|
public abstract void service(PageContext pPageContext)
|
||||||
throws ServletException, IOException;
|
throws ServletException, IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Services a parameter. Programatically equivalent to the
|
* Services a parameter. Programatically equivalent to the
|
||||||
* <d:valueof param="pParameter"/> JSP tag.
|
* <d:valueof param="pParameter"/> JSP tag.
|
||||||
*/
|
*/
|
||||||
public void serviceParameter(String pParameter, PageContext pPageContext) throws ServletException, IOException {
|
public void serviceParameter(String pParameter, PageContext pPageContext) throws ServletException, IOException {
|
||||||
Object param = pPageContext.getRequest().getAttribute(pParameter);
|
Object param = pPageContext.getRequest().getAttribute(pParameter);
|
||||||
|
|
||||||
if (param != null) {
|
if (param != null) {
|
||||||
if (param instanceof Param) {
|
if (param instanceof Param) {
|
||||||
((Param) param).service(pPageContext);
|
((Param) param).service(pPageContext);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pPageContext.getOut().print(param);
|
pPageContext.getOut().print(param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Try to get value from parameters
|
// Try to get value from parameters
|
||||||
Object obj = pPageContext.getRequest().getParameter(pParameter);
|
Object obj = pPageContext.getRequest().getParameter(pParameter);
|
||||||
|
|
||||||
// Print parameter or default value
|
// Print parameter or default value
|
||||||
pPageContext.getOut().print((obj != null) ? obj : "");
|
pPageContext.getOut().print((obj != null) ? obj : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "There's no need to override this method." :-)
|
* "There's no need to override this method." :-)
|
||||||
*/
|
*/
|
||||||
final public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
final public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
||||||
PageContext pageContext = (PageContext) pRequest.getAttribute(IncludeTag.PAGE_CONTEXT);
|
PageContext pageContext = (PageContext) pRequest.getAttribute(IncludeTag.PAGE_CONTEXT);
|
||||||
|
|
||||||
// TODO: What if pageContext == null
|
// TODO: What if pageContext == null
|
||||||
service(pageContext);
|
service(pageContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-42
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: JspFragment.java,v $
|
* $Log: JspFragment.java,v $
|
||||||
* Revision 1.2 2003/10/06 14:25:36 WMHAKUR
|
* Revision 1.2 2003/10/06 14:25:36 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:02:16 WMHAKUR
|
* Revision 1.1 2002/10/18 14:02:16 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for JSP sub pages or page fragments to implement.
|
* Interface for JSP sub pages or page fragments to implement.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*/
|
*/
|
||||||
public interface JspFragment {
|
public interface JspFragment {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Services a sub page or a page fragment inside another page
|
* Services a sub page or a page fragment inside another page
|
||||||
* (or PageContext).
|
* (or PageContext).
|
||||||
*
|
*
|
||||||
* @param pContext the PageContext that is used to render the subpage.
|
* @param pContext the PageContext that is used to render the subpage.
|
||||||
*
|
*
|
||||||
* @throws ServletException if an exception occurs that interferes with the
|
* @throws ServletException if an exception occurs that interferes with the
|
||||||
* subpage's normal operation
|
* subpage's normal operation
|
||||||
* @throws IOException if an input or output exception occurs
|
* @throws IOException if an input or output exception occurs
|
||||||
*/
|
*/
|
||||||
public void service(PageContext pContext) throws ServletException, IOException;
|
public void service(PageContext pContext) throws ServletException, IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-26
@@ -1,26 +1,26 @@
|
|||||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Oparam (Open parameter)
|
* Oparam (Open parameter)
|
||||||
*/
|
*/
|
||||||
public class Oparam extends Param implements JspFragment {
|
public class Oparam extends Param implements JspFragment {
|
||||||
/**
|
/**
|
||||||
* Creates an Oparam.
|
* Creates an Oparam.
|
||||||
*
|
*
|
||||||
* @param pValue the value of the parameter
|
* @param pValue the value of the parameter
|
||||||
*/
|
*/
|
||||||
public Oparam(String pValue) {
|
public Oparam(String pValue) {
|
||||||
super(pValue);
|
super(pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void service(PageContext pContext) throws ServletException, IOException {
|
public void service(PageContext pContext) throws ServletException, IOException {
|
||||||
pContext.getServletContext().log("Service subpage " + pContext.getServletContext().getRealPath(value));
|
pContext.getServletContext().log("Service subpage " + pContext.getServletContext().getRealPath(value));
|
||||||
|
|
||||||
pContext.include(value);
|
pContext.include(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-41
@@ -1,41 +1,41 @@
|
|||||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.jsp.JspWriter;
|
import javax.servlet.jsp.JspWriter;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Param
|
* Param
|
||||||
*/
|
*/
|
||||||
public class Param implements JspFragment {
|
public class Param implements JspFragment {
|
||||||
|
|
||||||
/** The value member field. */
|
/** The value member field. */
|
||||||
protected String value = null;
|
protected String value = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Param.
|
* Creates a Param.
|
||||||
*
|
*
|
||||||
* @param pValue the value of the parameter
|
* @param pValue the value of the parameter
|
||||||
*/
|
*/
|
||||||
public Param(String pValue) {
|
public Param(String pValue) {
|
||||||
value = pValue;
|
value = pValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the parameter.
|
* Gets the value of the parameter.
|
||||||
*/
|
*/
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Services the page fragment. This version simply prints the value of
|
* Services the page fragment. This version simply prints the value of
|
||||||
* this parameter to teh PageContext's out.
|
* this parameter to teh PageContext's out.
|
||||||
*/
|
*/
|
||||||
public void service(PageContext pContext)
|
public void service(PageContext pContext)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
JspWriter writer = pContext.getOut();
|
JspWriter writer = pContext.getOut();
|
||||||
writer.print(value);
|
writer.print(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+214
-214
@@ -1,214 +1,214 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: IncludeTag.java,v $
|
* $Log: IncludeTag.java,v $
|
||||||
* Revision 1.2 2003/10/06 14:25:36 WMHAKUR
|
* Revision 1.2 2003/10/06 14:25:36 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
|
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include tag tag that emulates ATG Dynamo Droplet tag JHTML behaviour for
|
* Include tag tag that emulates ATG Dynamo Droplet tag JHTML behaviour for
|
||||||
* JSP.
|
* JSP.
|
||||||
*
|
*
|
||||||
* @author Thomas Purcell (CSC Australia)
|
* @author Thomas Purcell (CSC Australia)
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class IncludeTag extends ExTagSupport {
|
public class IncludeTag extends ExTagSupport {
|
||||||
/**
|
/**
|
||||||
* This will contain the names of all the parameters that have been
|
* This will contain the names of all the parameters that have been
|
||||||
* added to the PageContext.REQUEST_SCOPE scope by this tag.
|
* added to the PageContext.REQUEST_SCOPE scope by this tag.
|
||||||
*/
|
*/
|
||||||
private ArrayList<String> parameterNames = null;
|
private ArrayList<String> parameterNames = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If any of the parameters we insert for this tag already exist, then
|
* If any of the parameters we insert for this tag already exist, then
|
||||||
* we back up the older parameter in this {@code HashMap} and
|
* we back up the older parameter in this {@code HashMap} and
|
||||||
* restore them when the tag is finished.
|
* restore them when the tag is finished.
|
||||||
*/
|
*/
|
||||||
private HashMap<String, Object> oldParameters = null;
|
private HashMap<String, Object> oldParameters = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the URL for the JSP page that the parameters contained in this
|
* This is the URL for the JSP page that the parameters contained in this
|
||||||
* tag are to be inserted into.
|
* tag are to be inserted into.
|
||||||
*/
|
*/
|
||||||
private String page;
|
private String page;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the PageContext attribute
|
* The name of the PageContext attribute
|
||||||
*/
|
*/
|
||||||
public final static String PAGE_CONTEXT = "com.twelvemonkeys.servlet.jsp.PageContext";
|
public final static String PAGE_CONTEXT = "com.twelvemonkeys.servlet.jsp.PageContext";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value for the JSP page to insert the parameters into. This
|
* Sets the value for the JSP page to insert the parameters into. This
|
||||||
* will be set by the tag attribute within the original JSP page.
|
* will be set by the tag attribute within the original JSP page.
|
||||||
*
|
*
|
||||||
* @param pPage The URL for the JSP page to insert parameters into.
|
* @param pPage The URL for the JSP page to insert parameters into.
|
||||||
*/
|
*/
|
||||||
public void setPage(String pPage) {
|
public void setPage(String pPage) {
|
||||||
page = pPage;
|
page = pPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a parameter to the {@code PageContext.REQUEST_SCOPE} scope.
|
* Adds a parameter to the {@code PageContext.REQUEST_SCOPE} scope.
|
||||||
* If a parameter with the same name as {@code pName} already exists,
|
* If a parameter with the same name as {@code pName} already exists,
|
||||||
* then the old parameter is first placed in the {@code OldParameters}
|
* then the old parameter is first placed in the {@code OldParameters}
|
||||||
* member variable. When this tag is finished, the old value will be
|
* member variable. When this tag is finished, the old value will be
|
||||||
* restored.
|
* restored.
|
||||||
*
|
*
|
||||||
* @param pName The name of the new parameter to be stored in the
|
* @param pName The name of the new parameter to be stored in the
|
||||||
* {@code PageContext.REQUEST_SCOPE} scope.
|
* {@code PageContext.REQUEST_SCOPE} scope.
|
||||||
* @param pValue The value for the parmeter to be stored in the {@code
|
* @param pValue The value for the parmeter to be stored in the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
public void addParameter(String pName, Object pValue) {
|
public void addParameter(String pName, Object pValue) {
|
||||||
// Check that we haven't already saved this parameter
|
// Check that we haven't already saved this parameter
|
||||||
if (!parameterNames.contains(pName)) {
|
if (!parameterNames.contains(pName)) {
|
||||||
parameterNames.add(pName);
|
parameterNames.add(pName);
|
||||||
|
|
||||||
// Now check if this parameter already exists in the page.
|
// Now check if this parameter already exists in the page.
|
||||||
Object obj = getRequest().getAttribute(pName);
|
Object obj = getRequest().getAttribute(pName);
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
oldParameters.put(pName, obj);
|
oldParameters.put(pName, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, insert the parameter in the request scope.
|
// Finally, insert the parameter in the request scope.
|
||||||
getRequest().setAttribute(pName, pValue);
|
getRequest().setAttribute(pName, pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the method called when the JSP interpreter first hits the tag
|
* This is the method called when the JSP interpreter first hits the tag
|
||||||
* associated with this class. This method will firstly determine whether
|
* associated with this class. This method will firstly determine whether
|
||||||
* the page referenced by the {@code page} attribute exists. If the
|
* the page referenced by the {@code page} attribute exists. If the
|
||||||
* page doesn't exist, this method will throw a {@code JspException}.
|
* page doesn't exist, this method will throw a {@code JspException}.
|
||||||
* If the page does exist, this method will hand control over to that JSP
|
* If the page does exist, this method will hand control over to that JSP
|
||||||
* page.
|
* page.
|
||||||
*
|
*
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
public int doStartTag() throws JspException {
|
public int doStartTag() throws JspException {
|
||||||
oldParameters = new HashMap<String, Object>();
|
oldParameters = new HashMap<String, Object>();
|
||||||
parameterNames = new ArrayList<String>();
|
parameterNames = new ArrayList<String>();
|
||||||
|
|
||||||
return EVAL_BODY_INCLUDE;
|
return EVAL_BODY_INCLUDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called when the JSP page compiler hits the end tag. By
|
* This method is called when the JSP page compiler hits the end tag. By
|
||||||
* now all the data should have been passed and parameters entered into
|
* now all the data should have been passed and parameters entered into
|
||||||
* the {@code PageContext.REQUEST_SCOPE} scope. This method includes
|
* the {@code PageContext.REQUEST_SCOPE} scope. This method includes
|
||||||
* the JSP page whose URL is stored in the {@code mPage} member
|
* the JSP page whose URL is stored in the {@code mPage} member
|
||||||
* variable.
|
* variable.
|
||||||
*
|
*
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
String msg;
|
String msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Iterator<String> iterator;
|
Iterator<String> iterator;
|
||||||
String parameterName;
|
String parameterName;
|
||||||
|
|
||||||
// -- Harald K 20020726
|
// -- Harald K 20020726
|
||||||
// Include the page, in place
|
// Include the page, in place
|
||||||
//getDispatcher().include(getRequest(), getResponse());
|
//getDispatcher().include(getRequest(), getResponse());
|
||||||
addParameter(PAGE_CONTEXT, pageContext); // Will be cleared later
|
addParameter(PAGE_CONTEXT, pageContext); // Will be cleared later
|
||||||
pageContext.include(page);
|
pageContext.include(page);
|
||||||
|
|
||||||
// Remove all the parameters that were added to the request scope
|
// Remove all the parameters that were added to the request scope
|
||||||
// for this insert tag.
|
// for this insert tag.
|
||||||
iterator = parameterNames.iterator();
|
iterator = parameterNames.iterator();
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
parameterName = iterator.next();
|
parameterName = iterator.next();
|
||||||
|
|
||||||
getRequest().removeAttribute(parameterName);
|
getRequest().removeAttribute(parameterName);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator = oldParameters.keySet().iterator();
|
iterator = oldParameters.keySet().iterator();
|
||||||
|
|
||||||
// Restore the parameters we temporarily replaced (if any).
|
// Restore the parameters we temporarily replaced (if any).
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
parameterName = iterator.next();
|
parameterName = iterator.next();
|
||||||
|
|
||||||
getRequest().setAttribute(parameterName, oldParameters.get(parameterName));
|
getRequest().setAttribute(parameterName, oldParameters.get(parameterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.doEndTag();
|
return super.doEndTag();
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
msg = "Caught an IOException while including " + page
|
msg = "Caught an IOException while including " + page
|
||||||
+ "\n" + ioe.toString();
|
+ "\n" + ioe.toString();
|
||||||
log(msg, ioe);
|
log(msg, ioe);
|
||||||
throw new JspException(msg);
|
throw new JspException(msg);
|
||||||
}
|
}
|
||||||
catch (ServletException se) {
|
catch (ServletException se) {
|
||||||
msg = "Caught a ServletException while including " + page
|
msg = "Caught a ServletException while including " + page
|
||||||
+ "\n" + se.toString();
|
+ "\n" + se.toString();
|
||||||
log(msg, se);
|
log(msg, se);
|
||||||
throw new JspException(msg);
|
throw new JspException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free up the member variables that we've used throughout this tag.
|
* Free up the member variables that we've used throughout this tag.
|
||||||
*/
|
*/
|
||||||
protected void clearServiceState() {
|
protected void clearServiceState() {
|
||||||
oldParameters = null;
|
oldParameters = null;
|
||||||
parameterNames = null;
|
parameterNames = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the request dispatcher for the JSP page whose URL is stored in
|
* Returns the request dispatcher for the JSP page whose URL is stored in
|
||||||
* the {@code mPage} member variable.
|
* the {@code mPage} member variable.
|
||||||
*
|
*
|
||||||
* @return The RequestDispatcher for the JSP page whose URL is stored in
|
* @return The RequestDispatcher for the JSP page whose URL is stored in
|
||||||
* the {@code mPage} member variable.
|
* the {@code mPage} member variable.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
private RequestDispatcher getDispatcher() {
|
private RequestDispatcher getDispatcher() {
|
||||||
return getRequest().getRequestDispatcher(page);
|
return getRequest().getRequestDispatcher(page);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the HttpServletRequest object for the current user request.
|
* Returns the HttpServletRequest object for the current user request.
|
||||||
*
|
*
|
||||||
* @return The HttpServletRequest object for the current user request.
|
* @return The HttpServletRequest object for the current user request.
|
||||||
*/
|
*/
|
||||||
private HttpServletRequest getRequest() {
|
private HttpServletRequest getRequest() {
|
||||||
return (HttpServletRequest) pageContext.getRequest();
|
return (HttpServletRequest) pageContext.getRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the HttpServletResponse object for the current user request.
|
* Returns the HttpServletResponse object for the current user request.
|
||||||
*
|
*
|
||||||
* @return The HttpServletResponse object for the current user request.
|
* @return The HttpServletResponse object for the current user request.
|
||||||
*/
|
*/
|
||||||
private HttpServletResponse getResponse() {
|
private HttpServletResponse getResponse() {
|
||||||
return (HttpServletResponse) pageContext.getResponse();
|
return (HttpServletResponse) pageContext.getResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+183
-183
@@ -1,183 +1,183 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: NestingHandler.java,v $
|
* $Log: NestingHandler.java,v $
|
||||||
* Revision 1.4 2003/10/06 14:25:44 WMHAKUR
|
* Revision 1.4 2003/10/06 14:25:44 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.3 2003/08/04 15:26:30 WMHAKUR
|
* Revision 1.3 2003/08/04 15:26:30 WMHAKUR
|
||||||
* Code clean-up.
|
* Code clean-up.
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
||||||
* Fixed package error.
|
* Fixed package error.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import org.xml.sax.*;
|
import org.xml.sax.*;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A SAX handler that returns an exception if the nesting of
|
* A SAX handler that returns an exception if the nesting of
|
||||||
* {@code param}, {@code oparam}, {@code droplet} and
|
* {@code param}, {@code oparam}, {@code droplet} and
|
||||||
* {@code valueof} is not correct.
|
* {@code valueof} is not correct.
|
||||||
*
|
*
|
||||||
* Based on the NestingHandler.java,
|
* Based on the NestingHandler.java,
|
||||||
* taken from More Servlets and JavaServer Pages
|
* taken from More Servlets and JavaServer Pages
|
||||||
* from Prentice Hall and Sun Microsystems Press,
|
* from Prentice Hall and Sun Microsystems Press,
|
||||||
* http://www.moreservlets.com/.
|
* http://www.moreservlets.com/.
|
||||||
* © 2002 Marty Hall; may be freely used or adapted.
|
* © 2002 Marty Hall; may be freely used or adapted.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*/
|
*/
|
||||||
public class NestingHandler extends DefaultHandler {
|
public class NestingHandler extends DefaultHandler {
|
||||||
private String includeTagName = "include";
|
private String includeTagName = "include";
|
||||||
private String paramTagName = "param";
|
private String paramTagName = "param";
|
||||||
private String openParamTagName = "oparam";
|
private String openParamTagName = "oparam";
|
||||||
|
|
||||||
//private Stack mParents = new Stack();
|
//private Stack mParents = new Stack();
|
||||||
|
|
||||||
private boolean inIncludeTag = false;
|
private boolean inIncludeTag = false;
|
||||||
|
|
||||||
private String namespacePrefix = null;
|
private String namespacePrefix = null;
|
||||||
private String namespaceURI = null;
|
private String namespaceURI = null;
|
||||||
|
|
||||||
private NestingValidator validator = null;
|
private NestingValidator validator = null;
|
||||||
|
|
||||||
public NestingHandler(String pNamespacePrefix, String pNameSpaceURI,
|
public NestingHandler(String pNamespacePrefix, String pNameSpaceURI,
|
||||||
NestingValidator pValidator) {
|
NestingValidator pValidator) {
|
||||||
namespacePrefix = pNamespacePrefix;
|
namespacePrefix = pNamespacePrefix;
|
||||||
namespaceURI = pNameSpaceURI;
|
namespaceURI = pNameSpaceURI;
|
||||||
|
|
||||||
validator = pValidator;
|
validator = pValidator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startElement(String pNamespaceURI, String pLocalName,
|
public void startElement(String pNamespaceURI, String pLocalName,
|
||||||
String pQualifiedName, Attributes pAttributes)
|
String pQualifiedName, Attributes pAttributes)
|
||||||
throws SAXException {
|
throws SAXException {
|
||||||
String namespacePrefix = !StringUtil.isEmpty(pNamespaceURI)
|
String namespacePrefix = !StringUtil.isEmpty(pNamespaceURI)
|
||||||
? getNSPrefixFromURI(pNamespaceURI)
|
? getNSPrefixFromURI(pNamespaceURI)
|
||||||
: getNamespacePrefix(pQualifiedName);
|
: getNamespacePrefix(pQualifiedName);
|
||||||
|
|
||||||
String localName = !StringUtil.isEmpty(pLocalName)
|
String localName = !StringUtil.isEmpty(pLocalName)
|
||||||
? pLocalName : getLocalName(pQualifiedName);
|
? pLocalName : getLocalName(pQualifiedName);
|
||||||
/*
|
/*
|
||||||
if (namespacePrefix.equals(namespacePrefix)) {
|
if (namespacePrefix.equals(namespacePrefix)) {
|
||||||
System.out.println("startElement:\nnamespaceURI=" + pNamespaceURI
|
System.out.println("startElement:\nnamespaceURI=" + pNamespaceURI
|
||||||
+ " namespacePrefix=" + namespacePrefix
|
+ " namespacePrefix=" + namespacePrefix
|
||||||
+ " localName=" + localName
|
+ " localName=" + localName
|
||||||
+ " qName=" + pQualifiedName
|
+ " qName=" + pQualifiedName
|
||||||
+ " attributes=" + pAttributes);
|
+ " attributes=" + pAttributes);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (localName.equals(includeTagName)) {
|
if (localName.equals(includeTagName)) {
|
||||||
// include
|
// include
|
||||||
//System.out.println("<" + namespacePrefix + ":"
|
//System.out.println("<" + namespacePrefix + ":"
|
||||||
// + includeTagName + ">");
|
// + includeTagName + ">");
|
||||||
if (inIncludeTag) {
|
if (inIncludeTag) {
|
||||||
validator.reportError("Cannot nest " + namespacePrefix + ":"
|
validator.reportError("Cannot nest " + namespacePrefix + ":"
|
||||||
+ includeTagName);
|
+ includeTagName);
|
||||||
}
|
}
|
||||||
inIncludeTag = true;
|
inIncludeTag = true;
|
||||||
}
|
}
|
||||||
else if (localName.equals(paramTagName)) {
|
else if (localName.equals(paramTagName)) {
|
||||||
// param
|
// param
|
||||||
//System.out.println("<" + namespacePrefix + ":"
|
//System.out.println("<" + namespacePrefix + ":"
|
||||||
// + paramTagName + "/>");
|
// + paramTagName + "/>");
|
||||||
if (!inIncludeTag) {
|
if (!inIncludeTag) {
|
||||||
validator.reportError(this.namespacePrefix + ":"
|
validator.reportError(this.namespacePrefix + ":"
|
||||||
+ paramTagName
|
+ paramTagName
|
||||||
+ " can only appear within "
|
+ " can only appear within "
|
||||||
+ this.namespacePrefix + ":"
|
+ this.namespacePrefix + ":"
|
||||||
+ includeTagName);
|
+ includeTagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (localName.equals(openParamTagName)) {
|
else if (localName.equals(openParamTagName)) {
|
||||||
// oparam
|
// oparam
|
||||||
//System.out.println("<" + namespacePrefix + ":"
|
//System.out.println("<" + namespacePrefix + ":"
|
||||||
// + openParamTagName + ">");
|
// + openParamTagName + ">");
|
||||||
if (!inIncludeTag) {
|
if (!inIncludeTag) {
|
||||||
validator.reportError(this.namespacePrefix + ":"
|
validator.reportError(this.namespacePrefix + ":"
|
||||||
+ openParamTagName
|
+ openParamTagName
|
||||||
+ " can only appear within "
|
+ " can only appear within "
|
||||||
+ this.namespacePrefix + ":"
|
+ this.namespacePrefix + ":"
|
||||||
+ includeTagName);
|
+ includeTagName);
|
||||||
}
|
}
|
||||||
inIncludeTag = false;
|
inIncludeTag = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Only jsp:text allowed inside include!
|
// Only jsp:text allowed inside include!
|
||||||
if (inIncludeTag && !localName.equals("text")) {
|
if (inIncludeTag && !localName.equals("text")) {
|
||||||
validator.reportError(namespacePrefix + ":" + localName
|
validator.reportError(namespacePrefix + ":" + localName
|
||||||
+ " can not appear within "
|
+ " can not appear within "
|
||||||
+ this.namespacePrefix + ":"
|
+ this.namespacePrefix + ":"
|
||||||
+ includeTagName);
|
+ includeTagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endElement(String pNamespaceURI,
|
public void endElement(String pNamespaceURI,
|
||||||
String pLocalName,
|
String pLocalName,
|
||||||
String pQualifiedName)
|
String pQualifiedName)
|
||||||
throws SAXException {
|
throws SAXException {
|
||||||
String namespacePrefix = !StringUtil.isEmpty(pNamespaceURI)
|
String namespacePrefix = !StringUtil.isEmpty(pNamespaceURI)
|
||||||
? getNSPrefixFromURI(pNamespaceURI)
|
? getNSPrefixFromURI(pNamespaceURI)
|
||||||
: getNamespacePrefix(pQualifiedName);
|
: getNamespacePrefix(pQualifiedName);
|
||||||
|
|
||||||
String localName = !StringUtil.isEmpty(pLocalName)
|
String localName = !StringUtil.isEmpty(pLocalName)
|
||||||
? pLocalName : getLocalName(pQualifiedName);
|
? pLocalName : getLocalName(pQualifiedName);
|
||||||
/*
|
/*
|
||||||
if (namespacePrefix.equals(namespacePrefix)) {
|
if (namespacePrefix.equals(namespacePrefix)) {
|
||||||
System.out.println("endElement:\nnamespaceURI=" + pNamespaceURI
|
System.out.println("endElement:\nnamespaceURI=" + pNamespaceURI
|
||||||
+ " namespacePrefix=" + namespacePrefix
|
+ " namespacePrefix=" + namespacePrefix
|
||||||
+ " localName=" + localName
|
+ " localName=" + localName
|
||||||
+ " qName=" + pQualifiedName);
|
+ " qName=" + pQualifiedName);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (namespacePrefix.equals(this.namespacePrefix)
|
if (namespacePrefix.equals(this.namespacePrefix)
|
||||||
&& localName.equals(includeTagName)) {
|
&& localName.equals(includeTagName)) {
|
||||||
|
|
||||||
//System.out.println("</" + namespacePrefix + ":"
|
//System.out.println("</" + namespacePrefix + ":"
|
||||||
// + includeTagName + ">");
|
// + includeTagName + ">");
|
||||||
|
|
||||||
inIncludeTag = false;
|
inIncludeTag = false;
|
||||||
}
|
}
|
||||||
else if (namespacePrefix.equals(this.namespacePrefix)
|
else if (namespacePrefix.equals(this.namespacePrefix)
|
||||||
&& localName.equals(openParamTagName)) {
|
&& localName.equals(openParamTagName)) {
|
||||||
|
|
||||||
//System.out.println("</" + namespacePrefix + ":"
|
//System.out.println("</" + namespacePrefix + ":"
|
||||||
// + openParamTagName + ">");
|
// + openParamTagName + ">");
|
||||||
|
|
||||||
inIncludeTag = true; // assuming no errors before this...
|
inIncludeTag = true; // assuming no errors before this...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stupid broken namespace-support "fix"..
|
* Stupid broken namespace-support "fix"..
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private String getNSPrefixFromURI(String pNamespaceURI) {
|
private String getNSPrefixFromURI(String pNamespaceURI) {
|
||||||
return (pNamespaceURI.equals(namespaceURI)
|
return (pNamespaceURI.equals(namespaceURI)
|
||||||
? namespacePrefix : "");
|
? namespacePrefix : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getNamespacePrefix(String pQualifiedName) {
|
private String getNamespacePrefix(String pQualifiedName) {
|
||||||
return pQualifiedName.substring(0, pQualifiedName.indexOf(':'));
|
return pQualifiedName.substring(0, pQualifiedName.indexOf(':'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLocalName(String pQualifiedName) {
|
private String getLocalName(String pQualifiedName) {
|
||||||
return pQualifiedName.substring(pQualifiedName.indexOf(':') + 1);
|
return pQualifiedName.substring(pQualifiedName.indexOf(':') + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+102
-102
@@ -1,102 +1,102 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: NestingValidator.java,v $
|
* $Log: NestingValidator.java,v $
|
||||||
* Revision 1.4 2003/08/04 15:26:40 WMHAKUR
|
* Revision 1.4 2003/08/04 15:26:40 WMHAKUR
|
||||||
* Code clean-up.
|
* Code clean-up.
|
||||||
*
|
*
|
||||||
* Revision 1.3 2002/11/18 14:12:43 WMHAKUR
|
* Revision 1.3 2002/11/18 14:12:43 WMHAKUR
|
||||||
* *** empty log message ***
|
* *** empty log message ***
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
||||||
* Fixed package error.
|
* Fixed package error.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||||
|
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
import javax.servlet.jsp.tagext.PageData;
|
import javax.servlet.jsp.tagext.PageData;
|
||||||
import javax.servlet.jsp.tagext.TagLibraryValidator;
|
import javax.servlet.jsp.tagext.TagLibraryValidator;
|
||||||
import javax.servlet.jsp.tagext.ValidationMessage;
|
import javax.servlet.jsp.tagext.ValidationMessage;
|
||||||
import javax.xml.parsers.SAXParser;
|
import javax.xml.parsers.SAXParser;
|
||||||
import javax.xml.parsers.SAXParserFactory;
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A validator that verifies that tags follow
|
* A validator that verifies that tags follow
|
||||||
* proper nesting order.
|
* proper nesting order.
|
||||||
* <P>
|
* <P>
|
||||||
* Based on NestingValidator.java,
|
* Based on NestingValidator.java,
|
||||||
* taken from More Servlets and JavaServer Pages
|
* taken from More Servlets and JavaServer Pages
|
||||||
* from Prentice Hall and Sun Microsystems Press,
|
* from Prentice Hall and Sun Microsystems Press,
|
||||||
* http://www.moreservlets.com/.
|
* http://www.moreservlets.com/.
|
||||||
* © 2002 Marty Hall; may be freely used or adapted.
|
* © 2002 Marty Hall; may be freely used or adapted.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class NestingValidator extends TagLibraryValidator {
|
public class NestingValidator extends TagLibraryValidator {
|
||||||
|
|
||||||
private List<ValidationMessage> errors = new ArrayList<ValidationMessage>();
|
private List<ValidationMessage> errors = new ArrayList<ValidationMessage>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public ValidationMessage[] validate(String pPrefix, String pURI, PageData pPage) {
|
public ValidationMessage[] validate(String pPrefix, String pURI, PageData pPage) {
|
||||||
|
|
||||||
//System.out.println("Validating " + pPrefix + " (" + pURI + ") for "
|
//System.out.println("Validating " + pPrefix + " (" + pURI + ") for "
|
||||||
// + pPage + ".");
|
// + pPage + ".");
|
||||||
|
|
||||||
// Pass the parser factory in on the command line with
|
// Pass the parser factory in on the command line with
|
||||||
// -D to override the use of the Apache parser.
|
// -D to override the use of the Apache parser.
|
||||||
|
|
||||||
DefaultHandler handler = new NestingHandler(pPrefix, pURI, this);
|
DefaultHandler handler = new NestingHandler(pPrefix, pURI, this);
|
||||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// FileUtil.copy(pPage.getInputStream(), System.out);
|
// FileUtil.copy(pPage.getInputStream(), System.out);
|
||||||
|
|
||||||
SAXParser parser = factory.newSAXParser();
|
SAXParser parser = factory.newSAXParser();
|
||||||
InputSource source =
|
InputSource source =
|
||||||
new InputSource(pPage.getInputStream());
|
new InputSource(pPage.getInputStream());
|
||||||
|
|
||||||
// Parse, handler will use callback to report errors
|
// Parse, handler will use callback to report errors
|
||||||
parser.parse(source, handler);
|
parser.parse(source, handler);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
String errorMessage = e.getMessage();
|
String errorMessage = e.getMessage();
|
||||||
|
|
||||||
reportError(errorMessage);
|
reportError(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any errors and exceptions, empty array means okay
|
// Return any errors and exceptions, empty array means okay
|
||||||
return errors.toArray(new ValidationMessage[errors.size()]);
|
return errors.toArray(new ValidationMessage[errors.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback method for the handler to report errors
|
* Callback method for the handler to report errors
|
||||||
*/
|
*/
|
||||||
public void reportError(String pMessage) {
|
public void reportError(String pMessage) {
|
||||||
// The first argument to the ValidationMessage
|
// The first argument to the ValidationMessage
|
||||||
// constructor can be a tag ID. Since tag IDs
|
// constructor can be a tag ID. Since tag IDs
|
||||||
// are not universally supported, use null for
|
// are not universally supported, use null for
|
||||||
// portability. The important part is the second
|
// portability. The important part is the second
|
||||||
// argument: the error message.
|
// argument: the error message.
|
||||||
errors.add(new ValidationMessage(null, pMessage));
|
errors.add(new ValidationMessage(null, pMessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+220
-220
@@ -1,220 +1,220 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: OparamTag.java,v $
|
* $Log: OparamTag.java,v $
|
||||||
* Revision 1.4 2003/10/06 14:25:53 WMHAKUR
|
* Revision 1.4 2003/10/06 14:25:53 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.3 2002/11/18 14:12:43 WMHAKUR
|
* Revision 1.3 2002/11/18 14:12:43 WMHAKUR
|
||||||
* *** empty log message ***
|
* *** empty log message ***
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/11/07 12:20:14 WMHAKUR
|
* Revision 1.2 2002/11/07 12:20:14 WMHAKUR
|
||||||
* Updated to reflect changes in com.twelvemonkeys.util.*Util
|
* Updated to reflect changes in com.twelvemonkeys.util.*Util
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||||
|
|
||||||
import com.twelvemonkeys.io.FileUtil;
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.servlet.jsp.droplet.Oparam;
|
import com.twelvemonkeys.servlet.jsp.droplet.Oparam;
|
||||||
import com.twelvemonkeys.servlet.jsp.taglib.BodyReaderTag;
|
import com.twelvemonkeys.servlet.jsp.taglib.BodyReaderTag;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
* Open parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
||||||
*
|
*
|
||||||
* @author Thomas Purcell (CSC Australia)
|
* @author Thomas Purcell (CSC Australia)
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: jsp/droplet/taglib/OparamTag.java#1 $
|
* @version $Id: jsp/droplet/taglib/OparamTag.java#1 $
|
||||||
*/
|
*/
|
||||||
public class OparamTag extends BodyReaderTag {
|
public class OparamTag extends BodyReaderTag {
|
||||||
|
|
||||||
protected final static String COUNTER = "com.twelvemonkeys.servlet.jsp.taglib.OparamTag.counter";
|
protected final static String COUNTER = "com.twelvemonkeys.servlet.jsp.taglib.OparamTag.counter";
|
||||||
|
|
||||||
private File subpage = null;
|
private File subpage = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the name of the parameter to be inserted into the {@code
|
* This is the name of the parameter to be inserted into the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
private String parameterName = null;
|
private String parameterName = null;
|
||||||
|
|
||||||
private String language = null;
|
private String language = null;
|
||||||
|
|
||||||
private String prefix = null;
|
private String prefix = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method allows the JSP page to set the name for the parameter by
|
* This method allows the JSP page to set the name for the parameter by
|
||||||
* using the {@code name} tag attribute.
|
* using the {@code name} tag attribute.
|
||||||
*
|
*
|
||||||
* @param pName The name for the parameter to insert into the {@code
|
* @param pName The name for the parameter to insert into the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
public void setName(String pName) {
|
public void setName(String pName) {
|
||||||
parameterName = pName;
|
parameterName = pName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLanguage(String pLanguage) {
|
public void setLanguage(String pLanguage) {
|
||||||
//System.out.println("setLanguage:"+pLanguage);
|
//System.out.println("setLanguage:"+pLanguage);
|
||||||
language = pLanguage;
|
language = pLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPrefix(String pPrefix) {
|
public void setPrefix(String pPrefix) {
|
||||||
//System.out.println("setPrefix:"+pPrefix);
|
//System.out.println("setPrefix:"+pPrefix);
|
||||||
prefix = pPrefix;
|
prefix = pPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that the tag implemented by this class is enclosed by an {@code IncludeTag}.
|
* Ensure that the tag implemented by this class is enclosed by an {@code IncludeTag}.
|
||||||
* If the tag is not enclosed by an {@code IncludeTag} then a {@code JspException} is thrown.
|
* If the tag is not enclosed by an {@code IncludeTag} then a {@code JspException} is thrown.
|
||||||
*
|
*
|
||||||
* @return If this tag is enclosed within an {@code IncludeTag}, then the default return value
|
* @return If this tag is enclosed within an {@code IncludeTag}, then the default return value
|
||||||
* from this method is the {@code TagSupport.EVAL_BODY_TAG} value.
|
* from this method is the {@code TagSupport.EVAL_BODY_TAG} value.
|
||||||
*
|
*
|
||||||
* @throws JspException
|
* @throws JspException
|
||||||
*/
|
*/
|
||||||
public int doStartTag() throws JspException {
|
public int doStartTag() throws JspException {
|
||||||
//checkEnclosedInIncludeTag(); // Moved to TagLibValidator
|
//checkEnclosedInIncludeTag(); // Moved to TagLibValidator
|
||||||
|
|
||||||
// Get request
|
// Get request
|
||||||
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
|
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
|
||||||
|
|
||||||
// Get filename
|
// Get filename
|
||||||
subpage = createFileNameFromRequest(request);
|
subpage = createFileNameFromRequest(request);
|
||||||
|
|
||||||
// Get include tag, and add to parameters
|
// Get include tag, and add to parameters
|
||||||
IncludeTag includeTag = (IncludeTag) getParent();
|
IncludeTag includeTag = (IncludeTag) getParent();
|
||||||
includeTag.addParameter(parameterName, new Oparam(subpage.getName()));
|
includeTag.addParameter(parameterName, new Oparam(subpage.getName()));
|
||||||
|
|
||||||
// if ! subpage.exist || jsp newer than subpage, write new
|
// if ! subpage.exist || jsp newer than subpage, write new
|
||||||
File jsp = new File(pageContext.getServletContext().getRealPath(request.getServletPath()));
|
File jsp = new File(pageContext.getServletContext().getRealPath(request.getServletPath()));
|
||||||
|
|
||||||
if (!subpage.exists() || jsp.lastModified() > subpage.lastModified()) {
|
if (!subpage.exists() || jsp.lastModified() > subpage.lastModified()) {
|
||||||
return EVAL_BODY_BUFFERED;
|
return EVAL_BODY_BUFFERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to evaluate body again!
|
// No need to evaluate body again!
|
||||||
return SKIP_BODY;
|
return SKIP_BODY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the method responsible for actually testing that the tag
|
* This is the method responsible for actually testing that the tag
|
||||||
* implemented by this class is enclosed within an {@code IncludeTag}.
|
* implemented by this class is enclosed within an {@code IncludeTag}.
|
||||||
*
|
*
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
protected void checkEnclosedInIncludeTag() throws JspException {
|
protected void checkEnclosedInIncludeTag() throws JspException {
|
||||||
Tag parentTag = getParent();
|
Tag parentTag = getParent();
|
||||||
|
|
||||||
if ((parentTag != null) && (parentTag instanceof IncludeTag)) {
|
if ((parentTag != null) && (parentTag instanceof IncludeTag)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String msg = "A class that extends EnclosedIncludeBodyReaderTag " +
|
String msg = "A class that extends EnclosedIncludeBodyReaderTag " +
|
||||||
"is not enclosed within an IncludeTag.";
|
"is not enclosed within an IncludeTag.";
|
||||||
log(msg);
|
log(msg);
|
||||||
throw new JspException(msg);
|
throw new JspException(msg);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method cleans up the member variables for this tag in preparation
|
* This method cleans up the member variables for this tag in preparation
|
||||||
* for being used again. This method is called when the tag finishes it's
|
* for being used again. This method is called when the tag finishes it's
|
||||||
* current call with in the page but could be called upon again within this
|
* current call with in the page but could be called upon again within this
|
||||||
* same page. This method is also called in the release stage of the tag
|
* same page. This method is also called in the release stage of the tag
|
||||||
* life cycle just in case a JspException was thrown during the tag
|
* life cycle just in case a JspException was thrown during the tag
|
||||||
* execution.
|
* execution.
|
||||||
*/
|
*/
|
||||||
protected void clearServiceState() {
|
protected void clearServiceState() {
|
||||||
parameterName = null;
|
parameterName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the method responsible for taking the result of the JSP code
|
* This is the method responsible for taking the result of the JSP code
|
||||||
* that forms the body of this tag and inserts it as a parameter into the
|
* that forms the body of this tag and inserts it as a parameter into the
|
||||||
* request scope session. If any problems occur while loading the body
|
* request scope session. If any problems occur while loading the body
|
||||||
* into the session scope then a {@code JspException} will be thrown.
|
* into the session scope then a {@code JspException} will be thrown.
|
||||||
*
|
*
|
||||||
* @param pContent The body of the tag as a String.
|
* @param pContent The body of the tag as a String.
|
||||||
* @throws JspException
|
* @throws JspException
|
||||||
*/
|
*/
|
||||||
protected void processBody(String pContent) throws JspException {
|
protected void processBody(String pContent) throws JspException {
|
||||||
// Okay, we have the content, we need to write it to disk somewhere
|
// Okay, we have the content, we need to write it to disk somewhere
|
||||||
String content = pContent;
|
String content = pContent;
|
||||||
|
|
||||||
if (!StringUtil.isEmpty(language)) {
|
if (!StringUtil.isEmpty(language)) {
|
||||||
content = "<%@page language=\"" + language + "\" %>" + content;
|
content = "<%@page language=\"" + language + "\" %>" + content;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StringUtil.isEmpty(prefix)) {
|
if (!StringUtil.isEmpty(prefix)) {
|
||||||
content = "<%@taglib uri=\"/twelvemonkeys-common\" prefix=\"" + prefix + "\" %>" + content;
|
content = "<%@taglib uri=\"/twelvemonkeys-common\" prefix=\"" + prefix + "\" %>" + content;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the content of the oparam to disk
|
// Write the content of the oparam to disk
|
||||||
try {
|
try {
|
||||||
log("Processing subpage " + subpage.getPath());
|
log("Processing subpage " + subpage.getPath());
|
||||||
FileUtil.write(subpage, content.getBytes());
|
FileUtil.write(subpage, content.getBytes());
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
throw new JspException(ioe);
|
throw new JspException(ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a unique filename for each (nested) oparam */
|
/** Creates a unique filename for each (nested) oparam */
|
||||||
private File createFileNameFromRequest(HttpServletRequest pRequest) {
|
private File createFileNameFromRequest(HttpServletRequest pRequest) {
|
||||||
//System.out.println("ServletPath" + pRequest.getServletPath());
|
//System.out.println("ServletPath" + pRequest.getServletPath());
|
||||||
String path = pRequest.getServletPath();
|
String path = pRequest.getServletPath();
|
||||||
|
|
||||||
// Find last '/'
|
// Find last '/'
|
||||||
int splitIndex = path.lastIndexOf("/");
|
int splitIndex = path.lastIndexOf("/");
|
||||||
|
|
||||||
// Split -> path + name
|
// Split -> path + name
|
||||||
String name = path.substring(splitIndex + 1);
|
String name = path.substring(splitIndex + 1);
|
||||||
path = path.substring(0, splitIndex);
|
path = path.substring(0, splitIndex);
|
||||||
|
|
||||||
// Replace special chars in name with '_'
|
// Replace special chars in name with '_'
|
||||||
name = name.replace('.', '_');
|
name = name.replace('.', '_');
|
||||||
String param = parameterName.replace('.', '_');
|
String param = parameterName.replace('.', '_');
|
||||||
param = param.replace('/', '_');
|
param = param.replace('/', '_');
|
||||||
param = param.replace('\\', '_');
|
param = param.replace('\\', '_');
|
||||||
param = param.replace(':', '_');
|
param = param.replace(':', '_');
|
||||||
|
|
||||||
// tempfile = realPath(path) + name + "_oparam_" + number + ".jsp"
|
// tempfile = realPath(path) + name + "_oparam_" + number + ".jsp"
|
||||||
int count = getOparamCountFromRequest(pRequest);
|
int count = getOparamCountFromRequest(pRequest);
|
||||||
|
|
||||||
// Hmm.. Would be great, but seems like I can't serve pages from within the temp dir
|
// Hmm.. Would be great, but seems like I can't serve pages from within the temp dir
|
||||||
//File temp = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");
|
//File temp = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");
|
||||||
//return new File(new File(temp, path), name + "_oparam_" + count + "_" + param + ".jsp");
|
//return new File(new File(temp, path), name + "_oparam_" + count + "_" + param + ".jsp");
|
||||||
|
|
||||||
return new File(new File(pageContext.getServletContext().getRealPath(path)), name + "_oparam_" + count + "_" + param + ".jsp");
|
return new File(new File(pageContext.getServletContext().getRealPath(path)), name + "_oparam_" + count + "_" + param + ".jsp");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the current oparam count for this request */
|
/** Gets the current oparam count for this request */
|
||||||
private int getOparamCountFromRequest(HttpServletRequest pRequest) {
|
private int getOparamCountFromRequest(HttpServletRequest pRequest) {
|
||||||
// Use request.attribute for incrementing oparam counter
|
// Use request.attribute for incrementing oparam counter
|
||||||
Integer count = (Integer) pRequest.getAttribute(COUNTER);
|
Integer count = (Integer) pRequest.getAttribute(COUNTER);
|
||||||
if (count == null) {
|
if (count == null) {
|
||||||
count = new Integer(0);
|
count = new Integer(0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
count = new Integer(count.intValue() + 1);
|
count = new Integer(count.intValue() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... and set it back
|
// ... and set it back
|
||||||
pRequest.setAttribute(COUNTER, count);
|
pRequest.setAttribute(COUNTER, count);
|
||||||
|
|
||||||
return count.intValue();
|
return count.intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+129
-129
@@ -1,129 +1,129 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: ParamTag.java,v $
|
* $Log: ParamTag.java,v $
|
||||||
* Revision 1.2 2003/10/06 14:26:00 WMHAKUR
|
* Revision 1.2 2003/10/06 14:26:00 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.jsp.droplet.Param;
|
import com.twelvemonkeys.servlet.jsp.droplet.Param;
|
||||||
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
|
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
|
||||||
|
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
* Parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
||||||
*
|
*
|
||||||
* @author Thomas Purcell (CSC Australia)
|
* @author Thomas Purcell (CSC Australia)
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ParamTag extends ExTagSupport {
|
public class ParamTag extends ExTagSupport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the name of the parameter to be inserted into the {@code
|
* This is the name of the parameter to be inserted into the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
private String parameterName;
|
private String parameterName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the value for the parameter to be inserted into the {@code
|
* This is the value for the parameter to be inserted into the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
private Object parameterValue;
|
private Object parameterValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method allows the JSP page to set the name for the parameter by
|
* This method allows the JSP page to set the name for the parameter by
|
||||||
* using the {@code name} tag attribute.
|
* using the {@code name} tag attribute.
|
||||||
*
|
*
|
||||||
* @param pName The name for the parameter to insert into the {@code
|
* @param pName The name for the parameter to insert into the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
public void setName(String pName) {
|
public void setName(String pName) {
|
||||||
parameterName = pName;
|
parameterName = pName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method allows the JSP page to set the value for hte parameter by
|
* This method allows the JSP page to set the value for hte parameter by
|
||||||
* using the {@code value} tag attribute.
|
* using the {@code value} tag attribute.
|
||||||
*
|
*
|
||||||
* @param pValue The value for the parameter to insert into the <code>
|
* @param pValue The value for the parameter to insert into the <code>
|
||||||
* PageContext.REQUEST_SCOPE</page> scope.
|
* PageContext.REQUEST_SCOPE</page> scope.
|
||||||
*/
|
*/
|
||||||
public void setValue(String pValue) {
|
public void setValue(String pValue) {
|
||||||
parameterValue = new Param(pValue);
|
parameterValue = new Param(pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that the tag implemented by this class is enclosed by an {@code
|
* Ensure that the tag implemented by this class is enclosed by an {@code
|
||||||
* IncludeTag}. If the tag is not enclosed by an
|
* IncludeTag}. If the tag is not enclosed by an
|
||||||
* {@code IncludeTag} then a {@code JspException} is thrown.
|
* {@code IncludeTag} then a {@code JspException} is thrown.
|
||||||
*
|
*
|
||||||
* @return If this tag is enclosed within an {@code IncludeTag}, then
|
* @return If this tag is enclosed within an {@code IncludeTag}, then
|
||||||
* the default return value from this method is the {@code
|
* the default return value from this method is the {@code
|
||||||
* TagSupport.SKIP_BODY} value.
|
* TagSupport.SKIP_BODY} value.
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
public int doStartTag() throws JspException {
|
public int doStartTag() throws JspException {
|
||||||
//checkEnclosedInIncludeTag();
|
//checkEnclosedInIncludeTag();
|
||||||
|
|
||||||
addParameter();
|
addParameter();
|
||||||
|
|
||||||
return SKIP_BODY;
|
return SKIP_BODY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the method responsible for actually testing that the tag
|
* This is the method responsible for actually testing that the tag
|
||||||
* implemented by this class is enclosed within an {@code IncludeTag}.
|
* implemented by this class is enclosed within an {@code IncludeTag}.
|
||||||
*
|
*
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
protected void checkEnclosedInIncludeTag() throws JspException {
|
protected void checkEnclosedInIncludeTag() throws JspException {
|
||||||
Tag parentTag = getParent();
|
Tag parentTag = getParent();
|
||||||
|
|
||||||
if ((parentTag != null) && (parentTag instanceof IncludeTag)) {
|
if ((parentTag != null) && (parentTag instanceof IncludeTag)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String msg = "A class that extends EnclosedIncludeBodyReaderTag " +
|
String msg = "A class that extends EnclosedIncludeBodyReaderTag " +
|
||||||
"is not enclosed within an IncludeTag.";
|
"is not enclosed within an IncludeTag.";
|
||||||
log(msg);
|
log(msg);
|
||||||
throw new JspException(msg);
|
throw new JspException(msg);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method adds the parameter whose name and value were passed to this
|
* This method adds the parameter whose name and value were passed to this
|
||||||
* object via the tag attributes to the parent {@code Include} tag.
|
* object via the tag attributes to the parent {@code Include} tag.
|
||||||
*/
|
*/
|
||||||
private void addParameter() {
|
private void addParameter() {
|
||||||
IncludeTag includeTag = (IncludeTag) getParent();
|
IncludeTag includeTag = (IncludeTag) getParent();
|
||||||
|
|
||||||
includeTag.addParameter(parameterName, parameterValue);
|
includeTag.addParameter(parameterName, parameterValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method cleans up the member variables for this tag in preparation
|
* This method cleans up the member variables for this tag in preparation
|
||||||
* for being used again. This method is called when the tag finishes it's
|
* for being used again. This method is called when the tag finishes it's
|
||||||
* current call with in the page but could be called upon again within this
|
* current call with in the page but could be called upon again within this
|
||||||
* same page. This method is also called in the release stage of the tag
|
* same page. This method is also called in the release stage of the tag
|
||||||
* life cycle just in case a JspException was thrown during the tag
|
* life cycle just in case a JspException was thrown during the tag
|
||||||
* execution.
|
* execution.
|
||||||
*/
|
*/
|
||||||
protected void clearServiceState() {
|
protected void clearServiceState() {
|
||||||
parameterName = null;
|
parameterName = null;
|
||||||
parameterValue = null;
|
parameterValue = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-47
@@ -1,47 +1,47 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: ValueOfTEI.java,v $
|
* $Log: ValueOfTEI.java,v $
|
||||||
* Revision 1.3 2003/10/06 14:26:07 WMHAKUR
|
* Revision 1.3 2003/10/06 14:26:07 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
||||||
* Fixed package error.
|
* Fixed package error.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:03:52 WMHAKUR
|
* Revision 1.1 2002/10/18 14:03:52 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||||
|
|
||||||
import javax.servlet.jsp.tagext.TagData;
|
import javax.servlet.jsp.tagext.TagData;
|
||||||
import javax.servlet.jsp.tagext.TagExtraInfo;
|
import javax.servlet.jsp.tagext.TagExtraInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TagExtraInfo for ValueOf.
|
* TagExtraInfo for ValueOf.
|
||||||
* @todo More meaningful response to the user.
|
* @todo More meaningful response to the user.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ValueOfTEI extends TagExtraInfo {
|
public class ValueOfTEI extends TagExtraInfo {
|
||||||
|
|
||||||
public boolean isValid(TagData pTagData) {
|
public boolean isValid(TagData pTagData) {
|
||||||
Object nameAttr = pTagData.getAttribute("name");
|
Object nameAttr = pTagData.getAttribute("name");
|
||||||
Object paramAttr = pTagData.getAttribute("param");
|
Object paramAttr = pTagData.getAttribute("param");
|
||||||
|
|
||||||
if ((nameAttr != null && paramAttr == null) || (nameAttr == null && paramAttr != null)) {
|
if ((nameAttr != null && paramAttr == null) || (nameAttr == null && paramAttr != null)) {
|
||||||
return true; // Exactly one of name or param set
|
return true; // Exactly one of name or param set
|
||||||
}
|
}
|
||||||
|
|
||||||
// Either both or none,
|
// Either both or none,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+148
-148
@@ -1,148 +1,148 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: ValueOfTag.java,v $
|
* $Log: ValueOfTag.java,v $
|
||||||
* Revision 1.2 2003/10/06 14:26:14 WMHAKUR
|
* Revision 1.2 2003/10/06 14:26:14 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/10/18 14:03:52 WMHAKUR
|
* Revision 1.1 2002/10/18 14:03:52 WMHAKUR
|
||||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.jsp.droplet.JspFragment;
|
import com.twelvemonkeys.servlet.jsp.droplet.JspFragment;
|
||||||
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
|
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import javax.servlet.jsp.JspWriter;
|
import javax.servlet.jsp.JspWriter;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ValueOf tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
* ValueOf tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
||||||
*
|
*
|
||||||
* @author Thomas Purcell (CSC Australia)
|
* @author Thomas Purcell (CSC Australia)
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||||
*/
|
*/
|
||||||
public class ValueOfTag extends ExTagSupport {
|
public class ValueOfTag extends ExTagSupport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the name of the parameter whose value is to be inserted into
|
* This is the name of the parameter whose value is to be inserted into
|
||||||
* the current JSP page. This value will be set via the {@code name}
|
* the current JSP page. This value will be set via the {@code name}
|
||||||
* attribute.
|
* attribute.
|
||||||
*/
|
*/
|
||||||
private String parameterName;
|
private String parameterName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the value of the parameter read from the {@code
|
* This is the value of the parameter read from the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope. If the parameter doesn't exist,
|
* PageContext.REQUEST_SCOPE} scope. If the parameter doesn't exist,
|
||||||
* then this will be null.
|
* then this will be null.
|
||||||
*/
|
*/
|
||||||
private Object parameterValue;
|
private Object parameterValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called as part of the initialisation phase of the tag
|
* This method is called as part of the initialisation phase of the tag
|
||||||
* life cycle. It sets the parameter name to be read from the {@code
|
* life cycle. It sets the parameter name to be read from the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*
|
*
|
||||||
* @param pName The name of the parameter to be read from the {@code
|
* @param pName The name of the parameter to be read from the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
public void setName(String pName) {
|
public void setName(String pName) {
|
||||||
parameterName = pName;
|
parameterName = pName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called as part of the initialisation phase of the tag
|
* This method is called as part of the initialisation phase of the tag
|
||||||
* life cycle. It sets the parameter name to be read from the {@code
|
* life cycle. It sets the parameter name to be read from the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope. This is just a synonym for
|
* PageContext.REQUEST_SCOPE} scope. This is just a synonym for
|
||||||
* setName, to be more like ATG Dynamo.
|
* setName, to be more like ATG Dynamo.
|
||||||
*
|
*
|
||||||
* @param pName The name of the parameter to be read from the {@code
|
* @param pName The name of the parameter to be read from the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope.
|
* PageContext.REQUEST_SCOPE} scope.
|
||||||
*/
|
*/
|
||||||
public void setParam(String pName) {
|
public void setParam(String pName) {
|
||||||
parameterName = pName;
|
parameterName = pName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method looks in the session scope for the session-scoped attribute
|
* This method looks in the session scope for the session-scoped attribute
|
||||||
* whose name matches the {@code name} tag attribute for this tag.
|
* whose name matches the {@code name} tag attribute for this tag.
|
||||||
* If it finds it, then it replaces this tag with the value for the
|
* If it finds it, then it replaces this tag with the value for the
|
||||||
* session-scoped attribute. If it fails to find the session-scoped
|
* session-scoped attribute. If it fails to find the session-scoped
|
||||||
* attribute, it displays the body for this tag.
|
* attribute, it displays the body for this tag.
|
||||||
*
|
*
|
||||||
* @return If the session-scoped attribute is found, then this method will
|
* @return If the session-scoped attribute is found, then this method will
|
||||||
* return {@code TagSupport.SKIP_BODY}, otherwise it will return
|
* return {@code TagSupport.SKIP_BODY}, otherwise it will return
|
||||||
* {@code TagSupport.EVAL_BODY_INCLUDE}.
|
* {@code TagSupport.EVAL_BODY_INCLUDE}.
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public int doStartTag() throws JspException {
|
public int doStartTag() throws JspException {
|
||||||
try {
|
try {
|
||||||
if (parameterExists()) {
|
if (parameterExists()) {
|
||||||
if (parameterValue instanceof JspFragment) {
|
if (parameterValue instanceof JspFragment) {
|
||||||
// OPARAM or PARAM
|
// OPARAM or PARAM
|
||||||
((JspFragment) parameterValue).service(pageContext);
|
((JspFragment) parameterValue).service(pageContext);
|
||||||
/*
|
/*
|
||||||
log("Service subpage " + pageContext.getServletContext().getRealPath(((Oparam) parameterValue).getName()));
|
log("Service subpage " + pageContext.getServletContext().getRealPath(((Oparam) parameterValue).getName()));
|
||||||
|
|
||||||
pageContext.include(((Oparam) parameterValue).getName());
|
pageContext.include(((Oparam) parameterValue).getName());
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Normal JSP parameter value
|
// Normal JSP parameter value
|
||||||
JspWriter writer = pageContext.getOut();
|
JspWriter writer = pageContext.getOut();
|
||||||
writer.print(parameterValue);
|
writer.print(parameterValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SKIP_BODY;
|
return SKIP_BODY;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return EVAL_BODY_INCLUDE;
|
return EVAL_BODY_INCLUDE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ServletException se) {
|
catch (ServletException se) {
|
||||||
log(se.getMessage(), se);
|
log(se.getMessage(), se);
|
||||||
throw new JspException(se);
|
throw new JspException(se);
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
String msg = "Caught an IOException in ValueOfTag.doStartTag()\n"
|
String msg = "Caught an IOException in ValueOfTag.doStartTag()\n"
|
||||||
+ ioe.toString();
|
+ ioe.toString();
|
||||||
log(msg, ioe);
|
log(msg, ioe);
|
||||||
throw new JspException(msg);
|
throw new JspException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is used to determine whether the parameter whose name is
|
* This method is used to determine whether the parameter whose name is
|
||||||
* stored in {@code mParameterName} exists within the {@code
|
* stored in {@code mParameterName} exists within the {@code
|
||||||
* PageContext.REQUEST_SCOPE} scope. If the parameter does exist,
|
* PageContext.REQUEST_SCOPE} scope. If the parameter does exist,
|
||||||
* then this method will return {@code true}, otherwise it returns
|
* then this method will return {@code true}, otherwise it returns
|
||||||
* {@code false}. This method has the side affect of loading the
|
* {@code false}. This method has the side affect of loading the
|
||||||
* parameter value into {@code mParameterValue} if the parameter
|
* parameter value into {@code mParameterValue} if the parameter
|
||||||
* does exist.
|
* does exist.
|
||||||
*
|
*
|
||||||
* @return {@code true} if the parameter whose name is in {@code
|
* @return {@code true} if the parameter whose name is in {@code
|
||||||
* mParameterName} exists in the {@code PageContext.REQUEST_SCOPE
|
* mParameterName} exists in the {@code PageContext.REQUEST_SCOPE
|
||||||
* } scope, {@code false} otherwise.
|
* } scope, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean parameterExists() {
|
private boolean parameterExists() {
|
||||||
parameterValue = pageContext.getAttribute(parameterName, PageContext.REQUEST_SCOPE);
|
parameterValue = pageContext.getAttribute(parameterName, PageContext.REQUEST_SCOPE);
|
||||||
|
|
||||||
// -- Harald K 20020726
|
// -- Harald K 20020726
|
||||||
if (parameterValue == null) {
|
if (parameterValue == null) {
|
||||||
parameterValue = pageContext.getRequest().getParameter(parameterName);
|
parameterValue = pageContext.getRequest().getParameter(parameterName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (parameterValue != null);
|
return (parameterValue != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-39
@@ -1,39 +1,39 @@
|
|||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @author Thomas Purcell (CSC Australia)
|
* @author Thomas Purcell (CSC Australia)
|
||||||
*
|
*
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
public abstract class BodyReaderTag extends ExBodyTagSupport {
|
public abstract class BodyReaderTag extends ExBodyTagSupport {
|
||||||
/**
|
/**
|
||||||
* This is the method called by the JSP engine when the body for a tag
|
* This is the method called by the JSP engine when the body for a tag
|
||||||
* has been parsed and is ready for inclusion in this current tag. This
|
* has been parsed and is ready for inclusion in this current tag. This
|
||||||
* method takes the content as a string and passes it to the {@code
|
* method takes the content as a string and passes it to the {@code
|
||||||
* processBody} method.
|
* processBody} method.
|
||||||
*
|
*
|
||||||
* @return This method returns the {@code BodyTagSupport.SKIP_BODY}
|
* @return This method returns the {@code BodyTagSupport.SKIP_BODY}
|
||||||
* constant. This means that the body of the tag will only be
|
* constant. This means that the body of the tag will only be
|
||||||
* processed the one time.
|
* processed the one time.
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
public int doAfterBody() throws JspException {
|
public int doAfterBody() throws JspException {
|
||||||
processBody(bodyContent.getString());
|
processBody(bodyContent.getString());
|
||||||
return SKIP_BODY;
|
return SKIP_BODY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the method that child classes must implement. It takes the
|
* This is the method that child classes must implement. It takes the
|
||||||
* body of the tag converted to a String as it's parameter. The body of
|
* body of the tag converted to a String as it's parameter. The body of
|
||||||
* the tag will have been interpreted to a String by the JSP engine before
|
* the tag will have been interpreted to a String by the JSP engine before
|
||||||
* this method is called.
|
* this method is called.
|
||||||
*
|
*
|
||||||
* @param pContent The body for the custom tag converted to a String.
|
* @param pContent The body for the custom tag converted to a String.
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
protected abstract void processBody(String pContent) throws JspException;
|
protected abstract void processBody(String pContent) throws JspException;
|
||||||
}
|
}
|
||||||
|
|||||||
+235
-235
@@ -1,235 +1,235 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: CSVToTableTag.java,v $
|
* $Log: CSVToTableTag.java,v $
|
||||||
* Revision 1.3 2003/10/06 14:24:50 WMHAKUR
|
* Revision 1.3 2003/10/06 14:24:50 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/11/26 17:33:49 WMHAKUR
|
* Revision 1.2 2002/11/26 17:33:49 WMHAKUR
|
||||||
* Added documentation & removed System.out.println()s.
|
* Added documentation & removed System.out.println()s.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/11/19 10:50:10 WMHAKUR
|
* Revision 1.1 2002/11/19 10:50:10 WMHAKUR
|
||||||
* Renamed from CSVToTable, to follow naming conventions.
|
* Renamed from CSVToTable, to follow naming conventions.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/11/18 22:11:16 WMHAKUR
|
* Revision 1.1 2002/11/18 22:11:16 WMHAKUR
|
||||||
* Tag to convert CSV to HTML table.
|
* Tag to convert CSV to HTML table.
|
||||||
* Can be further transformed, using XSLT.
|
* Can be further transformed, using XSLT.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import javax.servlet.jsp.JspWriter;
|
import javax.servlet.jsp.JspWriter;
|
||||||
import javax.servlet.jsp.tagext.BodyContent;
|
import javax.servlet.jsp.tagext.BodyContent;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a table from a string of "comma-separated values" (CSV).
|
* Creates a table from a string of "comma-separated values" (CSV).
|
||||||
* The delimiter character can be any character (or combination of characters).
|
* The delimiter character can be any character (or combination of characters).
|
||||||
* The default delimiter is TAB ({@code \t}).
|
* The default delimiter is TAB ({@code \t}).
|
||||||
*
|
*
|
||||||
* <P/>
|
* <P/>
|
||||||
* <HR/>
|
* <HR/>
|
||||||
* <P/>
|
* <P/>
|
||||||
*
|
*
|
||||||
* The input may look like this:
|
* The input may look like this:
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* <c:totable firstRowIsHeader="true" delimiter=";">
|
* <c:totable firstRowIsHeader="true" delimiter=";">
|
||||||
* header A;header B
|
* header A;header B
|
||||||
* data 1A; data 1B
|
* data 1A; data 1B
|
||||||
* data 2A; data 2B
|
* data 2A; data 2B
|
||||||
* </c:totable>
|
* </c:totable>
|
||||||
* </PRE>
|
* </PRE>
|
||||||
*
|
*
|
||||||
* The output (source) will look like this:
|
* The output (source) will look like this:
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* <TABLE>
|
* <TABLE>
|
||||||
* <TR>
|
* <TR>
|
||||||
* <TH>header A</TH><TH>header B</TH>
|
* <TH>header A</TH><TH>header B</TH>
|
||||||
* </TR>
|
* </TR>
|
||||||
* <TR>
|
* <TR>
|
||||||
* <TD>data 1A</TD><TD>data 1B</TD>
|
* <TD>data 1A</TD><TD>data 1B</TD>
|
||||||
* </TR>
|
* </TR>
|
||||||
* <TR>
|
* <TR>
|
||||||
* <TD>data 2A</TD><TD>data 2B</TD>
|
* <TD>data 2A</TD><TD>data 2B</TD>
|
||||||
* </TR>
|
* </TR>
|
||||||
* </TABLE>
|
* </TABLE>
|
||||||
* </PRE>
|
* </PRE>
|
||||||
* You wil probably want to use XSLT to make the final output look nicer. :-)
|
* You wil probably want to use XSLT to make the final output look nicer. :-)
|
||||||
*
|
*
|
||||||
* @see StringTokenizer
|
* @see StringTokenizer
|
||||||
* @see <A href="http://www.w3.org/TR/xslt">XSLT spec</A>
|
* @see <A href="http://www.w3.org/TR/xslt">XSLT spec</A>
|
||||||
*
|
*
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
*
|
*
|
||||||
* @version $Id: jsp/taglib/CSVToTableTag.java#1 $
|
* @version $Id: jsp/taglib/CSVToTableTag.java#1 $
|
||||||
*/
|
*/
|
||||||
public class CSVToTableTag extends ExBodyTagSupport {
|
public class CSVToTableTag extends ExBodyTagSupport {
|
||||||
public final static String TAB = "\t";
|
public final static String TAB = "\t";
|
||||||
|
|
||||||
protected String delimiter = null;
|
protected String delimiter = null;
|
||||||
protected boolean firstRowIsHeader = false;
|
protected boolean firstRowIsHeader = false;
|
||||||
protected boolean firstColIsHeader = false;
|
protected boolean firstColIsHeader = false;
|
||||||
|
|
||||||
public void setDelimiter(String pDelimiter) {
|
public void setDelimiter(String pDelimiter) {
|
||||||
delimiter = pDelimiter;
|
delimiter = pDelimiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDelimiter() {
|
public String getDelimiter() {
|
||||||
return delimiter != null ? delimiter : TAB;
|
return delimiter != null ? delimiter : TAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFirstRowIsHeader(String pBoolean) {
|
public void setFirstRowIsHeader(String pBoolean) {
|
||||||
firstRowIsHeader = Boolean.valueOf(pBoolean);
|
firstRowIsHeader = Boolean.valueOf(pBoolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFirstColIsHeader(String pBoolean) {
|
public void setFirstColIsHeader(String pBoolean) {
|
||||||
firstColIsHeader = Boolean.valueOf(pBoolean);
|
firstColIsHeader = Boolean.valueOf(pBoolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
BodyContent content = getBodyContent();
|
BodyContent content = getBodyContent();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Table table =
|
Table table =
|
||||||
Table.parseContent(content.getReader(), getDelimiter());
|
Table.parseContent(content.getReader(), getDelimiter());
|
||||||
|
|
||||||
JspWriter out = pageContext.getOut();
|
JspWriter out = pageContext.getOut();
|
||||||
|
|
||||||
//System.out.println("CSVToTable: " + table.getRows() + " rows, "
|
//System.out.println("CSVToTable: " + table.getRows() + " rows, "
|
||||||
// + table.getCols() + " cols.");
|
// + table.getCols() + " cols.");
|
||||||
|
|
||||||
if (table.getRows() > 0) {
|
if (table.getRows() > 0) {
|
||||||
out.println("<TABLE>");
|
out.println("<TABLE>");
|
||||||
// Loop over rows
|
// Loop over rows
|
||||||
for (int row = 0; row < table.getRows(); row++) {
|
for (int row = 0; row < table.getRows(); row++) {
|
||||||
out.println("<TR>");
|
out.println("<TR>");
|
||||||
|
|
||||||
// Loop over cells in each row
|
// Loop over cells in each row
|
||||||
for (int col = 0; col < table.getCols(); col++) {
|
for (int col = 0; col < table.getCols(); col++) {
|
||||||
// Test if we are using headers, else normal cell
|
// Test if we are using headers, else normal cell
|
||||||
if (firstRowIsHeader && row == 0 || firstColIsHeader && col == 0) {
|
if (firstRowIsHeader && row == 0 || firstColIsHeader && col == 0) {
|
||||||
out.println("<TH>" + table.get(row, col) + " </TH>");
|
out.println("<TH>" + table.get(row, col) + " </TH>");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
out.println("<TD>" + table.get(row, col) + " </TD>");
|
out.println("<TD>" + table.get(row, col) + " </TD>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.println("</TR>");
|
out.println("</TR>");
|
||||||
|
|
||||||
}
|
}
|
||||||
out.println("</TABLE>");
|
out.println("</TABLE>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
throw new JspException(ioe);
|
throw new JspException(ioe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.doEndTag();
|
return super.doEndTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Table {
|
static class Table {
|
||||||
List rows = null;
|
List rows = null;
|
||||||
int cols = 0;
|
int cols = 0;
|
||||||
|
|
||||||
private Table(List pRows, int pCols) {
|
private Table(List pRows, int pCols) {
|
||||||
rows = pRows;
|
rows = pRows;
|
||||||
cols = pCols;
|
cols = pCols;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getRows() {
|
int getRows() {
|
||||||
return rows != null ? rows.size() : 0;
|
return rows != null ? rows.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getCols() {
|
int getCols() {
|
||||||
return cols;
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
List getTableRows() {
|
List getTableRows() {
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
List getTableRow(int pRow) {
|
List getTableRow(int pRow) {
|
||||||
return rows != null
|
return rows != null
|
||||||
? (List) rows.get(pRow)
|
? (List) rows.get(pRow)
|
||||||
: Collections.EMPTY_LIST;
|
: Collections.EMPTY_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get(int pRow, int pCol) {
|
String get(int pRow, int pCol) {
|
||||||
List row = getTableRow(pRow);
|
List row = getTableRow(pRow);
|
||||||
// Rows may contain unequal number of cols
|
// Rows may contain unequal number of cols
|
||||||
return (row.size() > pCol) ? (String) row.get(pCol) : "";
|
return (row.size() > pCol) ? (String) row.get(pCol) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a BodyContent to a table.
|
* Parses a BodyContent to a table.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static Table parseContent(Reader pContent, String pDelim) throws IOException {
|
static Table parseContent(Reader pContent, String pDelim) throws IOException {
|
||||||
List<List<String>> tableRows = new ArrayList<List<String>>();
|
List<List<String>> tableRows = new ArrayList<List<String>>();
|
||||||
int tdsPerTR = 0;
|
int tdsPerTR = 0;
|
||||||
|
|
||||||
// Loop through TRs
|
// Loop through TRs
|
||||||
BufferedReader reader = new BufferedReader(pContent);
|
BufferedReader reader = new BufferedReader(pContent);
|
||||||
String tr;
|
String tr;
|
||||||
while ((tr = reader.readLine()) != null) {
|
while ((tr = reader.readLine()) != null) {
|
||||||
// Discard blank lines
|
// Discard blank lines
|
||||||
if (tr.trim().length() <= 0 && tr.indexOf(pDelim) < 0) {
|
if (tr.trim().length() <= 0 && tr.indexOf(pDelim) < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//System.out.println("CSVToTable: read LINE=\"" + tr + "\"");
|
//System.out.println("CSVToTable: read LINE=\"" + tr + "\"");
|
||||||
|
|
||||||
List<String> tableDatas = new ArrayList<String>();
|
List<String> tableDatas = new ArrayList<String>();
|
||||||
StringTokenizer tableRow = new StringTokenizer(tr, pDelim,
|
StringTokenizer tableRow = new StringTokenizer(tr, pDelim,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
boolean lastWasDelim = false;
|
boolean lastWasDelim = false;
|
||||||
while (tableRow.hasMoreTokens()) {
|
while (tableRow.hasMoreTokens()) {
|
||||||
String td = tableRow.nextToken();
|
String td = tableRow.nextToken();
|
||||||
|
|
||||||
//System.out.println("CSVToTable: read data=\"" + td + "\"");
|
//System.out.println("CSVToTable: read data=\"" + td + "\"");
|
||||||
|
|
||||||
// Test if we have empty TD
|
// Test if we have empty TD
|
||||||
if (td.equals(pDelim)) {
|
if (td.equals(pDelim)) {
|
||||||
if (lastWasDelim) {
|
if (lastWasDelim) {
|
||||||
// Add empty TD
|
// Add empty TD
|
||||||
tableDatas.add("");
|
tableDatas.add("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We just read a delimitter
|
// We just read a delimitter
|
||||||
lastWasDelim = true;
|
lastWasDelim = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// No tab, normal data
|
// No tab, normal data
|
||||||
lastWasDelim = false;
|
lastWasDelim = false;
|
||||||
|
|
||||||
// Add normal TD
|
// Add normal TD
|
||||||
tableDatas.add(td);
|
tableDatas.add(td);
|
||||||
}
|
}
|
||||||
} // end while (tableRow.hasNext())
|
} // end while (tableRow.hasNext())
|
||||||
|
|
||||||
// Store max TD count
|
// Store max TD count
|
||||||
if (tableDatas.size() > tdsPerTR) {
|
if (tableDatas.size() > tdsPerTR) {
|
||||||
tdsPerTR = tableDatas.size();
|
tdsPerTR = tableDatas.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a table row
|
// Add a table row
|
||||||
tableRows.add(tableDatas);
|
tableRows.add(tableDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return TABLE
|
// Return TABLE
|
||||||
return new Table(tableRows, tdsPerTR);
|
return new Table(tableRows, tdsPerTR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+290
-290
@@ -1,290 +1,290 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: ExBodyTagSupport.java,v $
|
* $Log: ExBodyTagSupport.java,v $
|
||||||
* Revision 1.3 2003/10/06 14:24:57 WMHAKUR
|
* Revision 1.3 2003/10/06 14:24:57 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/11/18 22:10:27 WMHAKUR
|
* Revision 1.2 2002/11/18 22:10:27 WMHAKUR
|
||||||
* *** empty log message ***
|
* *** empty log message ***
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import javax.servlet.jsp.JspWriter;
|
import javax.servlet.jsp.JspWriter;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import javax.servlet.jsp.tagext.BodyTagSupport;
|
import javax.servlet.jsp.tagext.BodyTagSupport;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the class that should be extended by all jsp pages that do use their
|
* This is the class that should be extended by all jsp pages that do use their
|
||||||
* body. It contains a lot of helper methods for simplifying common tasks.
|
* body. It contains a lot of helper methods for simplifying common tasks.
|
||||||
*
|
*
|
||||||
* @author Thomas Purcell (CSC Australia)
|
* @author Thomas Purcell (CSC Australia)
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
*
|
*
|
||||||
* @version $Id: jsp/taglib/ExBodyTagSupport.java#1 $
|
* @version $Id: jsp/taglib/ExBodyTagSupport.java#1 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ExBodyTagSupport extends BodyTagSupport implements ExTag {
|
public class ExBodyTagSupport extends BodyTagSupport implements ExTag {
|
||||||
/**
|
/**
|
||||||
* writeHtml ensures that the text being outputted appears as it was
|
* writeHtml ensures that the text being outputted appears as it was
|
||||||
* entered. This prevents users from hacking the system by entering
|
* entered. This prevents users from hacking the system by entering
|
||||||
* html or jsp code into an entry form where that value will be displayed
|
* html or jsp code into an entry form where that value will be displayed
|
||||||
* later in the site.
|
* later in the site.
|
||||||
*
|
*
|
||||||
* @param pOut The JspWriter to write the output to.
|
* @param pOut The JspWriter to write the output to.
|
||||||
* @param pHtml The original html to filter and output to the user.
|
* @param pHtml The original html to filter and output to the user.
|
||||||
* @throws IOException If the user clicks Stop in the browser, or their
|
* @throws IOException If the user clicks Stop in the browser, or their
|
||||||
* browser crashes, then the JspWriter will throw an IOException when
|
* browser crashes, then the JspWriter will throw an IOException when
|
||||||
* the jsp tries to write to it.
|
* the jsp tries to write to it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void writeHtml(JspWriter pOut, String pHtml) throws IOException {
|
public void writeHtml(JspWriter pOut, String pHtml) throws IOException {
|
||||||
StringTokenizer parser = new StringTokenizer(pHtml, "<>&", true);
|
StringTokenizer parser = new StringTokenizer(pHtml, "<>&", true);
|
||||||
|
|
||||||
while (parser.hasMoreTokens()) {
|
while (parser.hasMoreTokens()) {
|
||||||
String token = parser.nextToken();
|
String token = parser.nextToken();
|
||||||
|
|
||||||
if (token.equals("<")) {
|
if (token.equals("<")) {
|
||||||
pOut.print("<");
|
pOut.print("<");
|
||||||
}
|
}
|
||||||
else if (token.equals(">")) {
|
else if (token.equals(">")) {
|
||||||
pOut.print(">");
|
pOut.print(">");
|
||||||
}
|
}
|
||||||
else if (token.equals("&")) {
|
else if (token.equals("&")) {
|
||||||
pOut.print("&");
|
pOut.print("&");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pOut.print(token);
|
pOut.print(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message to the servlet context.
|
* Log a message to the servlet context.
|
||||||
*
|
*
|
||||||
* @param pMsg The error message to log.
|
* @param pMsg The error message to log.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void log(String pMsg) {
|
public void log(String pMsg) {
|
||||||
getServletContext().log(pMsg);
|
getServletContext().log(pMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message to the servlet context and include the exception that is
|
* Log a message to the servlet context and include the exception that is
|
||||||
* passed in as the second parameter.
|
* passed in as the second parameter.
|
||||||
*
|
*
|
||||||
* @param pMsg The error message to log.
|
* @param pMsg The error message to log.
|
||||||
* @param pException The exception that caused this error message to be
|
* @param pException The exception that caused this error message to be
|
||||||
* logged.
|
* logged.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void log(String pMsg, Throwable pException) {
|
public void log(String pMsg, Throwable pException) {
|
||||||
getServletContext().log(pMsg, pException);
|
getServletContext().log(pMsg, pException);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the ServletContext object associated with the current
|
* Retrieves the ServletContext object associated with the current
|
||||||
* PageContext object.
|
* PageContext object.
|
||||||
*
|
*
|
||||||
* @return The ServletContext object associated with the current
|
* @return The ServletContext object associated with the current
|
||||||
* PageContext object.
|
* PageContext object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public ServletContext getServletContext() {
|
public ServletContext getServletContext() {
|
||||||
return pageContext.getServletContext();
|
return pageContext.getServletContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the tag has finished running. Any clean up that needs
|
* Called when the tag has finished running. Any clean up that needs
|
||||||
* to be done between calls to this tag but within the same JSP page is
|
* to be done between calls to this tag but within the same JSP page is
|
||||||
* called in the {@code clearServiceState()} method call.
|
* called in the {@code clearServiceState()} method call.
|
||||||
*
|
*
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
clearServiceState();
|
clearServiceState();
|
||||||
return super.doEndTag();
|
return super.doEndTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a tag's role in the current JSP page is finished. After
|
* Called when a tag's role in the current JSP page is finished. After
|
||||||
* the {@code clearProperties()} method is called, the custom tag
|
* the {@code clearProperties()} method is called, the custom tag
|
||||||
* should be in an identical state as when it was first created. The
|
* should be in an identical state as when it was first created. The
|
||||||
* {@code clearServiceState()} method is called here just in case an
|
* {@code clearServiceState()} method is called here just in case an
|
||||||
* exception was thrown in the custom tag. If an exception was thrown,
|
* exception was thrown in the custom tag. If an exception was thrown,
|
||||||
* then the {@code doEndTag()} method will not have been called and
|
* then the {@code doEndTag()} method will not have been called and
|
||||||
* the tag might not have been cleaned up properly.
|
* the tag might not have been cleaned up properly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
clearServiceState();
|
clearServiceState();
|
||||||
|
|
||||||
clearProperties();
|
clearProperties();
|
||||||
super.release();
|
super.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation for the {@code clearProperties()}. Not
|
* The default implementation for the {@code clearProperties()}. Not
|
||||||
* all tags will need to overload this method call. By implementing it
|
* all tags will need to overload this method call. By implementing it
|
||||||
* here, all classes that extend this object are able to call {@code
|
* here, all classes that extend this object are able to call {@code
|
||||||
* super.clearProperties()}. So, if the class extends a different
|
* super.clearProperties()}. So, if the class extends a different
|
||||||
* tag, or this one, the parent method should always be called. This
|
* tag, or this one, the parent method should always be called. This
|
||||||
* method will be called when the tag is to be released. That is, the
|
* method will be called when the tag is to be released. That is, the
|
||||||
* tag has finished for the current page and should be returned to it's
|
* tag has finished for the current page and should be returned to it's
|
||||||
* initial state.
|
* initial state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected void clearProperties() {
|
protected void clearProperties() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation for the {@code clearServiceState()}.
|
* The default implementation for the {@code clearServiceState()}.
|
||||||
* Not all tags will need to overload this method call. By implementing it
|
* Not all tags will need to overload this method call. By implementing it
|
||||||
* here, all classes that extend this object are able to call {@code
|
* here, all classes that extend this object are able to call {@code
|
||||||
* super.clearServiceState()}. So, if the class extends a different
|
* super.clearServiceState()}. So, if the class extends a different
|
||||||
* tag, or this one, the parent method should always be called. This
|
* tag, or this one, the parent method should always be called. This
|
||||||
* method will be called when the tag has finished it's current tag
|
* method will be called when the tag has finished it's current tag
|
||||||
* within the page, but may be called upon again in this same JSP page.
|
* within the page, but may be called upon again in this same JSP page.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected void clearServiceState() {
|
protected void clearServiceState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initialisation parameter from the {@code
|
* Returns the initialisation parameter from the {@code
|
||||||
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
||||||
* parameters are defined in the {@code web.xml} configuration file.
|
* parameters are defined in the {@code web.xml} configuration file.
|
||||||
*
|
*
|
||||||
* @param pName The name of the initialisation parameter to return the
|
* @param pName The name of the initialisation parameter to return the
|
||||||
* value for.
|
* value for.
|
||||||
* @return The value for the parameter whose name was passed in as a
|
* @return The value for the parameter whose name was passed in as a
|
||||||
* parameter. If the parameter does not exist, then {@code null}
|
* parameter. If the parameter does not exist, then {@code null}
|
||||||
* will be returned.
|
* will be returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getInitParameter(String pName) {
|
public String getInitParameter(String pName) {
|
||||||
return getInitParameter(pName, PageContext.APPLICATION_SCOPE);
|
return getInitParameter(pName, PageContext.APPLICATION_SCOPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an Enumeration containing all the names for all the
|
* Returns an Enumeration containing all the names for all the
|
||||||
* initialisation parametes defined in the {@code
|
* initialisation parametes defined in the {@code
|
||||||
* PageContext.APPLICATION_SCOPE} scope.
|
* PageContext.APPLICATION_SCOPE} scope.
|
||||||
*
|
*
|
||||||
* @return An {@code Enumeration} containing all the names for all the
|
* @return An {@code Enumeration} containing all the names for all the
|
||||||
* initialisation parameters.
|
* initialisation parameters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Enumeration getInitParameterNames() {
|
public Enumeration getInitParameterNames() {
|
||||||
return getInitParameterNames(PageContext.APPLICATION_SCOPE);
|
return getInitParameterNames(PageContext.APPLICATION_SCOPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initialisation parameter from the scope specified with the
|
* Returns the initialisation parameter from the scope specified with the
|
||||||
* name specified.
|
* name specified.
|
||||||
*
|
*
|
||||||
* @param pName The name of the initialisation parameter to return the
|
* @param pName The name of the initialisation parameter to return the
|
||||||
* value for.
|
* value for.
|
||||||
* @param pScope The scope to search for the initialisation parameter
|
* @param pScope The scope to search for the initialisation parameter
|
||||||
* within.
|
* within.
|
||||||
* @return The value of the parameter found. If no parameter with the
|
* @return The value of the parameter found. If no parameter with the
|
||||||
* name specified is found in the scope specified, then {@code null
|
* name specified is found in the scope specified, then {@code null
|
||||||
* } is returned.
|
* } is returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getInitParameter(String pName, int pScope) {
|
public String getInitParameter(String pName, int pScope) {
|
||||||
switch (pScope) {
|
switch (pScope) {
|
||||||
case PageContext.PAGE_SCOPE:
|
case PageContext.PAGE_SCOPE:
|
||||||
return getServletConfig().getInitParameter(pName);
|
return getServletConfig().getInitParameter(pName);
|
||||||
case PageContext.APPLICATION_SCOPE:
|
case PageContext.APPLICATION_SCOPE:
|
||||||
return getServletContext().getInitParameter(pName);
|
return getServletContext().getInitParameter(pName);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Illegal scope.");
|
throw new IllegalArgumentException("Illegal scope.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an enumeration containing all the parameters defined in the
|
* Returns an enumeration containing all the parameters defined in the
|
||||||
* scope specified by the parameter.
|
* scope specified by the parameter.
|
||||||
*
|
*
|
||||||
* @param pScope The scope to return the names of all the parameters
|
* @param pScope The scope to return the names of all the parameters
|
||||||
* defined within.
|
* defined within.
|
||||||
* @return An {@code Enumeration} containing all the names for all the
|
* @return An {@code Enumeration} containing all the names for all the
|
||||||
* parameters defined in the scope passed in as a parameter.
|
* parameters defined in the scope passed in as a parameter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Enumeration getInitParameterNames(int pScope) {
|
public Enumeration getInitParameterNames(int pScope) {
|
||||||
switch (pScope) {
|
switch (pScope) {
|
||||||
case PageContext.PAGE_SCOPE:
|
case PageContext.PAGE_SCOPE:
|
||||||
return getServletConfig().getInitParameterNames();
|
return getServletConfig().getInitParameterNames();
|
||||||
case PageContext.APPLICATION_SCOPE:
|
case PageContext.APPLICATION_SCOPE:
|
||||||
return getServletContext().getInitParameterNames();
|
return getServletContext().getInitParameterNames();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Illegal scope");
|
throw new IllegalArgumentException("Illegal scope");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the servlet config associated with the current JSP page request.
|
* Returns the servlet config associated with the current JSP page request.
|
||||||
*
|
*
|
||||||
* @return The {@code ServletConfig} associated with the current
|
* @return The {@code ServletConfig} associated with the current
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public ServletConfig getServletConfig() {
|
public ServletConfig getServletConfig() {
|
||||||
return pageContext.getServletConfig();
|
return pageContext.getServletConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the context path associated with the current JSP page request.
|
* Gets the context path associated with the current JSP page request.
|
||||||
* If the request is not a HttpServletRequest, this method will
|
* If the request is not a HttpServletRequest, this method will
|
||||||
* return "/".
|
* return "/".
|
||||||
*
|
*
|
||||||
* @return a path relative to the current context's root, or
|
* @return a path relative to the current context's root, or
|
||||||
* {@code "/"} if this is not a HTTP request.
|
* {@code "/"} if this is not a HTTP request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getContextPath() {
|
public String getContextPath() {
|
||||||
ServletRequest request = pageContext.getRequest();
|
ServletRequest request = pageContext.getRequest();
|
||||||
if (request instanceof HttpServletRequest) {
|
if (request instanceof HttpServletRequest) {
|
||||||
return ((HttpServletRequest) request).getContextPath();
|
return ((HttpServletRequest) request).getContextPath();
|
||||||
}
|
}
|
||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the resource associated with the given relative path for the
|
* Gets the resource associated with the given relative path for the
|
||||||
* current JSP page request.
|
* current JSP page request.
|
||||||
* The path may be absolute, or relative to the current context root.
|
* The path may be absolute, or relative to the current context root.
|
||||||
*
|
*
|
||||||
* @param pPath the path
|
* @param pPath the path
|
||||||
*
|
*
|
||||||
* @return a path relative to the current context root
|
* @return a path relative to the current context root
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public InputStream getResourceAsStream(String pPath) {
|
public InputStream getResourceAsStream(String pPath) {
|
||||||
// throws MalformedURLException {
|
// throws MalformedURLException {
|
||||||
String path = pPath;
|
String path = pPath;
|
||||||
|
|
||||||
if (pPath != null && !pPath.startsWith("/")) {
|
if (pPath != null && !pPath.startsWith("/")) {
|
||||||
path = getContextPath() + pPath;
|
path = getContextPath() + pPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pageContext.getServletContext().getResourceAsStream(path);
|
return pageContext.getServletContext().getResourceAsStream(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+163
-163
@@ -1,163 +1,163 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: ExTag.java,v $
|
* $Log: ExTag.java,v $
|
||||||
* Revision 1.2 2003/10/06 14:25:05 WMHAKUR
|
* Revision 1.2 2003/10/06 14:25:05 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/11/18 22:10:27 WMHAKUR
|
* Revision 1.1 2002/11/18 22:10:27 WMHAKUR
|
||||||
* *** empty log message ***
|
* *** empty log message ***
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.jsp.JspWriter;
|
import javax.servlet.jsp.JspWriter;
|
||||||
import javax.servlet.jsp.tagext.Tag;
|
import javax.servlet.jsp.tagext.Tag;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface contains a lot of helper methods for simplifying common
|
* This interface contains a lot of helper methods for simplifying common
|
||||||
* taglib related tasks.
|
* taglib related tasks.
|
||||||
*
|
*
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
*
|
*
|
||||||
* @version $Id: jsp/taglib/ExTag.java#1 $
|
* @version $Id: jsp/taglib/ExTag.java#1 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public interface ExTag extends Tag {
|
public interface ExTag extends Tag {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* writeHtml ensures that the text being outputted appears as it was
|
* writeHtml ensures that the text being outputted appears as it was
|
||||||
* entered. This prevents users from hacking the system by entering
|
* entered. This prevents users from hacking the system by entering
|
||||||
* html or jsp code into an entry form where that value will be displayed
|
* html or jsp code into an entry form where that value will be displayed
|
||||||
* later in the site.
|
* later in the site.
|
||||||
*
|
*
|
||||||
* @param pOut The JspWriter to write the output to.
|
* @param pOut The JspWriter to write the output to.
|
||||||
* @param pHtml The original html to filter and output to the user.
|
* @param pHtml The original html to filter and output to the user.
|
||||||
* @throws IOException If the user clicks Stop in the browser, or their
|
* @throws IOException If the user clicks Stop in the browser, or their
|
||||||
* browser crashes, then the JspWriter will throw an IOException when
|
* browser crashes, then the JspWriter will throw an IOException when
|
||||||
* the jsp tries to write to it.
|
* the jsp tries to write to it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void writeHtml(JspWriter pOut, String pHtml) throws IOException;
|
public void writeHtml(JspWriter pOut, String pHtml) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message to the servlet context.
|
* Log a message to the servlet context.
|
||||||
*
|
*
|
||||||
* @param pMsg The error message to log.
|
* @param pMsg The error message to log.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void log(String pMsg);
|
public void log(String pMsg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs a message to the servlet context and include the exception that is
|
* Logs a message to the servlet context and include the exception that is
|
||||||
* passed in as the second parameter.
|
* passed in as the second parameter.
|
||||||
*
|
*
|
||||||
* @param pMsg The error message to log.
|
* @param pMsg The error message to log.
|
||||||
* @param pException The exception that caused this error message to be
|
* @param pException The exception that caused this error message to be
|
||||||
* logged.
|
* logged.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void log(String pMsg, Throwable pException);
|
public void log(String pMsg, Throwable pException);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the ServletContext object associated with the current
|
* Retrieves the ServletContext object associated with the current
|
||||||
* PageContext object.
|
* PageContext object.
|
||||||
*
|
*
|
||||||
* @return The ServletContext object associated with the current
|
* @return The ServletContext object associated with the current
|
||||||
* PageContext object.
|
* PageContext object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public ServletContext getServletContext();
|
public ServletContext getServletContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initialisation parameter from the {@code
|
* Returns the initialisation parameter from the {@code
|
||||||
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
||||||
* parameters are defined in the {@code web.xml} configuration file.
|
* parameters are defined in the {@code web.xml} configuration file.
|
||||||
*
|
*
|
||||||
* @param pName The name of the initialisation parameter to return the
|
* @param pName The name of the initialisation parameter to return the
|
||||||
* value for.
|
* value for.
|
||||||
* @return The value for the parameter whose name was passed in as a
|
* @return The value for the parameter whose name was passed in as a
|
||||||
* parameter. If the parameter does not exist, then {@code null}
|
* parameter. If the parameter does not exist, then {@code null}
|
||||||
* will be returned.
|
* will be returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getInitParameter(String pName);
|
public String getInitParameter(String pName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an Enumeration containing all the names for all the
|
* Returns an Enumeration containing all the names for all the
|
||||||
* initialisation parametes defined in the {@code
|
* initialisation parametes defined in the {@code
|
||||||
* PageContext.APPLICATION_SCOPE} scope.
|
* PageContext.APPLICATION_SCOPE} scope.
|
||||||
*
|
*
|
||||||
* @return An {@code Enumeration} containing all the names for all the
|
* @return An {@code Enumeration} containing all the names for all the
|
||||||
* initialisation parameters.
|
* initialisation parameters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Enumeration getInitParameterNames();
|
public Enumeration getInitParameterNames();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initialisation parameter from the scope specified with the
|
* Returns the initialisation parameter from the scope specified with the
|
||||||
* name specified.
|
* name specified.
|
||||||
*
|
*
|
||||||
* @param pName The name of the initialisation parameter to return the
|
* @param pName The name of the initialisation parameter to return the
|
||||||
* value for.
|
* value for.
|
||||||
* @param pScope The scope to search for the initialisation parameter
|
* @param pScope The scope to search for the initialisation parameter
|
||||||
* within.
|
* within.
|
||||||
* @return The value of the parameter found. If no parameter with the
|
* @return The value of the parameter found. If no parameter with the
|
||||||
* name specified is found in the scope specified, then {@code null
|
* name specified is found in the scope specified, then {@code null
|
||||||
* } is returned.
|
* } is returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getInitParameter(String pName, int pScope);
|
public String getInitParameter(String pName, int pScope);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an enumeration containing all the parameters defined in the
|
* Returns an enumeration containing all the parameters defined in the
|
||||||
* scope specified by the parameter.
|
* scope specified by the parameter.
|
||||||
*
|
*
|
||||||
* @param pScope The scope to return the names of all the parameters
|
* @param pScope The scope to return the names of all the parameters
|
||||||
* defined within.
|
* defined within.
|
||||||
* @return An {@code Enumeration} containing all the names for all the
|
* @return An {@code Enumeration} containing all the names for all the
|
||||||
* parameters defined in the scope passed in as a parameter.
|
* parameters defined in the scope passed in as a parameter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Enumeration getInitParameterNames(int pScope);
|
public Enumeration getInitParameterNames(int pScope);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the servlet config associated with the current JSP page request.
|
* Returns the servlet config associated with the current JSP page request.
|
||||||
*
|
*
|
||||||
* @return The {@code ServletConfig} associated with the current
|
* @return The {@code ServletConfig} associated with the current
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public ServletConfig getServletConfig();
|
public ServletConfig getServletConfig();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the context path associated with the current JSP page request.
|
* Gets the context path associated with the current JSP page request.
|
||||||
*
|
*
|
||||||
* @return a path relative to the current context's root.
|
* @return a path relative to the current context's root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getContextPath();
|
public String getContextPath();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the resource associated with the given relative path for the
|
* Gets the resource associated with the given relative path for the
|
||||||
* current JSP page request.
|
* current JSP page request.
|
||||||
* The path may be absolute, or relative to the current context root.
|
* The path may be absolute, or relative to the current context root.
|
||||||
*
|
*
|
||||||
* @param pPath the path
|
* @param pPath the path
|
||||||
*
|
*
|
||||||
* @return a path relative to the current context root
|
* @return a path relative to the current context root
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public InputStream getResourceAsStream(String pPath);
|
public InputStream getResourceAsStream(String pPath);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+293
-293
@@ -1,293 +1,293 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: ExTagSupport.java,v $
|
* $Log: ExTagSupport.java,v $
|
||||||
* Revision 1.3 2003/10/06 14:25:11 WMHAKUR
|
* Revision 1.3 2003/10/06 14:25:11 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.2 2002/11/18 22:10:27 WMHAKUR
|
* Revision 1.2 2002/11/18 22:10:27 WMHAKUR
|
||||||
* *** empty log message ***
|
* *** empty log message ***
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import javax.servlet.jsp.JspWriter;
|
import javax.servlet.jsp.JspWriter;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import javax.servlet.jsp.tagext.TagSupport;
|
import javax.servlet.jsp.tagext.TagSupport;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the class that should be extended by all jsp pages that don't use
|
* This is the class that should be extended by all jsp pages that don't use
|
||||||
* their body. It contains a lot of helper methods for simplifying common
|
* their body. It contains a lot of helper methods for simplifying common
|
||||||
* tasks.
|
* tasks.
|
||||||
*
|
*
|
||||||
* @author Thomas Purcell (CSC Australia)
|
* @author Thomas Purcell (CSC Australia)
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
*
|
*
|
||||||
* @version $Id: jsp/taglib/ExTagSupport.java#1 $
|
* @version $Id: jsp/taglib/ExTagSupport.java#1 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ExTagSupport extends TagSupport implements ExTag {
|
public class ExTagSupport extends TagSupport implements ExTag {
|
||||||
/**
|
/**
|
||||||
* writeHtml ensures that the text being outputted appears as it was
|
* writeHtml ensures that the text being outputted appears as it was
|
||||||
* entered. This prevents users from hacking the system by entering
|
* entered. This prevents users from hacking the system by entering
|
||||||
* html or jsp code into an entry form where that value will be displayed
|
* html or jsp code into an entry form where that value will be displayed
|
||||||
* later in the site.
|
* later in the site.
|
||||||
*
|
*
|
||||||
* @param pOut The JspWriter to write the output to.
|
* @param pOut The JspWriter to write the output to.
|
||||||
* @param pHtml The original html to filter and output to the user.
|
* @param pHtml The original html to filter and output to the user.
|
||||||
* @throws IOException If the user clicks Stop in the browser, or their
|
* @throws IOException If the user clicks Stop in the browser, or their
|
||||||
* browser crashes, then the JspWriter will throw an IOException when
|
* browser crashes, then the JspWriter will throw an IOException when
|
||||||
* the jsp tries to write to it.
|
* the jsp tries to write to it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void writeHtml(JspWriter pOut, String pHtml) throws IOException {
|
public void writeHtml(JspWriter pOut, String pHtml) throws IOException {
|
||||||
StringTokenizer parser = new StringTokenizer(pHtml, "<>&", true);
|
StringTokenizer parser = new StringTokenizer(pHtml, "<>&", true);
|
||||||
|
|
||||||
while (parser.hasMoreTokens()) {
|
while (parser.hasMoreTokens()) {
|
||||||
String token = parser.nextToken();
|
String token = parser.nextToken();
|
||||||
|
|
||||||
if (token.equals("<")) {
|
if (token.equals("<")) {
|
||||||
pOut.print("<");
|
pOut.print("<");
|
||||||
}
|
}
|
||||||
else if (token.equals(">")) {
|
else if (token.equals(">")) {
|
||||||
pOut.print(">");
|
pOut.print(">");
|
||||||
}
|
}
|
||||||
else if (token.equals("&")) {
|
else if (token.equals("&")) {
|
||||||
pOut.print("&");
|
pOut.print("&");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pOut.print(token);
|
pOut.print(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message to the servlet context.
|
* Log a message to the servlet context.
|
||||||
*
|
*
|
||||||
* @param pMsg The error message to log.
|
* @param pMsg The error message to log.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void log(String pMsg) {
|
public void log(String pMsg) {
|
||||||
getServletContext().log(pMsg);
|
getServletContext().log(pMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message to the servlet context and include the exception that is
|
* Log a message to the servlet context and include the exception that is
|
||||||
* passed in as the second parameter.
|
* passed in as the second parameter.
|
||||||
*
|
*
|
||||||
* @param pMsg The error message to log.
|
* @param pMsg The error message to log.
|
||||||
* @param pException The exception that caused this error message to be
|
* @param pException The exception that caused this error message to be
|
||||||
* logged.
|
* logged.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void log(String pMsg, Throwable pException) {
|
public void log(String pMsg, Throwable pException) {
|
||||||
getServletContext().log(pMsg, pException);
|
getServletContext().log(pMsg, pException);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the ServletContext object associated with the current
|
* Retrieves the ServletContext object associated with the current
|
||||||
* PageContext object.
|
* PageContext object.
|
||||||
*
|
*
|
||||||
* @return The ServletContext object associated with the current
|
* @return The ServletContext object associated with the current
|
||||||
* PageContext object.
|
* PageContext object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public ServletContext getServletContext() {
|
public ServletContext getServletContext() {
|
||||||
return pageContext.getServletContext();
|
return pageContext.getServletContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the tag has finished running. Any clean up that needs
|
* Called when the tag has finished running. Any clean up that needs
|
||||||
* to be done between calls to this tag but within the same JSP page is
|
* to be done between calls to this tag but within the same JSP page is
|
||||||
* called in the {@code clearServiceState()} method call.
|
* called in the {@code clearServiceState()} method call.
|
||||||
*
|
*
|
||||||
* @exception JspException
|
* @exception JspException
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
clearServiceState();
|
clearServiceState();
|
||||||
return super.doEndTag();
|
return super.doEndTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a tag's role in the current JSP page is finished. After
|
* Called when a tag's role in the current JSP page is finished. After
|
||||||
* the {@code clearProperties()} method is called, the custom tag
|
* the {@code clearProperties()} method is called, the custom tag
|
||||||
* should be in an identical state as when it was first created. The
|
* should be in an identical state as when it was first created. The
|
||||||
* {@code clearServiceState()} method is called here just in case an
|
* {@code clearServiceState()} method is called here just in case an
|
||||||
* exception was thrown in the custom tag. If an exception was thrown,
|
* exception was thrown in the custom tag. If an exception was thrown,
|
||||||
* then the {@code doEndTag()} method will not have been called and
|
* then the {@code doEndTag()} method will not have been called and
|
||||||
* the tag might not have been cleaned up properly.
|
* the tag might not have been cleaned up properly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
clearServiceState();
|
clearServiceState();
|
||||||
|
|
||||||
clearProperties();
|
clearProperties();
|
||||||
super.release();
|
super.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation for the {@code clearProperties()}. Not
|
* The default implementation for the {@code clearProperties()}. Not
|
||||||
* all tags will need to overload this method call. By implementing it
|
* all tags will need to overload this method call. By implementing it
|
||||||
* here, all classes that extend this object are able to call {@code
|
* here, all classes that extend this object are able to call {@code
|
||||||
* super.clearProperties()}. So, if the class extends a different
|
* super.clearProperties()}. So, if the class extends a different
|
||||||
* tag, or this one, the parent method should always be called. This
|
* tag, or this one, the parent method should always be called. This
|
||||||
* method will be called when the tag is to be released. That is, the
|
* method will be called when the tag is to be released. That is, the
|
||||||
* tag has finished for the current page and should be returned to it's
|
* tag has finished for the current page and should be returned to it's
|
||||||
* initial state.
|
* initial state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected void clearProperties() {
|
protected void clearProperties() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation for the {@code clearServiceState()}.
|
* The default implementation for the {@code clearServiceState()}.
|
||||||
* Not all tags will need to overload this method call. By implementing it
|
* Not all tags will need to overload this method call. By implementing it
|
||||||
* here, all classes that extend this object are able to call {@code
|
* here, all classes that extend this object are able to call {@code
|
||||||
* super.clearServiceState()}. So, if the class extends a different
|
* super.clearServiceState()}. So, if the class extends a different
|
||||||
* tag, or this one, the parent method should always be called. This
|
* tag, or this one, the parent method should always be called. This
|
||||||
* method will be called when the tag has finished it's current tag
|
* method will be called when the tag has finished it's current tag
|
||||||
* within the page, but may be called upon again in this same JSP page.
|
* within the page, but may be called upon again in this same JSP page.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected void clearServiceState() {
|
protected void clearServiceState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initialisation parameter from the {@code
|
* Returns the initialisation parameter from the {@code
|
||||||
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
||||||
* parameters are defined in the {@code web.xml} configuration file.
|
* parameters are defined in the {@code web.xml} configuration file.
|
||||||
*
|
*
|
||||||
* @param pName The name of the initialisation parameter to return the
|
* @param pName The name of the initialisation parameter to return the
|
||||||
* value for.
|
* value for.
|
||||||
* @return The value for the parameter whose name was passed in as a
|
* @return The value for the parameter whose name was passed in as a
|
||||||
* parameter. If the parameter does not exist, then {@code null}
|
* parameter. If the parameter does not exist, then {@code null}
|
||||||
* will be returned.
|
* will be returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getInitParameter(String pName) {
|
public String getInitParameter(String pName) {
|
||||||
return getInitParameter(pName, PageContext.APPLICATION_SCOPE);
|
return getInitParameter(pName, PageContext.APPLICATION_SCOPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an Enumeration containing all the names for all the
|
* Returns an Enumeration containing all the names for all the
|
||||||
* initialisation parametes defined in the {@code
|
* initialisation parametes defined in the {@code
|
||||||
* PageContext.APPLICATION_SCOPE} scope.
|
* PageContext.APPLICATION_SCOPE} scope.
|
||||||
*
|
*
|
||||||
* @return An {@code Enumeration} containing all the names for all the
|
* @return An {@code Enumeration} containing all the names for all the
|
||||||
* initialisation parameters.
|
* initialisation parameters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Enumeration getInitParameterNames() {
|
public Enumeration getInitParameterNames() {
|
||||||
return getInitParameterNames(PageContext.APPLICATION_SCOPE);
|
return getInitParameterNames(PageContext.APPLICATION_SCOPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initialisation parameter from the scope specified with the
|
* Returns the initialisation parameter from the scope specified with the
|
||||||
* name specified.
|
* name specified.
|
||||||
*
|
*
|
||||||
* @param pName The name of the initialisation parameter to return the
|
* @param pName The name of the initialisation parameter to return the
|
||||||
* value for.
|
* value for.
|
||||||
* @param pScope The scope to search for the initialisation parameter
|
* @param pScope The scope to search for the initialisation parameter
|
||||||
* within.
|
* within.
|
||||||
* @return The value of the parameter found. If no parameter with the
|
* @return The value of the parameter found. If no parameter with the
|
||||||
* name specified is found in the scope specified, then {@code null
|
* name specified is found in the scope specified, then {@code null
|
||||||
* } is returned.
|
* } is returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getInitParameter(String pName, int pScope) {
|
public String getInitParameter(String pName, int pScope) {
|
||||||
switch (pScope) {
|
switch (pScope) {
|
||||||
case PageContext.PAGE_SCOPE:
|
case PageContext.PAGE_SCOPE:
|
||||||
return getServletConfig().getInitParameter(pName);
|
return getServletConfig().getInitParameter(pName);
|
||||||
case PageContext.APPLICATION_SCOPE:
|
case PageContext.APPLICATION_SCOPE:
|
||||||
return getServletContext().getInitParameter(pName);
|
return getServletContext().getInitParameter(pName);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Illegal scope.");
|
throw new IllegalArgumentException("Illegal scope.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an enumeration containing all the parameters defined in the
|
* Returns an enumeration containing all the parameters defined in the
|
||||||
* scope specified by the parameter.
|
* scope specified by the parameter.
|
||||||
*
|
*
|
||||||
* @param pScope The scope to return the names of all the parameters
|
* @param pScope The scope to return the names of all the parameters
|
||||||
* defined within.
|
* defined within.
|
||||||
* @return An {@code Enumeration} containing all the names for all the
|
* @return An {@code Enumeration} containing all the names for all the
|
||||||
* parameters defined in the scope passed in as a parameter.
|
* parameters defined in the scope passed in as a parameter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Enumeration getInitParameterNames(int pScope) {
|
public Enumeration getInitParameterNames(int pScope) {
|
||||||
switch (pScope) {
|
switch (pScope) {
|
||||||
case PageContext.PAGE_SCOPE:
|
case PageContext.PAGE_SCOPE:
|
||||||
return getServletConfig().getInitParameterNames();
|
return getServletConfig().getInitParameterNames();
|
||||||
case PageContext.APPLICATION_SCOPE:
|
case PageContext.APPLICATION_SCOPE:
|
||||||
return getServletContext().getInitParameterNames();
|
return getServletContext().getInitParameterNames();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Illegal scope");
|
throw new IllegalArgumentException("Illegal scope");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the servlet config associated with the current JSP page request.
|
* Returns the servlet config associated with the current JSP page request.
|
||||||
*
|
*
|
||||||
* @return The {@code ServletConfig} associated with the current
|
* @return The {@code ServletConfig} associated with the current
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public ServletConfig getServletConfig() {
|
public ServletConfig getServletConfig() {
|
||||||
return pageContext.getServletConfig();
|
return pageContext.getServletConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the context path associated with the current JSP page request.
|
* Gets the context path associated with the current JSP page request.
|
||||||
* If the request is not a HttpServletRequest, this method will
|
* If the request is not a HttpServletRequest, this method will
|
||||||
* return "/".
|
* return "/".
|
||||||
*
|
*
|
||||||
* @return a path relative to the current context's root, or
|
* @return a path relative to the current context's root, or
|
||||||
* {@code "/"} if this is not a HTTP request.
|
* {@code "/"} if this is not a HTTP request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getContextPath() {
|
public String getContextPath() {
|
||||||
ServletRequest request = pageContext.getRequest();
|
ServletRequest request = pageContext.getRequest();
|
||||||
if (request instanceof HttpServletRequest) {
|
if (request instanceof HttpServletRequest) {
|
||||||
return ((HttpServletRequest) request).getContextPath();
|
return ((HttpServletRequest) request).getContextPath();
|
||||||
}
|
}
|
||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the resource associated with the given relative path for the
|
* Gets the resource associated with the given relative path for the
|
||||||
* current JSP page request.
|
* current JSP page request.
|
||||||
* The path may be absolute, or relative to the current context root.
|
* The path may be absolute, or relative to the current context root.
|
||||||
*
|
*
|
||||||
* @param pPath the path
|
* @param pPath the path
|
||||||
*
|
*
|
||||||
* @return a path relative to the current context root
|
* @return a path relative to the current context root
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public InputStream getResourceAsStream(String pPath) {
|
public InputStream getResourceAsStream(String pPath) {
|
||||||
//throws MalformedURLException {
|
//throws MalformedURLException {
|
||||||
String path = pPath;
|
String path = pPath;
|
||||||
|
|
||||||
if (pPath != null && !pPath.startsWith("/")) {
|
if (pPath != null && !pPath.startsWith("/")) {
|
||||||
path = getContextPath() + pPath;
|
path = getContextPath() + pPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pageContext.getServletContext().getResourceAsStream(path);
|
return pageContext.getServletContext().getResourceAsStream(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-20
@@ -1,20 +1,20 @@
|
|||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
import javax.servlet.jsp.*;
|
import javax.servlet.jsp.*;
|
||||||
import javax.servlet.jsp.tagext.*;
|
import javax.servlet.jsp.tagext.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TagExtraInfo for LastModifiedTag
|
* TagExtraInfo for LastModifiedTag
|
||||||
*
|
*
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
*
|
*
|
||||||
* @version 1.1
|
* @version 1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class LastModifiedTEI extends TagExtraInfo {
|
public class LastModifiedTEI extends TagExtraInfo {
|
||||||
public VariableInfo[] getVariableInfo(TagData pData) {
|
public VariableInfo[] getVariableInfo(TagData pData) {
|
||||||
return new VariableInfo[]{
|
return new VariableInfo[]{
|
||||||
new VariableInfo("lastModified", "java.lang.String", true, VariableInfo.NESTED),
|
new VariableInfo("lastModified", "java.lang.String", true, VariableInfo.NESTED),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+87
-87
@@ -1,87 +1,87 @@
|
|||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This tag truncates all consecutive whitespace in sequence inside its body,
|
* This tag truncates all consecutive whitespace in sequence inside its body,
|
||||||
* to one whitespace character. The first whitespace character in the sequence
|
* to one whitespace character. The first whitespace character in the sequence
|
||||||
* will be left untouched (except for CR/LF, which will always leave a LF).
|
* will be left untouched (except for CR/LF, which will always leave a LF).
|
||||||
*
|
*
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
*
|
*
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class TrimWhiteSpaceTag extends ExBodyTagSupport {
|
public class TrimWhiteSpaceTag extends ExBodyTagSupport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doStartTag implementation, simply returns
|
* doStartTag implementation, simply returns
|
||||||
* {@code BodyTag.EVAL_BODY_BUFFERED}.
|
* {@code BodyTag.EVAL_BODY_BUFFERED}.
|
||||||
*
|
*
|
||||||
* @return {@code BodyTag.EVAL_BODY_BUFFERED}
|
* @return {@code BodyTag.EVAL_BODY_BUFFERED}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int doStartTag() throws JspException {
|
public int doStartTag() throws JspException {
|
||||||
return EVAL_BODY_BUFFERED;
|
return EVAL_BODY_BUFFERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doEndTag implementation, truncates all whitespace.
|
* doEndTag implementation, truncates all whitespace.
|
||||||
*
|
*
|
||||||
* @return {@code super.doEndTag()}
|
* @return {@code super.doEndTag()}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
// Trim
|
// Trim
|
||||||
String trimmed = truncateWS(bodyContent.getString());
|
String trimmed = truncateWS(bodyContent.getString());
|
||||||
try {
|
try {
|
||||||
// Print trimmed content
|
// Print trimmed content
|
||||||
//pageContext.getOut().print("<!--TWS-->\n");
|
//pageContext.getOut().print("<!--TWS-->\n");
|
||||||
pageContext.getOut().print(trimmed);
|
pageContext.getOut().print(trimmed);
|
||||||
//pageContext.getOut().print("\n<!--/TWS-->");
|
//pageContext.getOut().print("\n<!--/TWS-->");
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
throw new JspException(ioe);
|
throw new JspException(ioe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.doEndTag();
|
return super.doEndTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Truncates whitespace from the given string.
|
* Truncates whitespace from the given string.
|
||||||
*
|
*
|
||||||
* @todo Candidate for StringUtil?
|
* @todo Candidate for StringUtil?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private static String truncateWS(String pStr) {
|
private static String truncateWS(String pStr) {
|
||||||
char[] chars = pStr.toCharArray();
|
char[] chars = pStr.toCharArray();
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
boolean lastWasWS = true; // Avoids leading WS
|
boolean lastWasWS = true; // Avoids leading WS
|
||||||
for (int i = 0; i < chars.length; i++) {
|
for (int i = 0; i < chars.length; i++) {
|
||||||
if (!Character.isWhitespace(chars[i])) {
|
if (!Character.isWhitespace(chars[i])) {
|
||||||
// if char is not WS, just store
|
// if char is not WS, just store
|
||||||
chars[count++] = chars[i];
|
chars[count++] = chars[i];
|
||||||
lastWasWS = false;
|
lastWasWS = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// else, if char is WS, store first, skip the rest
|
// else, if char is WS, store first, skip the rest
|
||||||
if (!lastWasWS) {
|
if (!lastWasWS) {
|
||||||
if (chars[i] == 0x0d) {
|
if (chars[i] == 0x0d) {
|
||||||
chars[count++] = 0x0a; //Always new line
|
chars[count++] = 0x0a; //Always new line
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
chars[count++] = chars[i];
|
chars[count++] = chars[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastWasWS = true;
|
lastWasWS = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the trucated string
|
// Return the trucated string
|
||||||
return new String(chars, 0, count);
|
return new String(chars, 0, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+158
-158
@@ -1,158 +1,158 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002 TwelveMonkeys.
|
* Copyright (c) 2002 TwelveMonkeys.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* $Log: XMLTransformTag.java,v $
|
* $Log: XMLTransformTag.java,v $
|
||||||
* Revision 1.2 2003/10/06 14:25:43 WMHAKUR
|
* Revision 1.2 2003/10/06 14:25:43 WMHAKUR
|
||||||
* Code clean-up only.
|
* Code clean-up only.
|
||||||
*
|
*
|
||||||
* Revision 1.1 2002/11/19 10:50:41 WMHAKUR
|
* Revision 1.1 2002/11/19 10:50:41 WMHAKUR
|
||||||
* *** empty log message ***
|
* *** empty log message ***
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
|
||||||
import javax.servlet.jsp.*;
|
import javax.servlet.jsp.*;
|
||||||
import javax.xml.transform.*;
|
import javax.xml.transform.*;
|
||||||
import javax.xml.transform.stream.*;
|
import javax.xml.transform.stream.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This tag performs XSL Transformations (XSLT) on a given XML document or its
|
* This tag performs XSL Transformations (XSLT) on a given XML document or its
|
||||||
* body content.
|
* body content.
|
||||||
*
|
*
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
*
|
*
|
||||||
* @version $Id: jsp/taglib/XMLTransformTag.java#1 $
|
* @version $Id: jsp/taglib/XMLTransformTag.java#1 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class XMLTransformTag extends ExBodyTagSupport {
|
public class XMLTransformTag extends ExBodyTagSupport {
|
||||||
private String mDocumentURI = null;
|
private String mDocumentURI = null;
|
||||||
private String mStylesheetURI = null;
|
private String mStylesheetURI = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the document attribute for this tag.
|
* Sets the document attribute for this tag.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void setDocumentURI(String pDocumentURI) {
|
public void setDocumentURI(String pDocumentURI) {
|
||||||
mDocumentURI = pDocumentURI;
|
mDocumentURI = pDocumentURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the stylesheet attribute for this tag.
|
* Sets the stylesheet attribute for this tag.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void setStylesheetURI(String pStylesheetURI) {
|
public void setStylesheetURI(String pStylesheetURI) {
|
||||||
mStylesheetURI = pStylesheetURI;
|
mStylesheetURI = pStylesheetURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doStartTag implementation, that performs XML Transformation on the
|
* doStartTag implementation, that performs XML Transformation on the
|
||||||
* given document, if any.
|
* given document, if any.
|
||||||
* If the documentURI attribute is set, then the transformation is
|
* If the documentURI attribute is set, then the transformation is
|
||||||
* performed on the document at that location, and
|
* performed on the document at that location, and
|
||||||
* {@code Tag.SKIP_BODY} is returned.
|
* {@code Tag.SKIP_BODY} is returned.
|
||||||
* Otherwise, this method simply returns
|
* Otherwise, this method simply returns
|
||||||
* {@code BodyTag.EVAL_BODY_BUFFERED} and leaves the transformation to
|
* {@code BodyTag.EVAL_BODY_BUFFERED} and leaves the transformation to
|
||||||
* the doEndTag.
|
* the doEndTag.
|
||||||
*
|
*
|
||||||
* @return {@code Tag.SKIP_BODY} if {@code documentURI} is not
|
* @return {@code Tag.SKIP_BODY} if {@code documentURI} is not
|
||||||
* {@code null}, otherwise
|
* {@code null}, otherwise
|
||||||
* {@code BodyTag.EVAL_BODY_BUFFERED}.
|
* {@code BodyTag.EVAL_BODY_BUFFERED}.
|
||||||
*
|
*
|
||||||
* @todo Is it really a good idea to allow "inline" XML in a JSP?
|
* @todo Is it really a good idea to allow "inline" XML in a JSP?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int doStartTag() throws JspException {
|
public int doStartTag() throws JspException {
|
||||||
//log("XML: " + mDocumentURI + " XSL: " + mStylesheetURI);
|
//log("XML: " + mDocumentURI + " XSL: " + mStylesheetURI);
|
||||||
|
|
||||||
if (mDocumentURI != null) {
|
if (mDocumentURI != null) {
|
||||||
// If document given, transform and skip body...
|
// If document given, transform and skip body...
|
||||||
try {
|
try {
|
||||||
transform(getSource(mDocumentURI));
|
transform(getSource(mDocumentURI));
|
||||||
}
|
}
|
||||||
catch (MalformedURLException murle) {
|
catch (MalformedURLException murle) {
|
||||||
throw new JspException(murle.getMessage(), murle);
|
throw new JspException(murle.getMessage(), murle);
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
throw new JspException(ioe.getMessage(), ioe);
|
throw new JspException(ioe.getMessage(), ioe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SKIP_BODY;
|
return SKIP_BODY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...else process the body
|
// ...else process the body
|
||||||
return EVAL_BODY_BUFFERED;
|
return EVAL_BODY_BUFFERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doEndTag implementation, that will perform XML Transformation on the
|
* doEndTag implementation, that will perform XML Transformation on the
|
||||||
* body content.
|
* body content.
|
||||||
*
|
*
|
||||||
* @return super.doEndTag()
|
* @return super.doEndTag()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
// Get body content (trim is CRUCIAL, as some XML parsers are picky...)
|
// Get body content (trim is CRUCIAL, as some XML parsers are picky...)
|
||||||
String body = bodyContent.getString().trim();
|
String body = bodyContent.getString().trim();
|
||||||
|
|
||||||
// Do transformation
|
// Do transformation
|
||||||
transform(new StreamSource(new ByteArrayInputStream(body.getBytes())));
|
transform(new StreamSource(new ByteArrayInputStream(body.getBytes())));
|
||||||
|
|
||||||
return super.doEndTag();
|
return super.doEndTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the transformation and writes the result to the JSP writer.
|
* Performs the transformation and writes the result to the JSP writer.
|
||||||
*
|
*
|
||||||
* @param in the source document to transform.
|
* @param in the source document to transform.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void transform(Source pIn) throws JspException {
|
public void transform(Source pIn) throws JspException {
|
||||||
try {
|
try {
|
||||||
// Create transformer
|
// Create transformer
|
||||||
Transformer transformer = TransformerFactory.newInstance()
|
Transformer transformer = TransformerFactory.newInstance()
|
||||||
.newTransformer(getSource(mStylesheetURI));
|
.newTransformer(getSource(mStylesheetURI));
|
||||||
|
|
||||||
// Store temporary output in a bytearray, as the transformer will
|
// Store temporary output in a bytearray, as the transformer will
|
||||||
// usually try to flush the stream (illegal operation from a custom
|
// usually try to flush the stream (illegal operation from a custom
|
||||||
// tag).
|
// tag).
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
StreamResult out = new StreamResult(os);
|
StreamResult out = new StreamResult(os);
|
||||||
|
|
||||||
// Perform the transformation
|
// Perform the transformation
|
||||||
transformer.transform(pIn, out);
|
transformer.transform(pIn, out);
|
||||||
|
|
||||||
// Write the result back to the JSP writer
|
// Write the result back to the JSP writer
|
||||||
pageContext.getOut().print(os.toString());
|
pageContext.getOut().print(os.toString());
|
||||||
}
|
}
|
||||||
catch (MalformedURLException murle) {
|
catch (MalformedURLException murle) {
|
||||||
throw new JspException(murle.getMessage(), murle);
|
throw new JspException(murle.getMessage(), murle);
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
throw new JspException(ioe.getMessage(), ioe);
|
throw new JspException(ioe.getMessage(), ioe);
|
||||||
}
|
}
|
||||||
catch (TransformerException te) {
|
catch (TransformerException te) {
|
||||||
throw new JspException("XSLT Trandformation failed: " + te.getMessage(), te);
|
throw new JspException("XSLT Trandformation failed: " + te.getMessage(), te);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a StreamSource object, for the given URI
|
* Returns a StreamSource object, for the given URI
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private StreamSource getSource(String pURI)
|
private StreamSource getSource(String pURI)
|
||||||
throws IOException, MalformedURLException {
|
throws IOException, MalformedURLException {
|
||||||
if (pURI != null && pURI.indexOf("://") < 0) {
|
if (pURI != null && pURI.indexOf("://") < 0) {
|
||||||
// If local, get as stream
|
// If local, get as stream
|
||||||
return new StreamSource(getResourceAsStream(pURI));
|
return new StreamSource(getResourceAsStream(pURI));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...else, create from URI string
|
// ...else, create from URI string
|
||||||
return new StreamSource(pURI);
|
return new StreamSource(pURI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+138
-138
@@ -1,138 +1,138 @@
|
|||||||
/****************************************************
|
/****************************************************
|
||||||
* *
|
* *
|
||||||
* (c) 2000-2003 TwelveMonkeys *
|
* (c) 2000-2003 TwelveMonkeys *
|
||||||
* All rights reserved *
|
* All rights reserved *
|
||||||
* http://www.twelvemonkeys.no *
|
* http://www.twelvemonkeys.no *
|
||||||
* *
|
* *
|
||||||
* $RCSfile: ConditionalTagBase.java,v $
|
* $RCSfile: ConditionalTagBase.java,v $
|
||||||
* @version $Revision: #1 $
|
* @version $Revision: #1 $
|
||||||
* $Date: 2008/05/05 $
|
* $Date: 2008/05/05 $
|
||||||
* *
|
* *
|
||||||
* @author Last modified by: $Author: haku $
|
* @author Last modified by: $Author: haku $
|
||||||
* *
|
* *
|
||||||
****************************************************/
|
****************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Produced (p) 2002 TwelveMonkeys
|
* Produced (p) 2002 TwelveMonkeys
|
||||||
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
||||||
* Phone : +47 22 57 70 00
|
* Phone : +47 22 57 70 00
|
||||||
* Fax : +47 22 57 70 70
|
* Fax : +47 22 57 70 70
|
||||||
*/
|
*/
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||||
|
|
||||||
|
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import javax.servlet.jsp.tagext.TagSupport;
|
import javax.servlet.jsp.tagext.TagSupport;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>An abstract base class for tags with some kind of conditional presentation of the tag body.</p>
|
* <p>An abstract base class for tags with some kind of conditional presentation of the tag body.</p>
|
||||||
*
|
*
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
||||||
*/
|
*/
|
||||||
public abstract class ConditionalTagBase extends TagSupport {
|
public abstract class ConditionalTagBase extends TagSupport {
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
protected String objectName;
|
protected String objectName;
|
||||||
protected String objectValue;
|
protected String objectValue;
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method getName
|
* Method getName
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return objectName;
|
return objectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method setName
|
* Method setName
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param pObjectName
|
* @param pObjectName
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void setName(String pObjectName) {
|
public void setName(String pObjectName) {
|
||||||
this.objectName = pObjectName;
|
this.objectName = pObjectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method getValue
|
* Method getValue
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return objectValue;
|
return objectValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method setValue
|
* Method setValue
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param pObjectValue
|
* @param pObjectValue
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void setValue(String pObjectValue) {
|
public void setValue(String pObjectValue) {
|
||||||
this.objectValue = pObjectValue;
|
this.objectValue = pObjectValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Perform the test required for this particular tag, and either evaluate or skip the body of this tag.</p>
|
* <p>Perform the test required for this particular tag, and either evaluate or skip the body of this tag.</p>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* @exception JspException if a JSP exception occurs.
|
* @exception JspException if a JSP exception occurs.
|
||||||
*/
|
*/
|
||||||
public int doStartTag() throws JspException {
|
public int doStartTag() throws JspException {
|
||||||
|
|
||||||
if (condition()) {
|
if (condition()) {
|
||||||
return (EVAL_BODY_INCLUDE);
|
return (EVAL_BODY_INCLUDE);
|
||||||
} else {
|
} else {
|
||||||
return (SKIP_BODY);
|
return (SKIP_BODY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Evaluate the remainder of the current page as normal.</p>
|
* <p>Evaluate the remainder of the current page as normal.</p>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* @exception JspException if a JSP exception occurs.
|
* @exception JspException if a JSP exception occurs.
|
||||||
*/
|
*/
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
return (EVAL_PAGE);
|
return (EVAL_PAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Release all allocated resources.</p>
|
* <p>Release all allocated resources.</p>
|
||||||
*/
|
*/
|
||||||
public void release() {
|
public void release() {
|
||||||
|
|
||||||
super.release();
|
super.release();
|
||||||
objectName = null;
|
objectName = null;
|
||||||
objectValue = null;
|
objectValue = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The condition that must be met in order to display the body of this tag.</p>
|
* <p>The condition that must be met in order to display the body of this tag.</p>
|
||||||
*
|
*
|
||||||
* @exception JspException if a JSP exception occurs.
|
* @exception JspException if a JSP exception occurs.
|
||||||
* @return {@code true} if and only if all conditions are met.
|
* @return {@code true} if and only if all conditions are met.
|
||||||
*/
|
*/
|
||||||
protected abstract boolean condition() throws JspException;
|
protected abstract boolean condition() throws JspException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*--- Formatted in Sun Java Convention Style on ma, des 1, '03 ---*/
|
/*--- Formatted in Sun Java Convention Style on ma, des 1, '03 ---*/
|
||||||
|
|
||||||
|
|
||||||
/*------ Formatted by Jindent 3.23 Basic 1.0 --- http://www.jindent.de ------*/
|
/*------ Formatted by Jindent 3.23 Basic 1.0 --- http://www.jindent.de ------*/
|
||||||
|
|||||||
+168
-168
@@ -1,168 +1,168 @@
|
|||||||
/*
|
/*
|
||||||
* Produced (p) 2002 TwelveMonkeys
|
* Produced (p) 2002 TwelveMonkeys
|
||||||
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
||||||
* Phone : +47 22 57 70 00
|
* Phone : +47 22 57 70 00
|
||||||
* Fax : +47 22 57 70 70
|
* Fax : +47 22 57 70 70
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||||
|
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Custom tag for testing equality of an attribute against a given value.
|
* Custom tag for testing equality of an attribute against a given value.
|
||||||
* The attribute types supported so far is:
|
* The attribute types supported so far is:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code java.lang.String} (ver. 1.0)
|
* <li>{@code java.lang.String} (ver. 1.0)
|
||||||
* <li>{@code javax.servlet.http.Cookie} (ver. 1.0)
|
* <li>{@code javax.servlet.http.Cookie} (ver. 1.0)
|
||||||
* </ul>
|
* </ul>
|
||||||
* </p>
|
* </p>
|
||||||
* See the implemented <a href="#condition">{@code condition}</a> method for details regarding the equality conditions.
|
* See the implemented <a href="#condition">{@code condition}</a> method for details regarding the equality conditions.
|
||||||
*
|
*
|
||||||
* <p><hr></p>
|
* <p><hr></p>
|
||||||
*
|
*
|
||||||
* <h3>Tag Reference</h3>
|
* <h3>Tag Reference</h3>
|
||||||
* <table border="0" cellspacing="3" cellpadding="3" width="90%">
|
* <table border="0" cellspacing="3" cellpadding="3" width="90%">
|
||||||
* <tr bgcolor="#cccccc">
|
* <tr bgcolor="#cccccc">
|
||||||
* <td colspan="5" class="body"><b>equal</b></td>
|
* <td colspan="5" class="body"><b>equal</b></td>
|
||||||
* <td width="17%" align="right" class="body">Availability: 1.0</td>
|
* <td width="17%" align="right" class="body">Availability: 1.0</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td colspan="6" class="body"><p>Tag for testing if an attribute is equal to a given value.</p></td>
|
* <td colspan="6" class="body"><p>Tag for testing if an attribute is equal to a given value.</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td width="15%" class="body"><b>Tag Body</b></td>
|
* <td width="15%" class="body"><b>Tag Body</b></td>
|
||||||
* <td width="17%" class="body">JSP</td>
|
* <td width="17%" class="body">JSP</td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body"><b>Restrictions</b></td>
|
* <td class="body"><b>Restrictions</b></td>
|
||||||
* <td colspan="5" class="body"><p>None</p></td>
|
* <td colspan="5" class="body"><p>None</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body"><b>Attributes</b></td>
|
* <td class="body"><b>Attributes</b></td>
|
||||||
* <td class="body">Name</td>
|
* <td class="body">Name</td>
|
||||||
* <td class="body">Required</td>
|
* <td class="body">Required</td>
|
||||||
* <td colspan="2" class="body">Runtime Expression Evaluation</td>
|
* <td colspan="2" class="body">Runtime Expression Evaluation</td>
|
||||||
* <td class="body">Availability</td>
|
* <td class="body">Availability</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr bgcolor="#cccccc">
|
* <tr bgcolor="#cccccc">
|
||||||
* <td bgcolor="#ffffff"> </td>
|
* <td bgcolor="#ffffff"> </td>
|
||||||
* <td class="body_grey"><b>name</b></td>
|
* <td class="body_grey"><b>name</b></td>
|
||||||
* <td class="body_grey"> Yes</td>
|
* <td class="body_grey"> Yes</td>
|
||||||
* <td colspan="2" class="body_grey"> Yes</td>
|
* <td colspan="2" class="body_grey"> Yes</td>
|
||||||
* <td class="body_grey"> 1.0</td>
|
* <td class="body_grey"> 1.0</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td bgcolor="#ffffff"> </td>
|
* <td bgcolor="#ffffff"> </td>
|
||||||
* <td colspan="5" class="body"><p>The attribute name</p></td>
|
* <td colspan="5" class="body"><p>The attribute name</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr bgcolor="#cccccc">
|
* <tr bgcolor="#cccccc">
|
||||||
* <td bgcolor="#ffffff"> </td>
|
* <td bgcolor="#ffffff"> </td>
|
||||||
* <td class="body_grey"><b>value</b></td>
|
* <td class="body_grey"><b>value</b></td>
|
||||||
* <td class="body_grey"> No</td>
|
* <td class="body_grey"> No</td>
|
||||||
* <td colspan="2" class="body_grey"> Yes</td>
|
* <td colspan="2" class="body_grey"> Yes</td>
|
||||||
* <td class="body_grey"> 1.0</td>
|
* <td class="body_grey"> 1.0</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td bgcolor="#ffffff" class="body"> </td>
|
* <td bgcolor="#ffffff" class="body"> </td>
|
||||||
* <td colspan="5" class="body"><p>The value for equality testing</p></td>
|
* <td colspan="5" class="body"><p>The value for equality testing</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body" valign="top"><b>Variables</b></td>
|
* <td class="body" valign="top"><b>Variables</b></td>
|
||||||
* <td colspan="5" class="body">None</td>
|
* <td colspan="5" class="body">None</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body" valign="top"><b>Examples</b></td>
|
* <td class="body" valign="top"><b>Examples</b></td>
|
||||||
* <td colspan="5" class="body">
|
* <td colspan="5" class="body">
|
||||||
* <pre>
|
* <pre>
|
||||||
*<%@ taglib prefix="twelvemonkeys" uri="twelvemonkeys-logic" %>
|
*<%@ taglib prefix="twelvemonkeys" uri="twelvemonkeys-logic" %>
|
||||||
*<bean:cookie id="logonUsernameCookie"
|
*<bean:cookie id="logonUsernameCookie"
|
||||||
* name="<%= com.strutscommand.Constants.LOGON_USERNAME_COOKIE_NAME %>"
|
* name="<%= com.strutscommand.Constants.LOGON_USERNAME_COOKIE_NAME %>"
|
||||||
* value="no_username_set" />
|
* value="no_username_set" />
|
||||||
*<twelvemonkeys:equal name="logonUsernameCookie" value="no_username_set">
|
*<twelvemonkeys:equal name="logonUsernameCookie" value="no_username_set">
|
||||||
* <html:text property="username" />
|
* <html:text property="username" />
|
||||||
*</twelvemonkeys:equal>
|
*</twelvemonkeys:equal>
|
||||||
* </pre>
|
* </pre>
|
||||||
* </td>
|
* </td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* </table>
|
* </table>
|
||||||
*
|
*
|
||||||
* <hr>
|
* <hr>
|
||||||
*
|
*
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
||||||
* @see <a href="NotEqualTag.html">notEqual</a>
|
* @see <a href="NotEqualTag.html">notEqual</a>
|
||||||
*/
|
*/
|
||||||
public class EqualTag extends ConditionalTagBase {
|
public class EqualTag extends ConditionalTagBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a name="condition"></a>
|
* <a name="condition"></a>
|
||||||
*
|
*
|
||||||
* The conditions that must be met in order to display the body of this tag:
|
* The conditions that must be met in order to display the body of this tag:
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>The attribute name property ({@code name} -> {@code mObjectName}) must not be empty.
|
* <li>The attribute name property ({@code name} -> {@code mObjectName}) must not be empty.
|
||||||
* <li>The attribute must exist.
|
* <li>The attribute must exist.
|
||||||
* <li>The attribute must be an instance of one of the supported classes:
|
* <li>The attribute must be an instance of one of the supported classes:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code java.lang.String}
|
* <li>{@code java.lang.String}
|
||||||
* <li>{@code javax.servlet.http.Cookie}
|
* <li>{@code javax.servlet.http.Cookie}
|
||||||
* </ul>
|
* </ul>
|
||||||
* <li>The value of the attribute must be equal to the object value property ({@code value} -> {@code mObjectValue}).
|
* <li>The value of the attribute must be equal to the object value property ({@code value} -> {@code mObjectValue}).
|
||||||
* </ol>
|
* </ol>
|
||||||
* <p>
|
* <p>
|
||||||
* NB! If the object value property ({@code value} -> {@code mObjectValue}) is empty than {@code true} will be returned.
|
* NB! If the object value property ({@code value} -> {@code mObjectValue}) is empty than {@code true} will be returned.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @return {@code true} if and only if all conditions are met.
|
* @return {@code true} if and only if all conditions are met.
|
||||||
*/
|
*/
|
||||||
protected boolean condition() throws JspException {
|
protected boolean condition() throws JspException {
|
||||||
|
|
||||||
if (StringUtil.isEmpty(objectName)) {
|
if (StringUtil.isEmpty(objectName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtil.isEmpty(objectValue)) {
|
if (StringUtil.isEmpty(objectValue)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object pageScopedAttribute = pageContext.getAttribute(objectName);
|
Object pageScopedAttribute = pageContext.getAttribute(objectName);
|
||||||
if (pageScopedAttribute == null) {
|
if (pageScopedAttribute == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pageScopedStringAttribute;
|
String pageScopedStringAttribute;
|
||||||
|
|
||||||
// String
|
// String
|
||||||
if (pageScopedAttribute instanceof String) {
|
if (pageScopedAttribute instanceof String) {
|
||||||
pageScopedStringAttribute = (String) pageScopedAttribute;
|
pageScopedStringAttribute = (String) pageScopedAttribute;
|
||||||
|
|
||||||
// Cookie
|
// Cookie
|
||||||
}
|
}
|
||||||
else if (pageScopedAttribute instanceof Cookie) {
|
else if (pageScopedAttribute instanceof Cookie) {
|
||||||
pageScopedStringAttribute = ((Cookie) pageScopedAttribute).getValue();
|
pageScopedStringAttribute = ((Cookie) pageScopedAttribute).getValue();
|
||||||
|
|
||||||
// Type not yet supported...
|
// Type not yet supported...
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (pageScopedStringAttribute.equals(objectValue));
|
return (pageScopedStringAttribute.equals(objectValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-40
@@ -1,40 +1,40 @@
|
|||||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||||
|
|
||||||
import javax.servlet.jsp.tagext.*;
|
import javax.servlet.jsp.tagext.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TagExtraInfo class for IteratorProvider tags.
|
* TagExtraInfo class for IteratorProvider tags.
|
||||||
*
|
*
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
* @version $id: $
|
* @version $id: $
|
||||||
*/
|
*/
|
||||||
public class IteratorProviderTEI extends TagExtraInfo {
|
public class IteratorProviderTEI extends TagExtraInfo {
|
||||||
/**
|
/**
|
||||||
* Gets the variable info for IteratorProvider tags. The attribute with the
|
* Gets the variable info for IteratorProvider tags. The attribute with the
|
||||||
* name defined by the "id" attribute and type defined by the "type"
|
* name defined by the "id" attribute and type defined by the "type"
|
||||||
* attribute is declared with scope {@code VariableInfo.AT_END}.
|
* attribute is declared with scope {@code VariableInfo.AT_END}.
|
||||||
*
|
*
|
||||||
* @param pData TagData instance provided by container
|
* @param pData TagData instance provided by container
|
||||||
* @return an VariableInfo array of lenght 1, containing the attribute
|
* @return an VariableInfo array of lenght 1, containing the attribute
|
||||||
* defined by the id parameter, declared, and with scope
|
* defined by the id parameter, declared, and with scope
|
||||||
* {@code VariableInfo.AT_END}.
|
* {@code VariableInfo.AT_END}.
|
||||||
*/
|
*/
|
||||||
public VariableInfo[] getVariableInfo(TagData pData) {
|
public VariableInfo[] getVariableInfo(TagData pData) {
|
||||||
// Get attribute name
|
// Get attribute name
|
||||||
String attributeName = pData.getId();
|
String attributeName = pData.getId();
|
||||||
if (attributeName == null) {
|
if (attributeName == null) {
|
||||||
attributeName = IteratorProviderTag.getDefaultIteratorName();
|
attributeName = IteratorProviderTag.getDefaultIteratorName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get type
|
// Get type
|
||||||
String type = pData.getAttributeString(IteratorProviderTag.ATTRIBUTE_TYPE);
|
String type = pData.getAttributeString(IteratorProviderTag.ATTRIBUTE_TYPE);
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
type = IteratorProviderTag.getDefaultIteratorType();
|
type = IteratorProviderTag.getDefaultIteratorType();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the variable info
|
// Return the variable info
|
||||||
return new VariableInfo[]{
|
return new VariableInfo[]{
|
||||||
new VariableInfo(attributeName, type, true, VariableInfo.AT_END),
|
new VariableInfo(attributeName, type, true, VariableInfo.AT_END),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+86
-86
@@ -1,86 +1,86 @@
|
|||||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||||
|
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
import javax.servlet.jsp.tagext.Tag;
|
import javax.servlet.jsp.tagext.Tag;
|
||||||
import javax.servlet.jsp.tagext.TagSupport;
|
import javax.servlet.jsp.tagext.TagSupport;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for adding iterators to a page.
|
* Abstract base class for adding iterators to a page.
|
||||||
*
|
*
|
||||||
* @todo Possible to use same strategy for all types of objects? Rename class
|
* @todo Possible to use same strategy for all types of objects? Rename class
|
||||||
* to ObjectProviderTag? Hmmm... Might work.
|
* to ObjectProviderTag? Hmmm... Might work.
|
||||||
*
|
*
|
||||||
* @author Harald Kuhr
|
* @author Harald Kuhr
|
||||||
* @version $id: $
|
* @version $id: $
|
||||||
*/
|
*/
|
||||||
public abstract class IteratorProviderTag extends TagSupport {
|
public abstract class IteratorProviderTag extends TagSupport {
|
||||||
/** {@code iterator} */
|
/** {@code iterator} */
|
||||||
protected final static String DEFAULT_ITERATOR_NAME = "iterator";
|
protected final static String DEFAULT_ITERATOR_NAME = "iterator";
|
||||||
/** {@code java.util.iterator} */
|
/** {@code java.util.iterator} */
|
||||||
protected final static String DEFAULT_ITERATOR_TYPE = "java.util.Iterator";
|
protected final static String DEFAULT_ITERATOR_TYPE = "java.util.Iterator";
|
||||||
/** {@code type} */
|
/** {@code type} */
|
||||||
public final static String ATTRIBUTE_TYPE = "type";
|
public final static String ATTRIBUTE_TYPE = "type";
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
private String type = null;
|
private String type = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type.
|
* Gets the type.
|
||||||
*
|
*
|
||||||
* @return the type (class name)
|
* @return the type (class name)
|
||||||
*/
|
*/
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the type.
|
* Sets the type.
|
||||||
*
|
*
|
||||||
* @param pType
|
* @param pType
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void setType(String pType) {
|
public void setType(String pType) {
|
||||||
type = pType;
|
type = pType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doEndTag implementation.
|
* doEndTag implementation.
|
||||||
*
|
*
|
||||||
* @return {@code Tag.EVAL_PAGE}
|
* @return {@code Tag.EVAL_PAGE}
|
||||||
* @throws JspException
|
* @throws JspException
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int doEndTag() throws JspException {
|
public int doEndTag() throws JspException {
|
||||||
// Set the iterator
|
// Set the iterator
|
||||||
pageContext.setAttribute(getId(), getIterator());
|
pageContext.setAttribute(getId(), getIterator());
|
||||||
|
|
||||||
return Tag.EVAL_PAGE;
|
return Tag.EVAL_PAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the iterator for this tag.
|
* Gets the iterator for this tag.
|
||||||
*
|
*
|
||||||
* @return an {@link java.util.Iterator}
|
* @return an {@link java.util.Iterator}
|
||||||
*/
|
*/
|
||||||
protected abstract Iterator getIterator();
|
protected abstract Iterator getIterator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default iterator name.
|
* Gets the default iterator name.
|
||||||
*
|
*
|
||||||
* @return {@link #DEFAULT_ITERATOR_NAME}
|
* @return {@link #DEFAULT_ITERATOR_NAME}
|
||||||
*/
|
*/
|
||||||
protected static String getDefaultIteratorName() {
|
protected static String getDefaultIteratorName() {
|
||||||
return DEFAULT_ITERATOR_NAME;
|
return DEFAULT_ITERATOR_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default iterator type.
|
* Gets the default iterator type.
|
||||||
*
|
*
|
||||||
* @return {@link #DEFAULT_ITERATOR_TYPE}
|
* @return {@link #DEFAULT_ITERATOR_TYPE}
|
||||||
*/
|
*/
|
||||||
protected static String getDefaultIteratorType() {
|
protected static String getDefaultIteratorType() {
|
||||||
return DEFAULT_ITERATOR_TYPE;
|
return DEFAULT_ITERATOR_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+168
-168
@@ -1,168 +1,168 @@
|
|||||||
/*
|
/*
|
||||||
* Produced (p) 2002 TwelveMonkeys
|
* Produced (p) 2002 TwelveMonkeys
|
||||||
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
||||||
* Phone : +47 22 57 70 00
|
* Phone : +47 22 57 70 00
|
||||||
* Fax : +47 22 57 70 70
|
* Fax : +47 22 57 70 70
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||||
|
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.jsp.JspException;
|
import javax.servlet.jsp.JspException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Custom tag for testing non-equality of an attribute against a given value.
|
* Custom tag for testing non-equality of an attribute against a given value.
|
||||||
* The attribute types supported so far is:
|
* The attribute types supported so far is:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code java.lang.String} (ver. 1.0)
|
* <li>{@code java.lang.String} (ver. 1.0)
|
||||||
* <li>{@code javax.servlet.http.Cookie} (ver. 1.0)
|
* <li>{@code javax.servlet.http.Cookie} (ver. 1.0)
|
||||||
* </ul>
|
* </ul>
|
||||||
* </p>
|
* </p>
|
||||||
* See the implemented <a href="#condition">{@code condition}</a> method for details regarding the non-equality conditions.
|
* See the implemented <a href="#condition">{@code condition}</a> method for details regarding the non-equality conditions.
|
||||||
*
|
*
|
||||||
* <p><hr></p>
|
* <p><hr></p>
|
||||||
*
|
*
|
||||||
* <h3>Tag Reference</h3>
|
* <h3>Tag Reference</h3>
|
||||||
* <table border="0" cellspacing="3" cellpadding="3" width="90%">
|
* <table border="0" cellspacing="3" cellpadding="3" width="90%">
|
||||||
* <tr bgcolor="#cccccc">
|
* <tr bgcolor="#cccccc">
|
||||||
* <td colspan="5" class="body"><b>notEqual</b></td>
|
* <td colspan="5" class="body"><b>notEqual</b></td>
|
||||||
* <td width="17%" align="right" class="body">Availability: 1.0</td>
|
* <td width="17%" align="right" class="body">Availability: 1.0</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td colspan="6" class="body"><p>Tag for testing if an attribute is NOT equal to a given value.</p></td>
|
* <td colspan="6" class="body"><p>Tag for testing if an attribute is NOT equal to a given value.</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td width="15%" class="body"><b>Tag Body</b></td>
|
* <td width="15%" class="body"><b>Tag Body</b></td>
|
||||||
* <td width="17%" class="body">JSP</td>
|
* <td width="17%" class="body">JSP</td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* <td width="17%" class="body"> </td>
|
* <td width="17%" class="body"> </td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body"><b>Restrictions</b></td>
|
* <td class="body"><b>Restrictions</b></td>
|
||||||
* <td colspan="5" class="body"><p>None</p></td>
|
* <td colspan="5" class="body"><p>None</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body"><b>Attributes</b></td>
|
* <td class="body"><b>Attributes</b></td>
|
||||||
* <td class="body">Name</td>
|
* <td class="body">Name</td>
|
||||||
* <td class="body">Required</td>
|
* <td class="body">Required</td>
|
||||||
* <td colspan="2" class="body">Runtime Expression Evaluation</td>
|
* <td colspan="2" class="body">Runtime Expression Evaluation</td>
|
||||||
* <td class="body">Availability</td>
|
* <td class="body">Availability</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr bgcolor="#cccccc">
|
* <tr bgcolor="#cccccc">
|
||||||
* <td bgcolor="#ffffff"> </td>
|
* <td bgcolor="#ffffff"> </td>
|
||||||
* <td class="body_grey"><b>name</b></td>
|
* <td class="body_grey"><b>name</b></td>
|
||||||
* <td class="body_grey"> Yes</td>
|
* <td class="body_grey"> Yes</td>
|
||||||
* <td colspan="2" class="body_grey"> Yes</td>
|
* <td colspan="2" class="body_grey"> Yes</td>
|
||||||
* <td class="body_grey"> 1.0</td>
|
* <td class="body_grey"> 1.0</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td bgcolor="#ffffff"> </td>
|
* <td bgcolor="#ffffff"> </td>
|
||||||
* <td colspan="5" class="body"><p>The attribute name</p></td>
|
* <td colspan="5" class="body"><p>The attribute name</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr bgcolor="#cccccc">
|
* <tr bgcolor="#cccccc">
|
||||||
* <td bgcolor="#ffffff"> </td>
|
* <td bgcolor="#ffffff"> </td>
|
||||||
* <td class="body_grey"><b>value</b></td>
|
* <td class="body_grey"><b>value</b></td>
|
||||||
* <td class="body_grey"> No</td>
|
* <td class="body_grey"> No</td>
|
||||||
* <td colspan="2" class="body_grey"> Yes</td>
|
* <td colspan="2" class="body_grey"> Yes</td>
|
||||||
* <td class="body_grey"> 1.0</td>
|
* <td class="body_grey"> 1.0</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td bgcolor="#ffffff" class="body"> </td>
|
* <td bgcolor="#ffffff" class="body"> </td>
|
||||||
* <td colspan="5" class="body"><p>The value for equality testing</p></td>
|
* <td colspan="5" class="body"><p>The value for equality testing</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body" valign="top"><b>Variables</b></td>
|
* <td class="body" valign="top"><b>Variables</b></td>
|
||||||
* <td colspan="5" class="body">None</td>
|
* <td colspan="5" class="body">None</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td class="body" valign="top"><b>Examples</b></td>
|
* <td class="body" valign="top"><b>Examples</b></td>
|
||||||
* <td colspan="5" class="body">
|
* <td colspan="5" class="body">
|
||||||
* <pre>
|
* <pre>
|
||||||
*<%@ taglib prefix="twelvemonkeys" uri="twelvemonkeys-logic" %>
|
*<%@ taglib prefix="twelvemonkeys" uri="twelvemonkeys-logic" %>
|
||||||
*<bean:cookie id="logonUsernameCookie"
|
*<bean:cookie id="logonUsernameCookie"
|
||||||
* name="<%= com.strutscommand.Constants.LOGON_USERNAME_COOKIE_NAME %>"
|
* name="<%= com.strutscommand.Constants.LOGON_USERNAME_COOKIE_NAME %>"
|
||||||
* value="no_username_set" />
|
* value="no_username_set" />
|
||||||
*<twelvemonkeys:notEqual name="logonUsernameCookie" value="no_username_set">
|
*<twelvemonkeys:notEqual name="logonUsernameCookie" value="no_username_set">
|
||||||
* <html:text property="username" value="<%= logonUsernameCookie.getValue() %>" />
|
* <html:text property="username" value="<%= logonUsernameCookie.getValue() %>" />
|
||||||
*</twelvemonkeys:notEqual>
|
*</twelvemonkeys:notEqual>
|
||||||
* </pre>
|
* </pre>
|
||||||
* </td>
|
* </td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* </table>
|
* </table>
|
||||||
*
|
*
|
||||||
* <hr>
|
* <hr>
|
||||||
*
|
*
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
||||||
* @see <a href="EqualTag.html">equal</a>
|
* @see <a href="EqualTag.html">equal</a>
|
||||||
*/
|
*/
|
||||||
public class NotEqualTag extends ConditionalTagBase {
|
public class NotEqualTag extends ConditionalTagBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a name="condition"></a>
|
* <a name="condition"></a>
|
||||||
*
|
*
|
||||||
* The condition that must be met in order to display the body of this tag:
|
* The condition that must be met in order to display the body of this tag:
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>The attribute name property ({@code name} -> {@code mObjectName}) must not be empty.
|
* <li>The attribute name property ({@code name} -> {@code mObjectName}) must not be empty.
|
||||||
* <li>The attribute must exist.
|
* <li>The attribute must exist.
|
||||||
* <li>The attribute must be an instance of one of the supported classes:
|
* <li>The attribute must be an instance of one of the supported classes:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code java.lang.String}
|
* <li>{@code java.lang.String}
|
||||||
* <li>{@code javax.servlet.http.Cookie}
|
* <li>{@code javax.servlet.http.Cookie}
|
||||||
* </ul>
|
* </ul>
|
||||||
* <li>The value of the attribute must NOT be equal to the object value property ({@code value} -> {@code mObjectValue}).
|
* <li>The value of the attribute must NOT be equal to the object value property ({@code value} -> {@code mObjectValue}).
|
||||||
* </ol>
|
* </ol>
|
||||||
* <p>
|
* <p>
|
||||||
* NB! If the object value property ({@code value} -> {@code mObjectValue}) is empty than {@code true} will be returned.
|
* NB! If the object value property ({@code value} -> {@code mObjectValue}) is empty than {@code true} will be returned.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @return {@code true} if and only if all conditions are met.
|
* @return {@code true} if and only if all conditions are met.
|
||||||
*/
|
*/
|
||||||
protected boolean condition() throws JspException {
|
protected boolean condition() throws JspException {
|
||||||
|
|
||||||
if (StringUtil.isEmpty(objectName)) {
|
if (StringUtil.isEmpty(objectName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtil.isEmpty(objectValue)) {
|
if (StringUtil.isEmpty(objectValue)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object pageScopedAttribute = pageContext.getAttribute(objectName);
|
Object pageScopedAttribute = pageContext.getAttribute(objectName);
|
||||||
if (pageScopedAttribute == null) {
|
if (pageScopedAttribute == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pageScopedStringAttribute;
|
String pageScopedStringAttribute;
|
||||||
|
|
||||||
// String
|
// String
|
||||||
if (pageScopedAttribute instanceof String) {
|
if (pageScopedAttribute instanceof String) {
|
||||||
pageScopedStringAttribute = (String) pageScopedAttribute;
|
pageScopedStringAttribute = (String) pageScopedAttribute;
|
||||||
|
|
||||||
// Cookie
|
// Cookie
|
||||||
}
|
}
|
||||||
else if (pageScopedAttribute instanceof Cookie) {
|
else if (pageScopedAttribute instanceof Cookie) {
|
||||||
pageScopedStringAttribute = ((Cookie) pageScopedAttribute).getValue();
|
pageScopedStringAttribute = ((Cookie) pageScopedAttribute).getValue();
|
||||||
|
|
||||||
// Type not yet supported...
|
// Type not yet supported...
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (!(pageScopedStringAttribute.equals(objectValue)));
|
return (!(pageScopedStringAttribute.equals(objectValue)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+183
-183
@@ -1,183 +1,183 @@
|
|||||||
package com.twelvemonkeys.servlet.log4j;
|
package com.twelvemonkeys.servlet.log4j;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.Servlet;
|
import javax.servlet.Servlet;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log4JContextWrapper
|
* Log4JContextWrapper
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: log4j/Log4JContextWrapper.java#1 $
|
* @version $Id: log4j/Log4JContextWrapper.java#1 $
|
||||||
*/
|
*/
|
||||||
final class Log4JContextWrapper implements ServletContext {
|
final class Log4JContextWrapper implements ServletContext {
|
||||||
// TODO: Move to sandbox
|
// TODO: Move to sandbox
|
||||||
|
|
||||||
// TODO: This solution sucks...
|
// TODO: This solution sucks...
|
||||||
// How about starting to create some kind of pluggable decorator system,
|
// How about starting to create some kind of pluggable decorator system,
|
||||||
// something along the lines of AOP mixins/interceptor pattern..
|
// something along the lines of AOP mixins/interceptor pattern..
|
||||||
// Probably using a dynamic Proxy, delegating to the mixins and or the
|
// Probably using a dynamic Proxy, delegating to the mixins and or the
|
||||||
// wrapped object based on configuration.
|
// wrapped object based on configuration.
|
||||||
// This way we could simply call ServletUtil.decorate(ServletContext):ServletContext
|
// This way we could simply call ServletUtil.decorate(ServletContext):ServletContext
|
||||||
// And the context would be decorated with all configured mixins at once,
|
// And the context would be decorated with all configured mixins at once,
|
||||||
// requiring less boilerplate delegation code, and less layers of wrapping
|
// requiring less boilerplate delegation code, and less layers of wrapping
|
||||||
// (alternatively we could decorate the Servlet/FilterConfig objects).
|
// (alternatively we could decorate the Servlet/FilterConfig objects).
|
||||||
// See the ServletUtil.createWrapper methods for some hints..
|
// See the ServletUtil.createWrapper methods for some hints..
|
||||||
|
|
||||||
|
|
||||||
// Something like this:
|
// Something like this:
|
||||||
public static ServletContext wrap(final ServletContext pContext, final Object[] pDelegates, final ClassLoader pLoader) {
|
public static ServletContext wrap(final ServletContext pContext, final Object[] pDelegates, final ClassLoader pLoader) {
|
||||||
ClassLoader cl = pLoader != null ? pLoader : Thread.currentThread().getContextClassLoader();
|
ClassLoader cl = pLoader != null ? pLoader : Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
// TODO: Create a "static" mapping between methods in the ServletContext
|
// TODO: Create a "static" mapping between methods in the ServletContext
|
||||||
// and the corresponding delegate
|
// and the corresponding delegate
|
||||||
|
|
||||||
// TODO: Resolve super-invokations, to delegate to next delegate in
|
// TODO: Resolve super-invokations, to delegate to next delegate in
|
||||||
// chain, and finally invoke pContext
|
// chain, and finally invoke pContext
|
||||||
|
|
||||||
return (ServletContext) Proxy.newProxyInstance(cl, new Class[] {ServletContext.class}, new InvocationHandler() {
|
return (ServletContext) Proxy.newProxyInstance(cl, new Class[] {ServletContext.class}, new InvocationHandler() {
|
||||||
public Object invoke(Object pProxy, Method pMethod, Object[] pArgs) throws Throwable {
|
public Object invoke(Object pProxy, Method pMethod, Object[] pArgs) throws Throwable {
|
||||||
// TODO: Test if any of the delegates should receive, if so invoke
|
// TODO: Test if any of the delegates should receive, if so invoke
|
||||||
|
|
||||||
// Else, invoke on original object
|
// Else, invoke on original object
|
||||||
return pMethod.invoke(pContext, pArgs);
|
return pMethod.invoke(pContext, pArgs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ServletContext context;
|
private final ServletContext context;
|
||||||
|
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
|
||||||
Log4JContextWrapper(ServletContext pContext) {
|
Log4JContextWrapper(ServletContext pContext) {
|
||||||
context = pContext;
|
context = pContext;
|
||||||
|
|
||||||
// TODO: We want a logger per servlet, not per servlet context, right?
|
// TODO: We want a logger per servlet, not per servlet context, right?
|
||||||
logger = Logger.getLogger(pContext.getServletContextName());
|
logger = Logger.getLogger(pContext.getServletContextName());
|
||||||
|
|
||||||
// TODO: Automatic init/config of Log4J using context parameter for log4j.xml?
|
// TODO: Automatic init/config of Log4J using context parameter for log4j.xml?
|
||||||
// See Log4JInit.java
|
// See Log4JInit.java
|
||||||
|
|
||||||
// TODO: Automatic config of properties in the context wrapper?
|
// TODO: Automatic config of properties in the context wrapper?
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void log(final Exception pException, final String pMessage) {
|
public final void log(final Exception pException, final String pMessage) {
|
||||||
log(pMessage, pException);
|
log(pMessage, pException);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add more logging methods to interface info/warn/error?
|
// TODO: Add more logging methods to interface info/warn/error?
|
||||||
// TODO: Implement these mehtods in GenericFilter/GenericServlet?
|
// TODO: Implement these mehtods in GenericFilter/GenericServlet?
|
||||||
|
|
||||||
public void log(String pMessage) {
|
public void log(String pMessage) {
|
||||||
// TODO: Get logger for caller..
|
// TODO: Get logger for caller..
|
||||||
// Should be possible using some stack peek hack, but that's slow...
|
// Should be possible using some stack peek hack, but that's slow...
|
||||||
// Find a good way...
|
// Find a good way...
|
||||||
// Maybe just pass it into the constuctor, and have one wrapper per servlet
|
// Maybe just pass it into the constuctor, and have one wrapper per servlet
|
||||||
logger.info(pMessage);
|
logger.info(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String pMessage, Throwable pCause) {
|
public void log(String pMessage, Throwable pCause) {
|
||||||
// TODO: Get logger for caller..
|
// TODO: Get logger for caller..
|
||||||
|
|
||||||
logger.error(pMessage, pCause);
|
logger.error(pMessage, pCause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getAttribute(String pMessage) {
|
public Object getAttribute(String pMessage) {
|
||||||
return context.getAttribute(pMessage);
|
return context.getAttribute(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getAttributeNames() {
|
public Enumeration getAttributeNames() {
|
||||||
return context.getAttributeNames();
|
return context.getAttributeNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletContext getContext(String pMessage) {
|
public ServletContext getContext(String pMessage) {
|
||||||
return context.getContext(pMessage);
|
return context.getContext(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInitParameter(String pMessage) {
|
public String getInitParameter(String pMessage) {
|
||||||
return context.getInitParameter(pMessage);
|
return context.getInitParameter(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getInitParameterNames() {
|
public Enumeration getInitParameterNames() {
|
||||||
return context.getInitParameterNames();
|
return context.getInitParameterNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMajorVersion() {
|
public int getMajorVersion() {
|
||||||
return context.getMajorVersion();
|
return context.getMajorVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMimeType(String pMessage) {
|
public String getMimeType(String pMessage) {
|
||||||
return context.getMimeType(pMessage);
|
return context.getMimeType(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinorVersion() {
|
public int getMinorVersion() {
|
||||||
return context.getMinorVersion();
|
return context.getMinorVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestDispatcher getNamedDispatcher(String pMessage) {
|
public RequestDispatcher getNamedDispatcher(String pMessage) {
|
||||||
return context.getNamedDispatcher(pMessage);
|
return context.getNamedDispatcher(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealPath(String pMessage) {
|
public String getRealPath(String pMessage) {
|
||||||
return context.getRealPath(pMessage);
|
return context.getRealPath(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestDispatcher getRequestDispatcher(String pMessage) {
|
public RequestDispatcher getRequestDispatcher(String pMessage) {
|
||||||
return context.getRequestDispatcher(pMessage);
|
return context.getRequestDispatcher(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public URL getResource(String pMessage) throws MalformedURLException {
|
public URL getResource(String pMessage) throws MalformedURLException {
|
||||||
return context.getResource(pMessage);
|
return context.getResource(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getResourceAsStream(String pMessage) {
|
public InputStream getResourceAsStream(String pMessage) {
|
||||||
return context.getResourceAsStream(pMessage);
|
return context.getResourceAsStream(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set getResourcePaths(String pMessage) {
|
public Set getResourcePaths(String pMessage) {
|
||||||
return context.getResourcePaths(pMessage);
|
return context.getResourcePaths(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServerInfo() {
|
public String getServerInfo() {
|
||||||
return context.getServerInfo();
|
return context.getServerInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Servlet getServlet(String pMessage) throws ServletException {
|
public Servlet getServlet(String pMessage) throws ServletException {
|
||||||
//noinspection deprecation
|
//noinspection deprecation
|
||||||
return context.getServlet(pMessage);
|
return context.getServlet(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServletContextName() {
|
public String getServletContextName() {
|
||||||
return context.getServletContextName();
|
return context.getServletContextName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getServletNames() {
|
public Enumeration getServletNames() {
|
||||||
//noinspection deprecation
|
//noinspection deprecation
|
||||||
return context.getServletNames();
|
return context.getServletNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getServlets() {
|
public Enumeration getServlets() {
|
||||||
//noinspection deprecation
|
//noinspection deprecation
|
||||||
return context.getServlets();
|
return context.getServlets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAttribute(String pMessage) {
|
public void removeAttribute(String pMessage) {
|
||||||
context.removeAttribute(pMessage);
|
context.removeAttribute(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(String pMessage, Object pExtension) {
|
public void setAttribute(String pMessage, Object pExtension) {
|
||||||
context.setAttribute(pMessage, pExtension);
|
context.setAttribute(pMessage, pExtension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,118 +1,118 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DebugServlet class description.
|
* DebugServlet class description.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: DebugServlet.java#1 $
|
* @version $Id: DebugServlet.java#1 $
|
||||||
*/
|
*/
|
||||||
public class DebugServlet extends GenericServlet {
|
public class DebugServlet extends GenericServlet {
|
||||||
private long dateModified;
|
private long dateModified;
|
||||||
|
|
||||||
public final void service(ServletRequest pRequest, ServletResponse pResponse) throws ServletException, IOException {
|
public final void service(ServletRequest pRequest, ServletResponse pResponse) throws ServletException, IOException {
|
||||||
service((HttpServletRequest) pRequest, (HttpServletResponse) pResponse);
|
service((HttpServletRequest) pRequest, (HttpServletResponse) pResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() throws ServletException {
|
public void init() throws ServletException {
|
||||||
super.init();
|
super.init();
|
||||||
dateModified = System.currentTimeMillis();
|
dateModified = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
||||||
pResponse.setContentType("text/plain");
|
pResponse.setContentType("text/plain");
|
||||||
// Include these to allow browser caching
|
// Include these to allow browser caching
|
||||||
pResponse.setDateHeader("Last-Modified", dateModified);
|
pResponse.setDateHeader("Last-Modified", dateModified);
|
||||||
pResponse.setHeader("ETag", getServletName());
|
pResponse.setHeader("ETag", getServletName());
|
||||||
|
|
||||||
ServletOutputStream out = pResponse.getOutputStream();
|
ServletOutputStream out = pResponse.getOutputStream();
|
||||||
|
|
||||||
out.println("Remote address: " + pRequest.getRemoteAddr());
|
out.println("Remote address: " + pRequest.getRemoteAddr());
|
||||||
out.println("Remote host name: " + pRequest.getRemoteHost());
|
out.println("Remote host name: " + pRequest.getRemoteHost());
|
||||||
out.println("Remote user: " + pRequest.getRemoteUser());
|
out.println("Remote user: " + pRequest.getRemoteUser());
|
||||||
out.println();
|
out.println();
|
||||||
|
|
||||||
out.println("Request Method: " + pRequest.getMethod());
|
out.println("Request Method: " + pRequest.getMethod());
|
||||||
out.println("Request Scheme: " + pRequest.getScheme());
|
out.println("Request Scheme: " + pRequest.getScheme());
|
||||||
out.println("Request URI: " + pRequest.getRequestURI());
|
out.println("Request URI: " + pRequest.getRequestURI());
|
||||||
out.println("Request URL: " + pRequest.getRequestURL().toString());
|
out.println("Request URL: " + pRequest.getRequestURL().toString());
|
||||||
out.println("Request PathInfo: " + pRequest.getPathInfo());
|
out.println("Request PathInfo: " + pRequest.getPathInfo());
|
||||||
out.println("Request ContentLength: " + pRequest.getContentLength());
|
out.println("Request ContentLength: " + pRequest.getContentLength());
|
||||||
out.println();
|
out.println();
|
||||||
|
|
||||||
out.println("Request Headers:");
|
out.println("Request Headers:");
|
||||||
Enumeration headerNames = pRequest.getHeaderNames();
|
Enumeration headerNames = pRequest.getHeaderNames();
|
||||||
while (headerNames.hasMoreElements()) {
|
while (headerNames.hasMoreElements()) {
|
||||||
String headerName = (String) headerNames.nextElement();
|
String headerName = (String) headerNames.nextElement();
|
||||||
Enumeration headerValues = pRequest.getHeaders(headerName);
|
Enumeration headerValues = pRequest.getHeaders(headerName);
|
||||||
|
|
||||||
if (headerName != null) {
|
if (headerName != null) {
|
||||||
while (headerValues.hasMoreElements()) {
|
while (headerValues.hasMoreElements()) {
|
||||||
String value = (String) headerValues.nextElement();
|
String value = (String) headerValues.nextElement();
|
||||||
out.println(" " + headerName + ": " + value);
|
out.println(" " + headerName + ": " + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.println();
|
out.println();
|
||||||
|
|
||||||
out.println("Request parameters:");
|
out.println("Request parameters:");
|
||||||
Enumeration paramNames = pRequest.getParameterNames();
|
Enumeration paramNames = pRequest.getParameterNames();
|
||||||
while (paramNames.hasMoreElements()) {
|
while (paramNames.hasMoreElements()) {
|
||||||
String name = (String) paramNames.nextElement();
|
String name = (String) paramNames.nextElement();
|
||||||
String[] values = pRequest.getParameterValues(name);
|
String[] values = pRequest.getParameterValues(name);
|
||||||
|
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
out.println(" " + name + ": " + value);
|
out.println(" " + name + ": " + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.println();
|
out.println();
|
||||||
|
|
||||||
out.println("Request attributes:");
|
out.println("Request attributes:");
|
||||||
Enumeration attribNames = pRequest.getAttributeNames();
|
Enumeration attribNames = pRequest.getAttributeNames();
|
||||||
while (attribNames.hasMoreElements()) {
|
while (attribNames.hasMoreElements()) {
|
||||||
String name = (String) attribNames.nextElement();
|
String name = (String) attribNames.nextElement();
|
||||||
Object value = pRequest.getAttribute(name);
|
Object value = pRequest.getAttribute(name);
|
||||||
out.println(" " + name + ": " + value);
|
out.println(" " + name + ": " + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,382 +1,382 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.BeanUtil;
|
import com.twelvemonkeys.lang.BeanUtil;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a generic, protocol-independent filter.
|
* Defines a generic, protocol-independent filter.
|
||||||
* <P/>
|
* <P/>
|
||||||
* {@code GenericFilter} is inspired by {@link GenericServlet}, and
|
* {@code GenericFilter} is inspired by {@link GenericServlet}, and
|
||||||
* implements the {@code Filter} and {@code FilterConfig} interfaces.
|
* implements the {@code Filter} and {@code FilterConfig} interfaces.
|
||||||
* <P/>
|
* <P/>
|
||||||
* {@code GenericFilter} makes writing filters easier. It provides simple
|
* {@code GenericFilter} makes writing filters easier. It provides simple
|
||||||
* versions of the lifecycle methods {@code init} and {@code destroy}
|
* versions of the lifecycle methods {@code init} and {@code destroy}
|
||||||
* and of the methods in the {@code FilterConfig} interface.
|
* and of the methods in the {@code FilterConfig} interface.
|
||||||
* {@code GenericFilter} also implements the {@code log} methods,
|
* {@code GenericFilter} also implements the {@code log} methods,
|
||||||
* declared in the {@code ServletContext} interface.
|
* declared in the {@code ServletContext} interface.
|
||||||
* <p/
|
* <p/
|
||||||
* {@code GenericFilter} has an auto-init system, that automatically invokes
|
* {@code GenericFilter} has an auto-init system, that automatically invokes
|
||||||
* the method matching the signature {@code void setX(<Type>)},
|
* the method matching the signature {@code void setX(<Type>)},
|
||||||
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
||||||
* naming is supported, lisp-style names will be converted to camelCase.
|
* naming is supported, lisp-style names will be converted to camelCase.
|
||||||
* Parameter values are automatically converted from string representation to
|
* Parameter values are automatically converted from string representation to
|
||||||
* most basic types, if necessary.
|
* most basic types, if necessary.
|
||||||
* <p/>
|
* <p/>
|
||||||
* To write a generic filter, you need only override the abstract
|
* To write a generic filter, you need only override the abstract
|
||||||
* {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method.
|
* {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Id: GenericFilter.java#1 $
|
* @version $Id: GenericFilter.java#1 $
|
||||||
*
|
*
|
||||||
* @see Filter
|
* @see Filter
|
||||||
* @see FilterConfig
|
* @see FilterConfig
|
||||||
*/
|
*/
|
||||||
public abstract class GenericFilter implements Filter, FilterConfig, Serializable {
|
public abstract class GenericFilter implements Filter, FilterConfig, Serializable {
|
||||||
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filter config.
|
* The filter config.
|
||||||
*/
|
*/
|
||||||
private transient FilterConfig filterConfig = null;
|
private transient FilterConfig filterConfig = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure the filter runs once per request
|
* Makes sure the filter runs once per request
|
||||||
* <p/>
|
* <p/>
|
||||||
* @see #isRunOnce
|
* @see #isRunOnce
|
||||||
* @see #ATTRIB_RUN_ONCE_VALUE
|
* @see #ATTRIB_RUN_ONCE_VALUE
|
||||||
* @see #oncePerRequest
|
* @see #oncePerRequest
|
||||||
*/
|
*/
|
||||||
private final static String ATTRIB_RUN_ONCE_EXT = ".REQUEST_HANDLED";
|
private final static String ATTRIB_RUN_ONCE_EXT = ".REQUEST_HANDLED";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure the filter runs once per request.
|
* Makes sure the filter runs once per request.
|
||||||
* Must be configured through init method, as the filter name is not
|
* Must be configured through init method, as the filter name is not
|
||||||
* available before we have a {@code FilterConfig} object.
|
* available before we have a {@code FilterConfig} object.
|
||||||
* <p/>
|
* <p/>
|
||||||
* @see #isRunOnce
|
* @see #isRunOnce
|
||||||
* @see #ATTRIB_RUN_ONCE_VALUE
|
* @see #ATTRIB_RUN_ONCE_VALUE
|
||||||
* @see #oncePerRequest
|
* @see #oncePerRequest
|
||||||
*/
|
*/
|
||||||
private String attribRunOnce = null;
|
private String attribRunOnce = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure the filter runs once per request
|
* Makes sure the filter runs once per request
|
||||||
* <p/>
|
* <p/>
|
||||||
* @see #isRunOnce
|
* @see #isRunOnce
|
||||||
* @see #ATTRIB_RUN_ONCE_EXT
|
* @see #ATTRIB_RUN_ONCE_EXT
|
||||||
* @see #oncePerRequest
|
* @see #oncePerRequest
|
||||||
*/
|
*/
|
||||||
private static final Object ATTRIB_RUN_ONCE_VALUE = new Object();
|
private static final Object ATTRIB_RUN_ONCE_VALUE = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if this filter should run once per request ({@code true}),
|
* Indicates if this filter should run once per request ({@code true}),
|
||||||
* or for each forward/include resource ({@code false}).
|
* or for each forward/include resource ({@code false}).
|
||||||
* <p/>
|
* <p/>
|
||||||
* Set this variable to true, to make sure the filter runs once per request.
|
* Set this variable to true, to make sure the filter runs once per request.
|
||||||
*
|
*
|
||||||
* <em>NOTE: As of Servlet 2.4, this field
|
* <em>NOTE: As of Servlet 2.4, this field
|
||||||
* should always be left to it's default value ({@code false}).
|
* should always be left to it's default value ({@code false}).
|
||||||
* <br/>
|
* <br/>
|
||||||
* To run the filter once per request, the {@code filter-mapping} element
|
* To run the filter once per request, the {@code filter-mapping} element
|
||||||
* of the web-descriptor should include a {@code dispatcher} element:
|
* of the web-descriptor should include a {@code dispatcher} element:
|
||||||
* <pre><dispatcher>REQUEST</dispatcher></pre>
|
* <pre><dispatcher>REQUEST</dispatcher></pre>
|
||||||
* </em>
|
* </em>
|
||||||
*/
|
*/
|
||||||
protected boolean oncePerRequest = false;
|
protected boolean oncePerRequest = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does nothing.
|
* Does nothing.
|
||||||
*/
|
*/
|
||||||
public GenericFilter() {}
|
public GenericFilter() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the web container to indicate to a filter that it is being
|
* Called by the web container to indicate to a filter that it is being
|
||||||
* placed into service.
|
* placed into service.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This implementation stores the {@code FilterConfig} object it
|
* This implementation stores the {@code FilterConfig} object it
|
||||||
* receives from the servlet container for later use.
|
* receives from the servlet container for later use.
|
||||||
* Generally, there's no reason to override this method, override the
|
* Generally, there's no reason to override this method, override the
|
||||||
* no-argument {@code init} instead. However, <em>if</em> you are
|
* no-argument {@code init} instead. However, <em>if</em> you are
|
||||||
* overriding this form of the method,
|
* overriding this form of the method,
|
||||||
* always call {@code super.init(config)}.
|
* always call {@code super.init(config)}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This implementation will also set all configured key/value pairs, that
|
* This implementation will also set all configured key/value pairs, that
|
||||||
* have a matching setter method annotated with {@link InitParam}.
|
* have a matching setter method annotated with {@link InitParam}.
|
||||||
*
|
*
|
||||||
* @param pConfig the filter config
|
* @param pConfig the filter config
|
||||||
* @throws ServletException if an error occurs during init
|
* @throws ServletException if an error occurs during init
|
||||||
*
|
*
|
||||||
* @see Filter#init(javax.servlet.FilterConfig)
|
* @see Filter#init(javax.servlet.FilterConfig)
|
||||||
* @see #init() init
|
* @see #init() init
|
||||||
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
||||||
*/
|
*/
|
||||||
public void init(final FilterConfig pConfig) throws ServletException {
|
public void init(final FilterConfig pConfig) throws ServletException {
|
||||||
if (pConfig == null) {
|
if (pConfig == null) {
|
||||||
throw new ServletConfigException("filter config == null");
|
throw new ServletConfigException("filter config == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store filter config
|
// Store filter config
|
||||||
filterConfig = pConfig;
|
filterConfig = pConfig;
|
||||||
|
|
||||||
// Configure this
|
// Configure this
|
||||||
try {
|
try {
|
||||||
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException e) {
|
catch (InvocationTargetException e) {
|
||||||
throw new ServletConfigException("Could not configure " + getFilterName(), e.getCause());
|
throw new ServletConfigException("Could not configure " + getFilterName(), e.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create run-once attribute name
|
// Create run-once attribute name
|
||||||
attribRunOnce = pConfig.getFilterName() + ATTRIB_RUN_ONCE_EXT;
|
attribRunOnce = pConfig.getFilterName() + ATTRIB_RUN_ONCE_EXT;
|
||||||
log("init (oncePerRequest=" + oncePerRequest + ", attribRunOnce=" + attribRunOnce + ")");
|
log("init (oncePerRequest=" + oncePerRequest + ", attribRunOnce=" + attribRunOnce + ")");
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method which can be overridden so that there's no need to
|
* A convenience method which can be overridden so that there's no need to
|
||||||
* call {@code super.init(config)}.
|
* call {@code super.init(config)}.
|
||||||
*
|
*
|
||||||
* @see #init(FilterConfig)
|
* @see #init(FilterConfig)
|
||||||
*
|
*
|
||||||
* @throws ServletException if an error occurs during init
|
* @throws ServletException if an error occurs during init
|
||||||
*/
|
*/
|
||||||
public void init() throws ServletException {}
|
public void init() throws ServletException {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@code doFilter} method of the Filter is called by the container
|
* The {@code doFilter} method of the Filter is called by the container
|
||||||
* each time a request/response pair is passed through the chain due to a
|
* each time a request/response pair is passed through the chain due to a
|
||||||
* client request for a resource at the end of the chain.
|
* client request for a resource at the end of the chain.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Subclasses <em>should not override this method</em>, but rather the
|
* Subclasses <em>should not override this method</em>, but rather the
|
||||||
* abstract {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method.
|
* abstract {@link #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} doFilterImpl} method.
|
||||||
*
|
*
|
||||||
* @param pRequest the servlet request
|
* @param pRequest the servlet request
|
||||||
* @param pResponse the servlet response
|
* @param pResponse the servlet response
|
||||||
* @param pFilterChain the filter chain
|
* @param pFilterChain the filter chain
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*
|
*
|
||||||
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
||||||
* @see #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilterImpl
|
* @see #doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilterImpl
|
||||||
*/
|
*/
|
||||||
public final void doFilter(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pFilterChain) throws IOException, ServletException {
|
public final void doFilter(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pFilterChain) throws IOException, ServletException {
|
||||||
// If request filter and already run, continue chain and return fast
|
// If request filter and already run, continue chain and return fast
|
||||||
if (oncePerRequest && isRunOnce(pRequest)) {
|
if (oncePerRequest && isRunOnce(pRequest)) {
|
||||||
pFilterChain.doFilter(pRequest, pResponse);
|
pFilterChain.doFilter(pRequest, pResponse);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do real filter
|
// Do real filter
|
||||||
doFilterImpl(pRequest, pResponse, pFilterChain);
|
doFilterImpl(pRequest, pResponse, pFilterChain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If request is filtered, returns true, otherwise marks request as filtered
|
* If request is filtered, returns true, otherwise marks request as filtered
|
||||||
* and returns false.
|
* and returns false.
|
||||||
* A return value of false, indicates that the filter has not yet run.
|
* A return value of false, indicates that the filter has not yet run.
|
||||||
* A return value of true, indicates that the filter has run for this
|
* A return value of true, indicates that the filter has run for this
|
||||||
* request, and processing should not continue.
|
* request, and processing should not continue.
|
||||||
* <P/>
|
* <P/>
|
||||||
* Note that the method will mark the request as filtered on first
|
* Note that the method will mark the request as filtered on first
|
||||||
* invocation.
|
* invocation.
|
||||||
* <p/>
|
* <p/>
|
||||||
* @see #ATTRIB_RUN_ONCE_EXT
|
* @see #ATTRIB_RUN_ONCE_EXT
|
||||||
* @see #ATTRIB_RUN_ONCE_VALUE
|
* @see #ATTRIB_RUN_ONCE_VALUE
|
||||||
*
|
*
|
||||||
* @param pRequest the servlet request
|
* @param pRequest the servlet request
|
||||||
* @return {@code true} if the request is already filtered, otherwise
|
* @return {@code true} if the request is already filtered, otherwise
|
||||||
* {@code false}.
|
* {@code false}.
|
||||||
*/
|
*/
|
||||||
private boolean isRunOnce(final ServletRequest pRequest) {
|
private boolean isRunOnce(final ServletRequest pRequest) {
|
||||||
// If request already filtered, return true (skip)
|
// If request already filtered, return true (skip)
|
||||||
if (pRequest.getAttribute(attribRunOnce) == ATTRIB_RUN_ONCE_VALUE) {
|
if (pRequest.getAttribute(attribRunOnce) == ATTRIB_RUN_ONCE_VALUE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set attribute and return false (continue)
|
// Set attribute and return false (continue)
|
||||||
pRequest.setAttribute(attribRunOnce, ATTRIB_RUN_ONCE_VALUE);
|
pRequest.setAttribute(attribRunOnce, ATTRIB_RUN_ONCE_VALUE);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked once, or each time a request/response pair is passed through the
|
* Invoked once, or each time a request/response pair is passed through the
|
||||||
* chain, depending on the {@link #oncePerRequest} member variable.
|
* chain, depending on the {@link #oncePerRequest} member variable.
|
||||||
*
|
*
|
||||||
* @param pRequest the servlet request
|
* @param pRequest the servlet request
|
||||||
* @param pResponse the servlet response
|
* @param pResponse the servlet response
|
||||||
* @param pChain the filter chain
|
* @param pChain the filter chain
|
||||||
*
|
*
|
||||||
* @throws IOException if an I/O error occurs
|
* @throws IOException if an I/O error occurs
|
||||||
* @throws ServletException if an exception occurs during the filter process
|
* @throws ServletException if an exception occurs during the filter process
|
||||||
*
|
*
|
||||||
* @see #oncePerRequest
|
* @see #oncePerRequest
|
||||||
* @see #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilter
|
* @see #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilter
|
||||||
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
||||||
*/
|
*/
|
||||||
protected abstract void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
|
protected abstract void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
|
||||||
throws IOException, ServletException;
|
throws IOException, ServletException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the web container to indicate to a filter that it is being
|
* Called by the web container to indicate to a filter that it is being
|
||||||
* taken out of service.
|
* taken out of service.
|
||||||
*
|
*
|
||||||
* @see Filter#destroy
|
* @see Filter#destroy
|
||||||
*/
|
*/
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
log("destroy");
|
log("destroy");
|
||||||
filterConfig = null;
|
filterConfig = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the filter-name of this filter as defined in the deployment
|
* Returns the filter-name of this filter as defined in the deployment
|
||||||
* descriptor.
|
* descriptor.
|
||||||
*
|
*
|
||||||
* @return the filter-name
|
* @return the filter-name
|
||||||
* @see FilterConfig#getFilterName
|
* @see FilterConfig#getFilterName
|
||||||
*/
|
*/
|
||||||
public String getFilterName() {
|
public String getFilterName() {
|
||||||
return filterConfig.getFilterName();
|
return filterConfig.getFilterName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a reference to the {@link ServletContext} in which the caller is
|
* Returns a reference to the {@link ServletContext} in which the caller is
|
||||||
* executing.
|
* executing.
|
||||||
*
|
*
|
||||||
* @return the {@code ServletContext} object, used by the caller to
|
* @return the {@code ServletContext} object, used by the caller to
|
||||||
* interact with its servlet container
|
* interact with its servlet container
|
||||||
* @see FilterConfig#getServletContext
|
* @see FilterConfig#getServletContext
|
||||||
* @see ServletContext
|
* @see ServletContext
|
||||||
*/
|
*/
|
||||||
public ServletContext getServletContext() {
|
public ServletContext getServletContext() {
|
||||||
return filterConfig.getServletContext();
|
return filterConfig.getServletContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@code String} containing the value of the named
|
* Returns a {@code String} containing the value of the named
|
||||||
* initialization parameter, or null if the parameter does not exist.
|
* initialization parameter, or null if the parameter does not exist.
|
||||||
*
|
*
|
||||||
* @param pKey a {@code String} specifying the name of the
|
* @param pKey a {@code String} specifying the name of the
|
||||||
* initialization parameter
|
* initialization parameter
|
||||||
* @return a {@code String} containing the value of the initialization
|
* @return a {@code String} containing the value of the initialization
|
||||||
* parameter
|
* parameter
|
||||||
*/
|
*/
|
||||||
public String getInitParameter(final String pKey) {
|
public String getInitParameter(final String pKey) {
|
||||||
return filterConfig.getInitParameter(pKey);
|
return filterConfig.getInitParameter(pKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the names of the servlet's initialization parameters as an
|
* Returns the names of the servlet's initialization parameters as an
|
||||||
* {@code Enumeration} of {@code String} objects, or an empty
|
* {@code Enumeration} of {@code String} objects, or an empty
|
||||||
* {@code Enumeration} if the servlet has no initialization parameters.
|
* {@code Enumeration} if the servlet has no initialization parameters.
|
||||||
*
|
*
|
||||||
* @return an {@code Enumeration} of {@code String} objects
|
* @return an {@code Enumeration} of {@code String} objects
|
||||||
* containing the mNames of the servlet's initialization parameters
|
* containing the mNames of the servlet's initialization parameters
|
||||||
*/
|
*/
|
||||||
public Enumeration getInitParameterNames() {
|
public Enumeration getInitParameterNames() {
|
||||||
return filterConfig.getInitParameterNames();
|
return filterConfig.getInitParameterNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the specified message to a servlet log file, prepended by the
|
* Writes the specified message to a servlet log file, prepended by the
|
||||||
* filter's name.
|
* filter's name.
|
||||||
*
|
*
|
||||||
* @param pMessage the log message
|
* @param pMessage the log message
|
||||||
* @see ServletContext#log(String)
|
* @see ServletContext#log(String)
|
||||||
*/
|
*/
|
||||||
protected void log(final String pMessage) {
|
protected void log(final String pMessage) {
|
||||||
getServletContext().log(getFilterName() + ": " + pMessage);
|
getServletContext().log(getFilterName() + ": " + pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes an explanatory message and a stack trace for a given
|
* Writes an explanatory message and a stack trace for a given
|
||||||
* {@code Throwable} to the servlet log file, prepended by the
|
* {@code Throwable} to the servlet log file, prepended by the
|
||||||
* filter's name.
|
* filter's name.
|
||||||
*
|
*
|
||||||
* @param pMessage the log message
|
* @param pMessage the log message
|
||||||
* @param pThrowable the exception
|
* @param pThrowable the exception
|
||||||
* @see ServletContext#log(String,Throwable)
|
* @see ServletContext#log(String,Throwable)
|
||||||
*/
|
*/
|
||||||
protected void log(final String pMessage, final Throwable pThrowable) {
|
protected void log(final String pMessage, final Throwable pThrowable) {
|
||||||
getServletContext().log(getFilterName() + ": " + pMessage, pThrowable);
|
getServletContext().log(getFilterName() + ": " + pMessage, pThrowable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the filter.
|
* Initializes the filter.
|
||||||
*
|
*
|
||||||
* @param pFilterConfig the filter config
|
* @param pFilterConfig the filter config
|
||||||
* @see #init init
|
* @see #init init
|
||||||
*
|
*
|
||||||
* @deprecated For compatibility only, use {@link #init init} instead.
|
* @deprecated For compatibility only, use {@link #init init} instead.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
public void setFilterConfig(final FilterConfig pFilterConfig) {
|
public void setFilterConfig(final FilterConfig pFilterConfig) {
|
||||||
try {
|
try {
|
||||||
init(pFilterConfig);
|
init(pFilterConfig);
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
log("Error in init(), see stack trace for details.", e);
|
log("Error in init(), see stack trace for details.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@code FilterConfig} for this filter.
|
* Gets the {@code FilterConfig} for this filter.
|
||||||
*
|
*
|
||||||
* @return the {@code FilterConfig} for this filter
|
* @return the {@code FilterConfig} for this filter
|
||||||
* @see FilterConfig
|
* @see FilterConfig
|
||||||
*/
|
*/
|
||||||
public FilterConfig getFilterConfig() {
|
public FilterConfig getFilterConfig() {
|
||||||
return filterConfig;
|
return filterConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies if this filter should run once per request ({@code true}),
|
* Specifies if this filter should run once per request ({@code true}),
|
||||||
* or for each forward/include resource ({@code false}).
|
* or for each forward/include resource ({@code false}).
|
||||||
* Called automatically from the {@code init}-method, with settings
|
* Called automatically from the {@code init}-method, with settings
|
||||||
* from web.xml.
|
* from web.xml.
|
||||||
*
|
*
|
||||||
* @param pOncePerRequest {@code true} if the filter should run only
|
* @param pOncePerRequest {@code true} if the filter should run only
|
||||||
* once per request
|
* once per request
|
||||||
* @see #oncePerRequest
|
* @see #oncePerRequest
|
||||||
*/
|
*/
|
||||||
@InitParam(name = "once-per-request")
|
@InitParam(name = "once-per-request")
|
||||||
public void setOncePerRequest(final boolean pOncePerRequest) {
|
public void setOncePerRequest(final boolean pOncePerRequest) {
|
||||||
oncePerRequest = pOncePerRequest;
|
oncePerRequest = pOncePerRequest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +1,88 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.BeanUtil;
|
import com.twelvemonkeys.lang.BeanUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a generic, protocol-independent servlet.
|
* Defines a generic, protocol-independent servlet.
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@code GenericServlet} has an auto-init system, that automatically invokes
|
* {@code GenericServlet} has an auto-init system, that automatically invokes
|
||||||
* the method matching the signature {@code void setX(<Type>)},
|
* the method matching the signature {@code void setX(<Type>)},
|
||||||
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
||||||
* naming is supported, lisp-style names will be converted to camelCase.
|
* naming is supported, lisp-style names will be converted to camelCase.
|
||||||
* Parameter values are automatically converted from string representation to
|
* Parameter values are automatically converted from string representation to
|
||||||
* most basic types, if necessary.
|
* most basic types, if necessary.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Id: GenericServlet.java#1 $
|
* @version $Id: GenericServlet.java#1 $
|
||||||
*/
|
*/
|
||||||
public abstract class GenericServlet extends javax.servlet.GenericServlet {
|
public abstract class GenericServlet extends javax.servlet.GenericServlet {
|
||||||
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the web container to indicate to a servlet that it is being
|
* Called by the web container to indicate to a servlet that it is being
|
||||||
* placed into service.
|
* placed into service.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This implementation stores the {@code ServletConfig} object it
|
* This implementation stores the {@code ServletConfig} object it
|
||||||
* receives from the servlet container for later use. When overriding this
|
* receives from the servlet container for later use. When overriding this
|
||||||
* form of the method, call {@code super.init(config)}.
|
* form of the method, call {@code super.init(config)}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This implementation will also set all configured key/value pairs, that
|
* This implementation will also set all configured key/value pairs, that
|
||||||
* have a matching setter method annotated with {@link InitParam}.
|
* have a matching setter method annotated with {@link InitParam}.
|
||||||
*
|
*
|
||||||
* @param pConfig the servlet config
|
* @param pConfig the servlet config
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*
|
*
|
||||||
* @see javax.servlet.GenericServlet#init
|
* @see javax.servlet.GenericServlet#init
|
||||||
* @see #init() init
|
* @see #init() init
|
||||||
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void init(final ServletConfig pConfig) throws ServletException {
|
public void init(final ServletConfig pConfig) throws ServletException {
|
||||||
if (pConfig == null) {
|
if (pConfig == null) {
|
||||||
throw new ServletConfigException("servlet config == null");
|
throw new ServletConfigException("servlet config == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException e) {
|
catch (InvocationTargetException e) {
|
||||||
throw new ServletConfigException("Could not configure " + getServletName(), e.getCause());
|
throw new ServletConfigException("Could not configure " + getServletName(), e.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init(pConfig);
|
super.init(pConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +1,88 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.BeanUtil;
|
import com.twelvemonkeys.lang.BeanUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a generic, HTTP specific servlet.
|
* Defines a generic, HTTP specific servlet.
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@code HttpServlet} has an auto-init system, that automatically invokes
|
* {@code HttpServlet} has an auto-init system, that automatically invokes
|
||||||
* the method matching the signature {@code void setX(<Type>)},
|
* the method matching the signature {@code void setX(<Type>)},
|
||||||
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
* for every init-parameter {@code x}. Both camelCase and lisp-style parameter
|
||||||
* naming is supported, lisp-style names will be converted to camelCase.
|
* naming is supported, lisp-style names will be converted to camelCase.
|
||||||
* Parameter values are automatically converted from string representation to
|
* Parameter values are automatically converted from string representation to
|
||||||
* most basic types, if necessary.
|
* most basic types, if necessary.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Id: HttpServlet.java#1 $
|
* @version $Id: HttpServlet.java#1 $
|
||||||
*/
|
*/
|
||||||
public abstract class HttpServlet extends javax.servlet.http.HttpServlet {
|
public abstract class HttpServlet extends javax.servlet.http.HttpServlet {
|
||||||
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
// TODO: Rewrite to use ServletConfigurator instead of BeanUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the web container to indicate to a servlet that it is being
|
* Called by the web container to indicate to a servlet that it is being
|
||||||
* placed into service.
|
* placed into service.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This implementation stores the {@code ServletConfig} object it
|
* This implementation stores the {@code ServletConfig} object it
|
||||||
* receives from the servlet container for later use. When overriding this
|
* receives from the servlet container for later use. When overriding this
|
||||||
* form of the method, call {@code super.init(config)}.
|
* form of the method, call {@code super.init(config)}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This implementation will also set all configured key/value pairs, that
|
* This implementation will also set all configured key/value pairs, that
|
||||||
* have a matching setter method annotated with {@link InitParam}.
|
* have a matching setter method annotated with {@link InitParam}.
|
||||||
*
|
*
|
||||||
* @param pConfig the servlet config
|
* @param pConfig the servlet config
|
||||||
* @throws ServletException if an error occurred during init
|
* @throws ServletException if an error occurred during init
|
||||||
*
|
*
|
||||||
* @see javax.servlet.GenericServlet#init
|
* @see javax.servlet.GenericServlet#init
|
||||||
* @see #init() init
|
* @see #init() init
|
||||||
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
* @see BeanUtil#configure(Object, java.util.Map, boolean)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void init(ServletConfig pConfig) throws ServletException {
|
public void init(ServletConfig pConfig) throws ServletException {
|
||||||
if (pConfig == null) {
|
if (pConfig == null) {
|
||||||
throw new ServletConfigException("servlet config == null");
|
throw new ServletConfigException("servlet config == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
BeanUtil.configure(this, ServletUtil.asMap(pConfig), true);
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException e) {
|
catch (InvocationTargetException e) {
|
||||||
throw new ServletConfigException("Could not configure " + getServletName(), e.getCause());
|
throw new ServletConfigException("Could not configure " + getServletName(), e.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init(pConfig);
|
super.init(pConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,120 +1,120 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@code ServletOutputStream} implementation backed by a
|
* A {@code ServletOutputStream} implementation backed by a
|
||||||
* {@link java.io.OutputStream}. For filters that need to buffer the
|
* {@link java.io.OutputStream}. For filters that need to buffer the
|
||||||
* response and do post filtering, it may be used like this:<pre>
|
* response and do post filtering, it may be used like this:<pre>
|
||||||
* ByteArrayOutputStream buffer = new ByteArraOutputStream();
|
* ByteArrayOutputStream buffer = new ByteArraOutputStream();
|
||||||
* ServletOutputStream adapter = new OutputStreamAdapter(buffer);
|
* ServletOutputStream adapter = new OutputStreamAdapter(buffer);
|
||||||
* </pre>
|
* </pre>
|
||||||
* <p/>
|
* <p/>
|
||||||
* As a {@code ServletOutputStream} is itself an {@code OutputStream}, this
|
* As a {@code ServletOutputStream} is itself an {@code OutputStream}, this
|
||||||
* class may also be used as a superclass for wrappers of other
|
* class may also be used as a superclass for wrappers of other
|
||||||
* {@code ServletOutputStream}s, like this:<pre>
|
* {@code ServletOutputStream}s, like this:<pre>
|
||||||
* class FilterServletOutputStream extends OutputStreamAdapter {
|
* class FilterServletOutputStream extends OutputStreamAdapter {
|
||||||
* public FilterServletOutputStream(ServletOutputStream out) {
|
* public FilterServletOutputStream(ServletOutputStream out) {
|
||||||
* super(out);
|
* super(out);
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* public void write(int abyte) {
|
* public void write(int abyte) {
|
||||||
* // do filtering...
|
* // do filtering...
|
||||||
* super.write(...);
|
* super.write(...);
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* ...
|
* ...
|
||||||
*
|
*
|
||||||
* ServletOutputStream original = response.getOutputStream();
|
* ServletOutputStream original = response.getOutputStream();
|
||||||
* ServletOutputStream wrapper = new FilterServletOutputStream(original);
|
* ServletOutputStream wrapper = new FilterServletOutputStream(original);
|
||||||
* </pre>
|
* </pre>
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author $Author: haku $
|
* @author $Author: haku $
|
||||||
* @version $Id: OutputStreamAdapter.java#1 $
|
* @version $Id: OutputStreamAdapter.java#1 $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class OutputStreamAdapter extends ServletOutputStream {
|
public class OutputStreamAdapter extends ServletOutputStream {
|
||||||
|
|
||||||
/** The wrapped {@code OutputStream}. */
|
/** The wrapped {@code OutputStream}. */
|
||||||
protected final OutputStream out;
|
protected final OutputStream out;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@code OutputStreamAdapter}.
|
* Creates an {@code OutputStreamAdapter}.
|
||||||
*
|
*
|
||||||
* @param pOut the wrapped {@code OutputStream}
|
* @param pOut the wrapped {@code OutputStream}
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if {@code pOut} is {@code null}.
|
* @throws IllegalArgumentException if {@code pOut} is {@code null}.
|
||||||
*/
|
*/
|
||||||
public OutputStreamAdapter(final OutputStream pOut) {
|
public OutputStreamAdapter(final OutputStream pOut) {
|
||||||
Validate.notNull(pOut, "out");
|
Validate.notNull(pOut, "out");
|
||||||
out = pOut;
|
out = pOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the wrapped {@code OutputStream}.
|
* Returns the wrapped {@code OutputStream}.
|
||||||
*
|
*
|
||||||
* @return the wrapped {@code OutputStream}.
|
* @return the wrapped {@code OutputStream}.
|
||||||
*/
|
*/
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ServletOutputStream adapted from " + out.toString();
|
return "ServletOutputStream adapted from " + out.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a byte to the underlying stream.
|
* Writes a byte to the underlying stream.
|
||||||
*
|
*
|
||||||
* @param pByte the byte to write.
|
* @param pByte the byte to write.
|
||||||
*
|
*
|
||||||
* @throws IOException if an error occurs during writing
|
* @throws IOException if an error occurs during writing
|
||||||
*/
|
*/
|
||||||
public void write(final int pByte) throws IOException {
|
public void write(final int pByte) throws IOException {
|
||||||
out.write(pByte);
|
out.write(pByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overide for efficiency
|
// Overide for efficiency
|
||||||
public void write(final byte pBytes[]) throws IOException {
|
public void write(final byte pBytes[]) throws IOException {
|
||||||
out.write(pBytes);
|
out.write(pBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overide for efficiency
|
// Overide for efficiency
|
||||||
public void write(final byte pBytes[], final int pOff, final int pLen) throws IOException {
|
public void write(final byte pBytes[], final int pOff, final int pLen) throws IOException {
|
||||||
out.write(pBytes, pOff, pLen);
|
out.write(pBytes, pOff, pLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,435 +1,435 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.io.FileUtil;
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple proxy servlet implementation. Supports HTTP and HTTPS.
|
* A simple proxy servlet implementation. Supports HTTP and HTTPS.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note: The servlet is not a true HTTP proxy as described in
|
* Note: The servlet is not a true HTTP proxy as described in
|
||||||
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">RFC 2616</a>,
|
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">RFC 2616</a>,
|
||||||
* instead it passes on all incoming HTTP requests to the configured remote
|
* instead it passes on all incoming HTTP requests to the configured remote
|
||||||
* server.
|
* server.
|
||||||
* Useful for bypassing firewalls or to avoid exposing internal network
|
* Useful for bypassing firewalls or to avoid exposing internal network
|
||||||
* infrastructure to external clients.
|
* infrastructure to external clients.
|
||||||
* <p/>
|
* <p/>
|
||||||
* At the moment, no caching of content is implemented.
|
* At the moment, no caching of content is implemented.
|
||||||
* <p/>
|
* <p/>
|
||||||
* If the {@code remoteServer} init parameter is not set, the servlet will
|
* If the {@code remoteServer} init parameter is not set, the servlet will
|
||||||
* respond by sending a {@code 500 Internal Server Error} response to the client.
|
* respond by sending a {@code 500 Internal Server Error} response to the client.
|
||||||
* If the configured remote server is down, or unreachable, the servlet will
|
* If the configured remote server is down, or unreachable, the servlet will
|
||||||
* respond by sending a {@code 502 Bad Gateway} response to the client.
|
* respond by sending a {@code 502 Bad Gateway} response to the client.
|
||||||
* Otherwise, the response from the remote server will be tunneled unmodified
|
* Otherwise, the response from the remote server will be tunneled unmodified
|
||||||
* to the client.
|
* to the client.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Id: ProxyServlet.java#1 $
|
* @version $Id: ProxyServlet.java#1 $
|
||||||
*/
|
*/
|
||||||
public class ProxyServlet extends GenericServlet {
|
public class ProxyServlet extends GenericServlet {
|
||||||
|
|
||||||
/** Remote server host name or IP address */
|
/** Remote server host name or IP address */
|
||||||
protected String remoteServer = null;
|
protected String remoteServer = null;
|
||||||
/** Remote server port */
|
/** Remote server port */
|
||||||
protected int remotePort = 80;
|
protected int remotePort = 80;
|
||||||
/** Remote server "mount" path */
|
/** Remote server "mount" path */
|
||||||
protected String remotePath = "";
|
protected String remotePath = "";
|
||||||
|
|
||||||
private static final String HTTP_REQUEST_HEADER_HOST = "host";
|
private static final String HTTP_REQUEST_HEADER_HOST = "host";
|
||||||
private static final String HTTP_RESPONSE_HEADER_SERVER = "server";
|
private static final String HTTP_RESPONSE_HEADER_SERVER = "server";
|
||||||
private static final String MESSAGE_REMOTE_SERVER_NOT_CONFIGURED = "Remote server not configured.";
|
private static final String MESSAGE_REMOTE_SERVER_NOT_CONFIGURED = "Remote server not configured.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by {@code init} to set the remote server. Must be a valid host
|
* Called by {@code init} to set the remote server. Must be a valid host
|
||||||
* name or IP address. No default.
|
* name or IP address. No default.
|
||||||
*
|
*
|
||||||
* @param pRemoteServer
|
* @param pRemoteServer
|
||||||
*/
|
*/
|
||||||
public void setRemoteServer(String pRemoteServer) {
|
public void setRemoteServer(String pRemoteServer) {
|
||||||
remoteServer = pRemoteServer;
|
remoteServer = pRemoteServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by {@code init} to set the remote port. Must be a number.
|
* Called by {@code init} to set the remote port. Must be a number.
|
||||||
* Default is {@code 80}.
|
* Default is {@code 80}.
|
||||||
*
|
*
|
||||||
* @param pRemotePort
|
* @param pRemotePort
|
||||||
*/
|
*/
|
||||||
public void setRemotePort(String pRemotePort) {
|
public void setRemotePort(String pRemotePort) {
|
||||||
try {
|
try {
|
||||||
remotePort = Integer.parseInt(pRemotePort);
|
remotePort = Integer.parseInt(pRemotePort);
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
log("RemotePort must be a number!", e);
|
log("RemotePort must be a number!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by {@code init} to set the remote path. May be an empty string
|
* Called by {@code init} to set the remote path. May be an empty string
|
||||||
* for the root path, or any other valid path on the remote server.
|
* for the root path, or any other valid path on the remote server.
|
||||||
* Default is {@code ""}.
|
* Default is {@code ""}.
|
||||||
*
|
*
|
||||||
* @param pRemotePath
|
* @param pRemotePath
|
||||||
*/
|
*/
|
||||||
public void setRemotePath(String pRemotePath) {
|
public void setRemotePath(String pRemotePath) {
|
||||||
if (StringUtil.isEmpty(pRemotePath)) {
|
if (StringUtil.isEmpty(pRemotePath)) {
|
||||||
pRemotePath = "";
|
pRemotePath = "";
|
||||||
}
|
}
|
||||||
else if (pRemotePath.charAt(0) != '/') {
|
else if (pRemotePath.charAt(0) != '/') {
|
||||||
pRemotePath = "/" + pRemotePath;
|
pRemotePath = "/" + pRemotePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
remotePath = pRemotePath;
|
remotePath = pRemotePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override {@code service} to use HTTP specifics.
|
* Override {@code service} to use HTTP specifics.
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
*
|
*
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*
|
*
|
||||||
* @see #service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
* @see #service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||||
*/
|
*/
|
||||||
public final void service(ServletRequest pRequest, ServletResponse pResponse) throws ServletException, IOException {
|
public final void service(ServletRequest pRequest, ServletResponse pResponse) throws ServletException, IOException {
|
||||||
service((HttpServletRequest) pRequest, (HttpServletResponse) pResponse);
|
service((HttpServletRequest) pRequest, (HttpServletResponse) pResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Services a single request.
|
* Services a single request.
|
||||||
* Supports HTTP and HTTPS.
|
* Supports HTTP and HTTPS.
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
*
|
*
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*
|
*
|
||||||
* @see ProxyServlet Class descrition
|
* @see ProxyServlet Class descrition
|
||||||
*/
|
*/
|
||||||
protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
||||||
// Sanity check configuration
|
// Sanity check configuration
|
||||||
if (remoteServer == null) {
|
if (remoteServer == null) {
|
||||||
log(MESSAGE_REMOTE_SERVER_NOT_CONFIGURED);
|
log(MESSAGE_REMOTE_SERVER_NOT_CONFIGURED);
|
||||||
pResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
|
pResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
|
||||||
MESSAGE_REMOTE_SERVER_NOT_CONFIGURED);
|
MESSAGE_REMOTE_SERVER_NOT_CONFIGURED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpURLConnection remoteConnection = null;
|
HttpURLConnection remoteConnection = null;
|
||||||
try {
|
try {
|
||||||
// Recreate request URI for remote request
|
// Recreate request URI for remote request
|
||||||
String requestURI = createRemoteRequestURI(pRequest);
|
String requestURI = createRemoteRequestURI(pRequest);
|
||||||
URL remoteURL = new URL(pRequest.getScheme(), remoteServer, remotePort, requestURI);
|
URL remoteURL = new URL(pRequest.getScheme(), remoteServer, remotePort, requestURI);
|
||||||
|
|
||||||
// Get connection, with method from original request
|
// Get connection, with method from original request
|
||||||
// NOTE: The actual connection is not done before we ask for streams...
|
// NOTE: The actual connection is not done before we ask for streams...
|
||||||
// NOTE: The HttpURLConnection is supposed to handle multiple
|
// NOTE: The HttpURLConnection is supposed to handle multiple
|
||||||
// requests to the same server internally
|
// requests to the same server internally
|
||||||
String method = pRequest.getMethod();
|
String method = pRequest.getMethod();
|
||||||
remoteConnection = (HttpURLConnection) remoteURL.openConnection();
|
remoteConnection = (HttpURLConnection) remoteURL.openConnection();
|
||||||
remoteConnection.setRequestMethod(method);
|
remoteConnection.setRequestMethod(method);
|
||||||
|
|
||||||
// Copy header fields
|
// Copy header fields
|
||||||
copyHeadersFromClient(pRequest, remoteConnection);
|
copyHeadersFromClient(pRequest, remoteConnection);
|
||||||
|
|
||||||
// Do proxy specifc stuff?
|
// Do proxy specifc stuff?
|
||||||
// TODO: Read up the specs from RFC 2616 (HTTP) on proxy behaviour
|
// TODO: Read up the specs from RFC 2616 (HTTP) on proxy behaviour
|
||||||
// TODO: RFC 2616 says "[a] proxy server MUST NOT establish an HTTP/1.1
|
// TODO: RFC 2616 says "[a] proxy server MUST NOT establish an HTTP/1.1
|
||||||
// persistent connection with an HTTP/1.0 client"
|
// persistent connection with an HTTP/1.0 client"
|
||||||
|
|
||||||
// Copy message body from client to remote server
|
// Copy message body from client to remote server
|
||||||
copyBodyFromClient(pRequest, remoteConnection);
|
copyBodyFromClient(pRequest, remoteConnection);
|
||||||
|
|
||||||
// Set response status code from remote server to client
|
// Set response status code from remote server to client
|
||||||
int responseCode = remoteConnection.getResponseCode();
|
int responseCode = remoteConnection.getResponseCode();
|
||||||
pResponse.setStatus(responseCode);
|
pResponse.setStatus(responseCode);
|
||||||
//System.out.println("Response is: " + responseCode + " " + remoteConnection.getResponseMessage());
|
//System.out.println("Response is: " + responseCode + " " + remoteConnection.getResponseMessage());
|
||||||
|
|
||||||
// Copy header fields back
|
// Copy header fields back
|
||||||
copyHeadersToClient(remoteConnection, pResponse);
|
copyHeadersToClient(remoteConnection, pResponse);
|
||||||
|
|
||||||
// More proxy specific stuff?
|
// More proxy specific stuff?
|
||||||
|
|
||||||
// Copy message body from remote server to client
|
// Copy message body from remote server to client
|
||||||
copyBodyToClient(remoteConnection, pResponse);
|
copyBodyToClient(remoteConnection, pResponse);
|
||||||
}
|
}
|
||||||
catch (ConnectException e) {
|
catch (ConnectException e) {
|
||||||
// In case we could not connecto to the remote server
|
// In case we could not connecto to the remote server
|
||||||
log("Could not connect to remote server.", e);
|
log("Could not connect to remote server.", e);
|
||||||
pResponse.sendError(HttpServletResponse.SC_BAD_GATEWAY, e.getMessage());
|
pResponse.sendError(HttpServletResponse.SC_BAD_GATEWAY, e.getMessage());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Disconnect from server
|
// Disconnect from server
|
||||||
// TODO: Should we actually do this?
|
// TODO: Should we actually do this?
|
||||||
if (remoteConnection != null) {
|
if (remoteConnection != null) {
|
||||||
remoteConnection.disconnect();
|
remoteConnection.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the message body from the remote server to the client (outgoing
|
* Copies the message body from the remote server to the client (outgoing
|
||||||
* {@code HttpServletResponse}).
|
* {@code HttpServletResponse}).
|
||||||
*
|
*
|
||||||
* @param pRemoteConnection
|
* @param pRemoteConnection
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void copyBodyToClient(HttpURLConnection pRemoteConnection, HttpServletResponse pResponse) throws IOException {
|
private void copyBodyToClient(HttpURLConnection pRemoteConnection, HttpServletResponse pResponse) throws IOException {
|
||||||
InputStream fromRemote = null;
|
InputStream fromRemote = null;
|
||||||
OutputStream toClient = null;
|
OutputStream toClient = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get either input or error stream
|
// Get either input or error stream
|
||||||
try {
|
try {
|
||||||
fromRemote = pRemoteConnection.getInputStream();
|
fromRemote = pRemoteConnection.getInputStream();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// If exception, use errorStream instead
|
// If exception, use errorStream instead
|
||||||
fromRemote = pRemoteConnection.getErrorStream();
|
fromRemote = pRemoteConnection.getErrorStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
// I guess the stream might be null if there is no response other
|
// I guess the stream might be null if there is no response other
|
||||||
// than headers (Continue, No Content, etc).
|
// than headers (Continue, No Content, etc).
|
||||||
if (fromRemote != null) {
|
if (fromRemote != null) {
|
||||||
toClient = pResponse.getOutputStream();
|
toClient = pResponse.getOutputStream();
|
||||||
FileUtil.copy(fromRemote, toClient);
|
FileUtil.copy(fromRemote, toClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (fromRemote != null) {
|
if (fromRemote != null) {
|
||||||
try {
|
try {
|
||||||
fromRemote.close();
|
fromRemote.close();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
log("Stream from remote could not be closed.", e);
|
log("Stream from remote could not be closed.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (toClient != null) {
|
if (toClient != null) {
|
||||||
try {
|
try {
|
||||||
toClient.close();
|
toClient.close();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
log("Stream to client could not be closed.", e);
|
log("Stream to client could not be closed.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the message body from the client (incomming
|
* Copies the message body from the client (incomming
|
||||||
* {@code HttpServletRequest}) to the remote server if the request method
|
* {@code HttpServletRequest}) to the remote server if the request method
|
||||||
* is {@code POST} or <tt>PUT<tt>.
|
* is {@code POST} or <tt>PUT<tt>.
|
||||||
* Otherwise this method does nothing.
|
* Otherwise this method does nothing.
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pRemoteConnection
|
* @param pRemoteConnection
|
||||||
*
|
*
|
||||||
* @throws java.io.IOException
|
* @throws java.io.IOException
|
||||||
*/
|
*/
|
||||||
private void copyBodyFromClient(HttpServletRequest pRequest, HttpURLConnection pRemoteConnection) throws IOException {
|
private void copyBodyFromClient(HttpServletRequest pRequest, HttpURLConnection pRemoteConnection) throws IOException {
|
||||||
// If this is a POST or PUT, copy message body from client remote server
|
// If this is a POST or PUT, copy message body from client remote server
|
||||||
if (!("POST".equals(pRequest.getMethod()) || "PUT".equals(pRequest.getMethod()))) {
|
if (!("POST".equals(pRequest.getMethod()) || "PUT".equals(pRequest.getMethod()))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Setting doOutput to true, will make it a POST request (why?)...
|
// NOTE: Setting doOutput to true, will make it a POST request (why?)...
|
||||||
pRemoteConnection.setDoOutput(true);
|
pRemoteConnection.setDoOutput(true);
|
||||||
|
|
||||||
// Get streams and do the copying
|
// Get streams and do the copying
|
||||||
InputStream fromClient = null;
|
InputStream fromClient = null;
|
||||||
OutputStream toRemote = null;
|
OutputStream toRemote = null;
|
||||||
try {
|
try {
|
||||||
fromClient = pRequest.getInputStream();
|
fromClient = pRequest.getInputStream();
|
||||||
toRemote = pRemoteConnection.getOutputStream();
|
toRemote = pRemoteConnection.getOutputStream();
|
||||||
FileUtil.copy(fromClient, toRemote);
|
FileUtil.copy(fromClient, toRemote);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (fromClient != null) {
|
if (fromClient != null) {
|
||||||
try {
|
try {
|
||||||
fromClient.close();
|
fromClient.close();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
log("Stream from client could not be closed.", e);
|
log("Stream from client could not be closed.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (toRemote != null) {
|
if (toRemote != null) {
|
||||||
try {
|
try {
|
||||||
toRemote.close();
|
toRemote.close();
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
log("Stream to remote could not be closed.", e);
|
log("Stream to remote could not be closed.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the remote request URI based on the incoming request.
|
* Creates the remote request URI based on the incoming request.
|
||||||
* The URI will include any query strings etc.
|
* The URI will include any query strings etc.
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
*
|
*
|
||||||
* @return a {@code String} representing the remote request URI
|
* @return a {@code String} representing the remote request URI
|
||||||
*/
|
*/
|
||||||
private String createRemoteRequestURI(HttpServletRequest pRequest) {
|
private String createRemoteRequestURI(HttpServletRequest pRequest) {
|
||||||
StringBuilder requestURI = new StringBuilder(remotePath);
|
StringBuilder requestURI = new StringBuilder(remotePath);
|
||||||
requestURI.append(pRequest.getPathInfo());
|
requestURI.append(pRequest.getPathInfo());
|
||||||
|
|
||||||
if (!StringUtil.isEmpty(pRequest.getQueryString())) {
|
if (!StringUtil.isEmpty(pRequest.getQueryString())) {
|
||||||
requestURI.append("?");
|
requestURI.append("?");
|
||||||
requestURI.append(pRequest.getQueryString());
|
requestURI.append(pRequest.getQueryString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return requestURI.toString();
|
return requestURI.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies headers from the remote connection back to the client
|
* Copies headers from the remote connection back to the client
|
||||||
* (the outgoing HttpServletResponse). All headers except the "Server"
|
* (the outgoing HttpServletResponse). All headers except the "Server"
|
||||||
* header are copied.
|
* header are copied.
|
||||||
*
|
*
|
||||||
* @param pRemoteConnection
|
* @param pRemoteConnection
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
*/
|
*/
|
||||||
private void copyHeadersToClient(HttpURLConnection pRemoteConnection, HttpServletResponse pResponse) {
|
private void copyHeadersToClient(HttpURLConnection pRemoteConnection, HttpServletResponse pResponse) {
|
||||||
// NOTE: There is no getHeaderFieldCount method or similar...
|
// NOTE: There is no getHeaderFieldCount method or similar...
|
||||||
// Also, the getHeaderFields() method was introduced in J2SE 1.4, and
|
// Also, the getHeaderFields() method was introduced in J2SE 1.4, and
|
||||||
// we want to be 1.2 compatible.
|
// we want to be 1.2 compatible.
|
||||||
// So, just try to loop until there are no more headers.
|
// So, just try to loop until there are no more headers.
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
String key = pRemoteConnection.getHeaderFieldKey(i);
|
String key = pRemoteConnection.getHeaderFieldKey(i);
|
||||||
// NOTE: getHeaderField(String) returns only the last value
|
// NOTE: getHeaderField(String) returns only the last value
|
||||||
String value = pRemoteConnection.getHeaderField(i);
|
String value = pRemoteConnection.getHeaderField(i);
|
||||||
|
|
||||||
// If the key is not null, life is simple, and Sun is shining
|
// If the key is not null, life is simple, and Sun is shining
|
||||||
// However, the default implementations includes the HTTP response
|
// However, the default implementations includes the HTTP response
|
||||||
// code ("HTTP/1.1 200 Ok" or similar) as a header field with
|
// code ("HTTP/1.1 200 Ok" or similar) as a header field with
|
||||||
// key "null" (why..?)...
|
// key "null" (why..?)...
|
||||||
// In addition, we want to skip the original "Server" header
|
// In addition, we want to skip the original "Server" header
|
||||||
if (key != null && !HTTP_RESPONSE_HEADER_SERVER.equalsIgnoreCase(key)) {
|
if (key != null && !HTTP_RESPONSE_HEADER_SERVER.equalsIgnoreCase(key)) {
|
||||||
//System.out.println("client <<<-- remote: " + key + ": " + value);
|
//System.out.println("client <<<-- remote: " + key + ": " + value);
|
||||||
pResponse.setHeader(key, value);
|
pResponse.setHeader(key, value);
|
||||||
}
|
}
|
||||||
else if (value == null) {
|
else if (value == null) {
|
||||||
// If BOTH key and value is null, there are no more header fields
|
// If BOTH key and value is null, there are no more header fields
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 1.4+ version below....
|
/* 1.4+ version below....
|
||||||
Map headers = pRemoteConnection.getHeaderFields();
|
Map headers = pRemoteConnection.getHeaderFields();
|
||||||
for (Iterator iterator = headers.entrySet().iterator(); iterator.hasNext();) {
|
for (Iterator iterator = headers.entrySet().iterator(); iterator.hasNext();) {
|
||||||
Map.Entry header = (Map.Entry) iterator.next();
|
Map.Entry header = (Map.Entry) iterator.next();
|
||||||
|
|
||||||
List values = (List) header.getValue();
|
List values = (List) header.getValue();
|
||||||
|
|
||||||
for (Iterator valueIter = values.iterator(); valueIter.hasNext();) {
|
for (Iterator valueIter = values.iterator(); valueIter.hasNext();) {
|
||||||
String value = (String) valueIter.next();
|
String value = (String) valueIter.next();
|
||||||
String key = (String) header.getKey();
|
String key = (String) header.getKey();
|
||||||
|
|
||||||
// Skip the server header
|
// Skip the server header
|
||||||
if (HTTP_RESPONSE_HEADER_SERVER.equalsIgnoreCase(key)) {
|
if (HTTP_RESPONSE_HEADER_SERVER.equalsIgnoreCase(key)) {
|
||||||
key = null;
|
key = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default implementations includes the HTTP response code
|
// The default implementations includes the HTTP response code
|
||||||
// ("HTTP/1.1 200 Ok" or similar) as a header field with
|
// ("HTTP/1.1 200 Ok" or similar) as a header field with
|
||||||
// key "null" (why..?)...
|
// key "null" (why..?)...
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
//System.out.println("client <<<-- remote: " + key + ": " + value);
|
//System.out.println("client <<<-- remote: " + key + ": " + value);
|
||||||
pResponse.setHeader(key, value);
|
pResponse.setHeader(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies headers from the client (the incoming {@code HttpServletRequest})
|
* Copies headers from the client (the incoming {@code HttpServletRequest})
|
||||||
* to the outgoing connection.
|
* to the outgoing connection.
|
||||||
* All headers except the "Host" header are copied.
|
* All headers except the "Host" header are copied.
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pRemoteConnection
|
* @param pRemoteConnection
|
||||||
*/
|
*/
|
||||||
private void copyHeadersFromClient(HttpServletRequest pRequest, HttpURLConnection pRemoteConnection) {
|
private void copyHeadersFromClient(HttpServletRequest pRequest, HttpURLConnection pRemoteConnection) {
|
||||||
Enumeration headerNames = pRequest.getHeaderNames();
|
Enumeration headerNames = pRequest.getHeaderNames();
|
||||||
while (headerNames.hasMoreElements()) {
|
while (headerNames.hasMoreElements()) {
|
||||||
String headerName = (String) headerNames.nextElement();
|
String headerName = (String) headerNames.nextElement();
|
||||||
Enumeration headerValues = pRequest.getHeaders(headerName);
|
Enumeration headerValues = pRequest.getHeaders(headerName);
|
||||||
|
|
||||||
// Skip the "host" header, as we want something else
|
// Skip the "host" header, as we want something else
|
||||||
if (HTTP_REQUEST_HEADER_HOST.equalsIgnoreCase(headerName)) {
|
if (HTTP_REQUEST_HEADER_HOST.equalsIgnoreCase(headerName)) {
|
||||||
// Skip this header
|
// Skip this header
|
||||||
headerName = null;
|
headerName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the the header to the remoteConnection
|
// Set the the header to the remoteConnection
|
||||||
if (headerName != null) {
|
if (headerName != null) {
|
||||||
// Convert from multiple line to single line, comma separated, as
|
// Convert from multiple line to single line, comma separated, as
|
||||||
// there seems to be a shortcoming in the URLConneciton API...
|
// there seems to be a shortcoming in the URLConneciton API...
|
||||||
StringBuilder headerValue = new StringBuilder();
|
StringBuilder headerValue = new StringBuilder();
|
||||||
while (headerValues.hasMoreElements()) {
|
while (headerValues.hasMoreElements()) {
|
||||||
String value = (String) headerValues.nextElement();
|
String value = (String) headerValues.nextElement();
|
||||||
headerValue.append(value);
|
headerValue.append(value);
|
||||||
if (headerValues.hasMoreElements()) {
|
if (headerValues.hasMoreElements()) {
|
||||||
headerValue.append(", ");
|
headerValue.append(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//System.out.println("client -->>> remote: " + headerName + ": " + headerValue);
|
//System.out.println("client -->>> remote: " + headerName + ": " + headerValue);
|
||||||
pRemoteConnection.setRequestProperty(headerName, headerValue.toString());
|
pRemoteConnection.setRequestProperty(headerName, headerValue.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +1,81 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServletConfigException.
|
* ServletConfigException.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: ServletConfigException.java#2 $
|
* @version $Id: ServletConfigException.java#2 $
|
||||||
*/
|
*/
|
||||||
public class ServletConfigException extends ServletException {
|
public class ServletConfigException extends ServletException {
|
||||||
|
|
||||||
// TODO: Parameters for init-param at fault, and possibly servlet name?
|
// TODO: Parameters for init-param at fault, and possibly servlet name?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@code ServletConfigException} with the given message.
|
* Creates a {@code ServletConfigException} with the given message.
|
||||||
*
|
*
|
||||||
* @param pMessage the exception message
|
* @param pMessage the exception message
|
||||||
*/
|
*/
|
||||||
public ServletConfigException(String pMessage) {
|
public ServletConfigException(String pMessage) {
|
||||||
super(pMessage);
|
super(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@code ServletConfigException} with the given message and cause.
|
* Creates a {@code ServletConfigException} with the given message and cause.
|
||||||
*
|
*
|
||||||
* @param pMessage the exception message
|
* @param pMessage the exception message
|
||||||
* @param pCause the exception cause
|
* @param pCause the exception cause
|
||||||
*/
|
*/
|
||||||
public ServletConfigException(final String pMessage, final Throwable pCause) {
|
public ServletConfigException(final String pMessage, final Throwable pCause) {
|
||||||
super(pMessage, pCause);
|
super(pMessage, pCause);
|
||||||
|
|
||||||
maybeInitCause(pCause);
|
maybeInitCause(pCause);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@code ServletConfigException} with the cause.
|
* Creates a {@code ServletConfigException} with the cause.
|
||||||
*
|
*
|
||||||
* @param pCause the exception cause
|
* @param pCause the exception cause
|
||||||
*/
|
*/
|
||||||
public ServletConfigException(final Throwable pCause) {
|
public ServletConfigException(final Throwable pCause) {
|
||||||
super(String.format("Error in Servlet configuration: %s", pCause.getMessage()), pCause);
|
super(String.format("Error in Servlet configuration: %s", pCause.getMessage()), pCause);
|
||||||
|
|
||||||
maybeInitCause(pCause);
|
maybeInitCause(pCause);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeInitCause(Throwable pCause) {
|
private void maybeInitCause(Throwable pCause) {
|
||||||
// Workaround for ServletExceptions that does not do proper exception chaining
|
// Workaround for ServletExceptions that does not do proper exception chaining
|
||||||
if (getCause() == null) {
|
if (getCause() == null) {
|
||||||
initCause(pCause);
|
initCause(pCause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,282 +1,282 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import javax.servlet.FilterConfig;
|
import javax.servlet.FilterConfig;
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code ServletConfig} or {@code FilterConfig} adapter, that implements
|
* {@code ServletConfig} or {@code FilterConfig} adapter, that implements
|
||||||
* the {@code Map} interface for interoperability with collection-based API's.
|
* the {@code Map} interface for interoperability with collection-based API's.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This {@code Map} is not synchronized.
|
* This {@code Map} is not synchronized.
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: ServletConfigMapAdapter.java#2 $
|
* @version $Id: ServletConfigMapAdapter.java#2 $
|
||||||
*/
|
*/
|
||||||
class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map<String, String>, Serializable, Cloneable {
|
class ServletConfigMapAdapter extends AbstractMap<String, String> implements Map<String, String>, Serializable, Cloneable {
|
||||||
|
|
||||||
enum ConfigType {
|
enum ConfigType {
|
||||||
ServletConfig, FilterConfig, ServletContext
|
ServletConfig, FilterConfig, ServletContext
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ConfigType type;
|
private final ConfigType type;
|
||||||
|
|
||||||
private final ServletConfig servletConfig;
|
private final ServletConfig servletConfig;
|
||||||
private final FilterConfig filterConfig;
|
private final FilterConfig filterConfig;
|
||||||
private final ServletContext servletContext;
|
private final ServletContext servletContext;
|
||||||
|
|
||||||
// Cache the entry set
|
// Cache the entry set
|
||||||
private transient Set<Entry<String, String>> entrySet;
|
private transient Set<Entry<String, String>> entrySet;
|
||||||
|
|
||||||
public ServletConfigMapAdapter(final ServletConfig pConfig) {
|
public ServletConfigMapAdapter(final ServletConfig pConfig) {
|
||||||
this(pConfig, ConfigType.ServletConfig);
|
this(pConfig, ConfigType.ServletConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletConfigMapAdapter(final FilterConfig pConfig) {
|
public ServletConfigMapAdapter(final FilterConfig pConfig) {
|
||||||
this(pConfig, ConfigType.FilterConfig);
|
this(pConfig, ConfigType.FilterConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletConfigMapAdapter(final ServletContext pContext) {
|
public ServletConfigMapAdapter(final ServletContext pContext) {
|
||||||
this(pContext, ConfigType.ServletContext);
|
this(pContext, ConfigType.ServletContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServletConfigMapAdapter(final Object pConfig, final ConfigType pType) {
|
private ServletConfigMapAdapter(final Object pConfig, final ConfigType pType) {
|
||||||
// Could happen if client code invokes with null reference
|
// Could happen if client code invokes with null reference
|
||||||
Validate.notNull(pConfig, "config");
|
Validate.notNull(pConfig, "config");
|
||||||
|
|
||||||
type = pType;
|
type = pType;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ServletConfig:
|
case ServletConfig:
|
||||||
servletConfig = (ServletConfig) pConfig;
|
servletConfig = (ServletConfig) pConfig;
|
||||||
filterConfig = null;
|
filterConfig = null;
|
||||||
servletContext = null;
|
servletContext = null;
|
||||||
break;
|
break;
|
||||||
case FilterConfig:
|
case FilterConfig:
|
||||||
servletConfig = null;
|
servletConfig = null;
|
||||||
filterConfig = (FilterConfig) pConfig;
|
filterConfig = (FilterConfig) pConfig;
|
||||||
servletContext = null;
|
servletContext = null;
|
||||||
break;
|
break;
|
||||||
case ServletContext:
|
case ServletContext:
|
||||||
servletConfig = null;
|
servletConfig = null;
|
||||||
filterConfig = null;
|
filterConfig = null;
|
||||||
servletContext = (ServletContext) pConfig;
|
servletContext = (ServletContext) pConfig;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Wrong type: " + pType);
|
throw new IllegalArgumentException("Wrong type: " + pType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the servlet or filter name from the config.
|
* Gets the servlet or filter name from the config.
|
||||||
*
|
*
|
||||||
* @return the servlet or filter name
|
* @return the servlet or filter name
|
||||||
*/
|
*/
|
||||||
public final String getName() {
|
public final String getName() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ServletConfig:
|
case ServletConfig:
|
||||||
return servletConfig.getServletName();
|
return servletConfig.getServletName();
|
||||||
case FilterConfig:
|
case FilterConfig:
|
||||||
return filterConfig.getFilterName();
|
return filterConfig.getFilterName();
|
||||||
case ServletContext:
|
case ServletContext:
|
||||||
return servletContext.getServletContextName();
|
return servletContext.getServletContextName();
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the servlet context from the config.
|
* Gets the servlet context from the config.
|
||||||
*
|
*
|
||||||
* @return the servlet context
|
* @return the servlet context
|
||||||
*/
|
*/
|
||||||
public final ServletContext getServletContext() {
|
public final ServletContext getServletContext() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ServletConfig:
|
case ServletConfig:
|
||||||
return servletConfig.getServletContext();
|
return servletConfig.getServletContext();
|
||||||
case FilterConfig:
|
case FilterConfig:
|
||||||
return filterConfig.getServletContext();
|
return filterConfig.getServletContext();
|
||||||
case ServletContext:
|
case ServletContext:
|
||||||
return servletContext;
|
return servletContext;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Enumeration getInitParameterNames() {
|
public final Enumeration getInitParameterNames() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ServletConfig:
|
case ServletConfig:
|
||||||
return servletConfig.getInitParameterNames();
|
return servletConfig.getInitParameterNames();
|
||||||
case FilterConfig:
|
case FilterConfig:
|
||||||
return filterConfig.getInitParameterNames();
|
return filterConfig.getInitParameterNames();
|
||||||
case ServletContext:
|
case ServletContext:
|
||||||
return servletContext.getInitParameterNames();
|
return servletContext.getInitParameterNames();
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String getInitParameter(final String pName) {
|
public final String getInitParameter(final String pName) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ServletConfig:
|
case ServletConfig:
|
||||||
return servletConfig.getInitParameter(pName);
|
return servletConfig.getInitParameter(pName);
|
||||||
case FilterConfig:
|
case FilterConfig:
|
||||||
return filterConfig.getInitParameter(pName);
|
return filterConfig.getInitParameter(pName);
|
||||||
case ServletContext:
|
case ServletContext:
|
||||||
return servletContext.getInitParameter(pName);
|
return servletContext.getInitParameter(pName);
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Entry<String, String>> entrySet() {
|
public Set<Entry<String, String>> entrySet() {
|
||||||
if (entrySet == null) {
|
if (entrySet == null) {
|
||||||
entrySet = createEntrySet();
|
entrySet = createEntrySet();
|
||||||
}
|
}
|
||||||
return entrySet;
|
return entrySet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Entry<String, String>> createEntrySet() {
|
private Set<Entry<String, String>> createEntrySet() {
|
||||||
return new AbstractSet<Entry<String, String>>() {
|
return new AbstractSet<Entry<String, String>>() {
|
||||||
// Cache size, if requested, -1 means not calculated
|
// Cache size, if requested, -1 means not calculated
|
||||||
private int size = -1;
|
private int size = -1;
|
||||||
|
|
||||||
public Iterator<Entry<String, String>> iterator() {
|
public Iterator<Entry<String, String>> iterator() {
|
||||||
return new Iterator<Entry<String, String>>() {
|
return new Iterator<Entry<String, String>>() {
|
||||||
// Iterator is backed by initParameterNames enumeration
|
// Iterator is backed by initParameterNames enumeration
|
||||||
final Enumeration names = getInitParameterNames();
|
final Enumeration names = getInitParameterNames();
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return names.hasMoreElements();
|
return names.hasMoreElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entry<String, String> next() {
|
public Entry<String, String> next() {
|
||||||
final String key = (String) names.nextElement();
|
final String key = (String) names.nextElement();
|
||||||
return new Entry<String, String>() {
|
return new Entry<String, String>() {
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return get(key);
|
return get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String setValue(String pValue) {
|
public String setValue(String pValue) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Override equals
|
// NOTE: Override equals
|
||||||
public boolean equals(Object pOther) {
|
public boolean equals(Object pOther) {
|
||||||
if (!(pOther instanceof Map.Entry)) {
|
if (!(pOther instanceof Map.Entry)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map.Entry e = (Map.Entry) pOther;
|
Map.Entry e = (Map.Entry) pOther;
|
||||||
Object value = get(key);
|
Object value = get(key);
|
||||||
Object rKey = e.getKey();
|
Object rKey = e.getKey();
|
||||||
Object rValue = e.getValue();
|
Object rValue = e.getValue();
|
||||||
return (key == null ? rKey == null : key.equals(rKey))
|
return (key == null ? rKey == null : key.equals(rKey))
|
||||||
&& (value == null ? rValue == null : value.equals(rValue));
|
&& (value == null ? rValue == null : value.equals(rValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Override hashCode to keep the map's
|
// NOTE: Override hashCode to keep the map's
|
||||||
// hashCode constant and compatible
|
// hashCode constant and compatible
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
Object value = get(key);
|
Object value = get(key);
|
||||||
return ((key == null) ? 0 : key.hashCode()) ^
|
return ((key == null) ? 0 : key.hashCode()) ^
|
||||||
((value == null) ? 0 : value.hashCode());
|
((value == null) ? 0 : value.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return key + "=" + get(key);
|
return key + "=" + get(key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove() {
|
public void remove() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
size = calculateSize();
|
size = calculateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int calculateSize() {
|
private int calculateSize() {
|
||||||
final Enumeration names = getInitParameterNames();
|
final Enumeration names = getInitParameterNames();
|
||||||
|
|
||||||
int size = 0;
|
int size = 0;
|
||||||
while (names.hasMoreElements()) {
|
while (names.hasMoreElements()) {
|
||||||
size++;
|
size++;
|
||||||
names.nextElement();
|
names.nextElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public String get(Object pKey) {
|
public String get(Object pKey) {
|
||||||
return getInitParameter(StringUtil.valueOf(pKey));
|
return getInitParameter(StringUtil.valueOf(pKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unsupported Map methods
|
/// Unsupported Map methods
|
||||||
@Override
|
@Override
|
||||||
public String put(String pKey, String pValue) {
|
public String put(String pKey, String pValue) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String remove(Object pKey) {
|
public String remove(Object pKey) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putAll(Map pMap) {
|
public void putAll(Map pMap) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+114
-114
@@ -1,114 +1,114 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A delegate for handling stream support in wrapped servlet responses.
|
* A delegate for handling stream support in wrapped servlet responses.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Client code should delegate {@code getOutputStream}, {@code getWriter},
|
* Client code should delegate {@code getOutputStream}, {@code getWriter},
|
||||||
* {@code flushBuffer} and {@code resetBuffer} methods from the servlet response.
|
* {@code flushBuffer} and {@code resetBuffer} methods from the servlet response.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: ServletResponseStreamDelegate.java#2 $
|
* @version $Id: ServletResponseStreamDelegate.java#2 $
|
||||||
*/
|
*/
|
||||||
public class ServletResponseStreamDelegate {
|
public class ServletResponseStreamDelegate {
|
||||||
private Object out = null;
|
private Object out = null;
|
||||||
protected final ServletResponse response;
|
protected final ServletResponse response;
|
||||||
|
|
||||||
public ServletResponseStreamDelegate(final ServletResponse pResponse) {
|
public ServletResponseStreamDelegate(final ServletResponse pResponse) {
|
||||||
response = notNull(pResponse, "response");
|
response = notNull(pResponse, "response");
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Intentionally NOT thread safe, as one request/response should be handled by one thread ONLY.
|
// NOTE: Intentionally NOT thread safe, as one request/response should be handled by one thread ONLY.
|
||||||
public final ServletOutputStream getOutputStream() throws IOException {
|
public final ServletOutputStream getOutputStream() throws IOException {
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
OutputStream out = createOutputStream();
|
OutputStream out = createOutputStream();
|
||||||
this.out = out instanceof ServletOutputStream ? out : new OutputStreamAdapter(out);
|
this.out = out instanceof ServletOutputStream ? out : new OutputStreamAdapter(out);
|
||||||
}
|
}
|
||||||
else if (out instanceof PrintWriter) {
|
else if (out instanceof PrintWriter) {
|
||||||
throw new IllegalStateException("getWriter() already called.");
|
throw new IllegalStateException("getWriter() already called.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ServletOutputStream) out;
|
return (ServletOutputStream) out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Intentionally NOT thread safe, as one request/response should be handled by one thread ONLY.
|
// NOTE: Intentionally NOT thread safe, as one request/response should be handled by one thread ONLY.
|
||||||
public final PrintWriter getWriter() throws IOException {
|
public final PrintWriter getWriter() throws IOException {
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
// NOTE: getCharacterEncoding may/should not return null
|
// NOTE: getCharacterEncoding may/should not return null
|
||||||
OutputStream out = createOutputStream();
|
OutputStream out = createOutputStream();
|
||||||
String charEncoding = response.getCharacterEncoding();
|
String charEncoding = response.getCharacterEncoding();
|
||||||
this.out = new PrintWriter(charEncoding != null ? new OutputStreamWriter(out, charEncoding) : new OutputStreamWriter(out));
|
this.out = new PrintWriter(charEncoding != null ? new OutputStreamWriter(out, charEncoding) : new OutputStreamWriter(out));
|
||||||
}
|
}
|
||||||
else if (out instanceof ServletOutputStream) {
|
else if (out instanceof ServletOutputStream) {
|
||||||
throw new IllegalStateException("getOutputStream() already called.");
|
throw new IllegalStateException("getOutputStream() already called.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (PrintWriter) out;
|
return (PrintWriter) out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code OutputStream}.
|
* Returns the {@code OutputStream}.
|
||||||
* Subclasses should override this method to provide a decorated output stream.
|
* Subclasses should override this method to provide a decorated output stream.
|
||||||
* This method is guaranteed to be invoked only once for a request/response
|
* This method is guaranteed to be invoked only once for a request/response
|
||||||
* (unless {@code resetBuffer} is invoked).
|
* (unless {@code resetBuffer} is invoked).
|
||||||
* <P/>
|
* <P/>
|
||||||
* This implementation simply returns the output stream from the wrapped
|
* This implementation simply returns the output stream from the wrapped
|
||||||
* response.
|
* response.
|
||||||
*
|
*
|
||||||
* @return the {@code OutputStream} to use for the response
|
* @return the {@code OutputStream} to use for the response
|
||||||
* @throws IOException if an I/O exception occurs
|
* @throws IOException if an I/O exception occurs
|
||||||
*/
|
*/
|
||||||
protected OutputStream createOutputStream() throws IOException {
|
protected OutputStream createOutputStream() throws IOException {
|
||||||
return response.getOutputStream();
|
return response.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushBuffer() throws IOException {
|
public void flushBuffer() throws IOException {
|
||||||
if (out instanceof ServletOutputStream) {
|
if (out instanceof ServletOutputStream) {
|
||||||
((ServletOutputStream) out).flush();
|
((ServletOutputStream) out).flush();
|
||||||
}
|
}
|
||||||
else if (out != null) {
|
else if (out != null) {
|
||||||
((PrintWriter) out).flush();
|
((PrintWriter) out).flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetBuffer() {
|
public void resetBuffer() {
|
||||||
out = null;
|
out = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,306 +1,306 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.io.FileUtil;
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThrottleFilter, a filter for easing server during heavy load.
|
* ThrottleFilter, a filter for easing server during heavy load.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Intercepts requests, and returns HTTP response code {@code 503 (Service Unavailable)},
|
* Intercepts requests, and returns HTTP response code {@code 503 (Service Unavailable)},
|
||||||
* if there are more than a given number of concurrent
|
* if there are more than a given number of concurrent
|
||||||
* requests, to avoid large backlogs. The number of concurrent requests and the
|
* requests, to avoid large backlogs. The number of concurrent requests and the
|
||||||
* response messages sent to the user agent, is configurable from the web
|
* response messages sent to the user agent, is configurable from the web
|
||||||
* descriptor.
|
* descriptor.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: ThrottleFilter.java#1 $
|
* @version $Id: ThrottleFilter.java#1 $
|
||||||
* @see #setMaxConcurrentThreadCount
|
* @see #setMaxConcurrentThreadCount
|
||||||
* @see #setResponseMessages
|
* @see #setResponseMessages
|
||||||
*/
|
*/
|
||||||
public class ThrottleFilter extends GenericFilter {
|
public class ThrottleFilter extends GenericFilter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimum free thread count, defaults to {@code 10}
|
* Minimum free thread count, defaults to {@code 10}
|
||||||
*/
|
*/
|
||||||
protected int maxConcurrentThreadCount = 10;
|
protected int maxConcurrentThreadCount = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of running request threads
|
* The number of running request threads
|
||||||
*/
|
*/
|
||||||
private int runningThreads = 0;
|
private int runningThreads = 0;
|
||||||
private final Object runningThreadsLock = new Object();
|
private final Object runningThreadsLock = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default response message sent to user agents, if the request is rejected
|
* Default response message sent to user agents, if the request is rejected
|
||||||
*/
|
*/
|
||||||
protected final static String DEFUALT_RESPONSE_MESSAGE =
|
protected final static String DEFUALT_RESPONSE_MESSAGE =
|
||||||
"Service temporarily unavailable, please try again later.";
|
"Service temporarily unavailable, please try again later.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default response content type
|
* Default response content type
|
||||||
*/
|
*/
|
||||||
protected static final String DEFAULT_TYPE = "text/html";
|
protected static final String DEFAULT_TYPE = "text/html";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reposne message sent to user agenta, if the request is rejected
|
* The reposne message sent to user agenta, if the request is rejected
|
||||||
*/
|
*/
|
||||||
private Map<String, String> responseMessageNames = new HashMap<String, String>(10);
|
private Map<String, String> responseMessageNames = new HashMap<String, String>(10);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reposne message sent to user agents, if the request is rejected
|
* The reposne message sent to user agents, if the request is rejected
|
||||||
*/
|
*/
|
||||||
private String[] responseMessageTypes = null;
|
private String[] responseMessageTypes = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache for response messages
|
* Cache for response messages
|
||||||
*/
|
*/
|
||||||
private Map<String, CacheEntry> responseCache = new HashMap<String, CacheEntry>(10);
|
private Map<String, CacheEntry> responseCache = new HashMap<String, CacheEntry>(10);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum free thread count.
|
* Sets the minimum free thread count.
|
||||||
*
|
*
|
||||||
* @param pMaxConcurrentThreadCount
|
* @param pMaxConcurrentThreadCount
|
||||||
*/
|
*/
|
||||||
public void setMaxConcurrentThreadCount(String pMaxConcurrentThreadCount) {
|
public void setMaxConcurrentThreadCount(String pMaxConcurrentThreadCount) {
|
||||||
if (!StringUtil.isEmpty(pMaxConcurrentThreadCount)) {
|
if (!StringUtil.isEmpty(pMaxConcurrentThreadCount)) {
|
||||||
try {
|
try {
|
||||||
maxConcurrentThreadCount = Integer.parseInt(pMaxConcurrentThreadCount);
|
maxConcurrentThreadCount = Integer.parseInt(pMaxConcurrentThreadCount);
|
||||||
}
|
}
|
||||||
catch (NumberFormatException nfe) {
|
catch (NumberFormatException nfe) {
|
||||||
// Use default
|
// Use default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the response message sent to the user agent, if the request is
|
* Sets the response message sent to the user agent, if the request is
|
||||||
* rejected.
|
* rejected.
|
||||||
* <BR/>
|
* <BR/>
|
||||||
* The format is {@code <mime-type>=<filename>,
|
* The format is {@code <mime-type>=<filename>,
|
||||||
* <mime-type>=<filename>}.
|
* <mime-type>=<filename>}.
|
||||||
* <BR/>
|
* <BR/>
|
||||||
* Example: {@code <text/vnd.wap.wmlgt;=</errors/503.wml>,
|
* Example: {@code <text/vnd.wap.wmlgt;=</errors/503.wml>,
|
||||||
* <text/html>=</errors/503.html>}
|
* <text/html>=</errors/503.html>}
|
||||||
*
|
*
|
||||||
* @param pResponseMessages
|
* @param pResponseMessages
|
||||||
*/
|
*/
|
||||||
public void setResponseMessages(String pResponseMessages) {
|
public void setResponseMessages(String pResponseMessages) {
|
||||||
// Split string in type=filename pairs
|
// Split string in type=filename pairs
|
||||||
String[] mappings = StringUtil.toStringArray(pResponseMessages, ", \r\n\t");
|
String[] mappings = StringUtil.toStringArray(pResponseMessages, ", \r\n\t");
|
||||||
List<String> types = new ArrayList<String>();
|
List<String> types = new ArrayList<String>();
|
||||||
|
|
||||||
for (String pair : mappings) {
|
for (String pair : mappings) {
|
||||||
// Split pairs on '='
|
// Split pairs on '='
|
||||||
String[] mapping = StringUtil.toStringArray(pair, "= ");
|
String[] mapping = StringUtil.toStringArray(pair, "= ");
|
||||||
|
|
||||||
// Test for wrong mapping
|
// Test for wrong mapping
|
||||||
if ((mapping == null) || (mapping.length < 2)) {
|
if ((mapping == null) || (mapping.length < 2)) {
|
||||||
log("Error in init param \"responseMessages\": " + pResponseMessages);
|
log("Error in init param \"responseMessages\": " + pResponseMessages);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
types.add(mapping[0]);
|
types.add(mapping[0]);
|
||||||
responseMessageNames.put(mapping[0], mapping[1]);
|
responseMessageNames.put(mapping[0], mapping[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create arrays
|
// Create arrays
|
||||||
responseMessageTypes = types.toArray(new String[types.size()]);
|
responseMessageTypes = types.toArray(new String[types.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
* @param pChain
|
* @param pChain
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*/
|
*/
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
try {
|
try {
|
||||||
if (beginRequest()) {
|
if (beginRequest()) {
|
||||||
// Continue request
|
// Continue request
|
||||||
pChain.doFilter(pRequest, pResponse);
|
pChain.doFilter(pRequest, pResponse);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Send error and end request
|
// Send error and end request
|
||||||
// Get HTTP specific versions
|
// Get HTTP specific versions
|
||||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||||
HttpServletResponse response = (HttpServletResponse) pResponse;
|
HttpServletResponse response = (HttpServletResponse) pResponse;
|
||||||
|
|
||||||
// Get content type
|
// Get content type
|
||||||
String contentType = getContentType(request);
|
String contentType = getContentType(request);
|
||||||
|
|
||||||
// Note: This is not the way the spec says you should do it.
|
// Note: This is not the way the spec says you should do it.
|
||||||
// However, we handle error response this way for preformace reasons.
|
// However, we handle error response this way for preformace reasons.
|
||||||
// The "correct" way would be to use sendError() and register a servlet
|
// The "correct" way would be to use sendError() and register a servlet
|
||||||
// that does the content negotiation as errorpage in the web descriptor.
|
// that does the content negotiation as errorpage in the web descriptor.
|
||||||
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
|
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
|
||||||
response.setContentType(contentType);
|
response.setContentType(contentType);
|
||||||
response.getWriter().println(getMessage(contentType));
|
response.getWriter().println(getMessage(contentType));
|
||||||
|
|
||||||
// Log warning, as this shouldn't happen too often
|
// Log warning, as this shouldn't happen too often
|
||||||
log("Request denied, no more available threads for requestURI=" + request.getRequestURI());
|
log("Request denied, no more available threads for requestURI=" + request.getRequestURI());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
doneRequest();
|
doneRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the beginning of a request
|
* Marks the beginning of a request
|
||||||
*
|
*
|
||||||
* @return {@code true} if the request should be handled.
|
* @return {@code true} if the request should be handled.
|
||||||
*/
|
*/
|
||||||
private boolean beginRequest() {
|
private boolean beginRequest() {
|
||||||
synchronized (runningThreadsLock) {
|
synchronized (runningThreadsLock) {
|
||||||
runningThreads++;
|
runningThreads++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (runningThreads <= maxConcurrentThreadCount);
|
return (runningThreads <= maxConcurrentThreadCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the end of the request
|
* Marks the end of the request
|
||||||
*/
|
*/
|
||||||
private void doneRequest() {
|
private void doneRequest() {
|
||||||
synchronized (runningThreadsLock) {
|
synchronized (runningThreadsLock) {
|
||||||
runningThreads--;
|
runningThreads--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the content type for the response, suitable for the requesting user agent.
|
* Gets the content type for the response, suitable for the requesting user agent.
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @return the content type
|
* @return the content type
|
||||||
*/
|
*/
|
||||||
private String getContentType(HttpServletRequest pRequest) {
|
private String getContentType(HttpServletRequest pRequest) {
|
||||||
if (responseMessageTypes != null) {
|
if (responseMessageTypes != null) {
|
||||||
String accept = pRequest.getHeader("Accept");
|
String accept = pRequest.getHeader("Accept");
|
||||||
|
|
||||||
for (String type : responseMessageTypes) {
|
for (String type : responseMessageTypes) {
|
||||||
// Note: This is not 100% correct way of doing content negotiation
|
// Note: This is not 100% correct way of doing content negotiation
|
||||||
// But we just want a compatible result, quick, so this is okay
|
// But we just want a compatible result, quick, so this is okay
|
||||||
if (StringUtil.contains(accept, type)) {
|
if (StringUtil.contains(accept, type)) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If none found, return default
|
// If none found, return default
|
||||||
return DEFAULT_TYPE;
|
return DEFAULT_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the response message for the given content type.
|
* Gets the response message for the given content type.
|
||||||
*
|
*
|
||||||
* @param pContentType
|
* @param pContentType
|
||||||
* @return the message
|
* @return the message
|
||||||
*/
|
*/
|
||||||
private String getMessage(String pContentType) {
|
private String getMessage(String pContentType) {
|
||||||
String fileName = responseMessageNames.get(pContentType);
|
String fileName = responseMessageNames.get(pContentType);
|
||||||
|
|
||||||
// Get cached value
|
// Get cached value
|
||||||
CacheEntry entry = responseCache.get(fileName);
|
CacheEntry entry = responseCache.get(fileName);
|
||||||
|
|
||||||
if ((entry == null) || entry.isExpired()) {
|
if ((entry == null) || entry.isExpired()) {
|
||||||
|
|
||||||
// Create and add or replace cached value
|
// Create and add or replace cached value
|
||||||
entry = new CacheEntry(readMessage(fileName));
|
entry = new CacheEntry(readMessage(fileName));
|
||||||
responseCache.put(fileName, entry);
|
responseCache.put(fileName, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return value
|
// Return value
|
||||||
return (entry.getValue() != null)
|
return (entry.getValue() != null)
|
||||||
? (String) entry.getValue()
|
? (String) entry.getValue()
|
||||||
: DEFUALT_RESPONSE_MESSAGE;
|
: DEFUALT_RESPONSE_MESSAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the response message from a file in the current web app.
|
* Reads the response message from a file in the current web app.
|
||||||
*
|
*
|
||||||
* @param pFileName
|
* @param pFileName
|
||||||
* @return the message
|
* @return the message
|
||||||
*/
|
*/
|
||||||
private String readMessage(String pFileName) {
|
private String readMessage(String pFileName) {
|
||||||
try {
|
try {
|
||||||
// Read resource from web app
|
// Read resource from web app
|
||||||
InputStream is = getServletContext().getResourceAsStream(pFileName);
|
InputStream is = getServletContext().getResourceAsStream(pFileName);
|
||||||
|
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
return new String(FileUtil.read(is));
|
return new String(FileUtil.read(is));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log("File not found: " + pFileName);
|
log("File not found: " + pFileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException ioe) {
|
catch (IOException ioe) {
|
||||||
log("Error reading file: " + pFileName + " (" + ioe.getMessage() + ")");
|
log("Error reading file: " + pFileName + " (" + ioe.getMessage() + ")");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of Cached objects
|
* Keeps track of Cached objects
|
||||||
*/
|
*/
|
||||||
private static class CacheEntry {
|
private static class CacheEntry {
|
||||||
private Object value;
|
private Object value;
|
||||||
private long timestamp = -1;
|
private long timestamp = -1;
|
||||||
|
|
||||||
CacheEntry(Object pValue) {
|
CacheEntry(Object pValue) {
|
||||||
value = pValue;
|
value = pValue;
|
||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object getValue() {
|
Object getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isExpired() {
|
boolean isExpired() {
|
||||||
return (System.currentTimeMillis() - timestamp) > 60000; // Cache 1 minute
|
return (System.currentTimeMillis() - timestamp) > 60000; // Cache 1 minute
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,112 +1,112 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TimingFilter class description.
|
* TimingFilter class description.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: TimingFilter.java#1 $
|
* @version $Id: TimingFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
public class TimingFilter extends GenericFilter {
|
public class TimingFilter extends GenericFilter {
|
||||||
|
|
||||||
private String attribUsage = null;
|
private String attribUsage = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method init
|
* Method init
|
||||||
*
|
*
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*/
|
*/
|
||||||
public void init() throws ServletException {
|
public void init() throws ServletException {
|
||||||
attribUsage = getFilterName() + ".timerDelta";
|
attribUsage = getFilterName() + ".timerDelta";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
* @param pChain
|
* @param pChain
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*/
|
*/
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
// Get total usage of earlier filters on same level
|
// Get total usage of earlier filters on same level
|
||||||
Object usageAttrib = pRequest.getAttribute(attribUsage);
|
Object usageAttrib = pRequest.getAttribute(attribUsage);
|
||||||
long total = 0;
|
long total = 0;
|
||||||
|
|
||||||
if (usageAttrib instanceof Long) {
|
if (usageAttrib instanceof Long) {
|
||||||
// If set, get value, and remove attribute for nested resources
|
// If set, get value, and remove attribute for nested resources
|
||||||
total = (Long) usageAttrib;
|
total = (Long) usageAttrib;
|
||||||
pRequest.removeAttribute(attribUsage);
|
pRequest.removeAttribute(attribUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start timing
|
// Start timing
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Continue chain
|
// Continue chain
|
||||||
pChain.doFilter(pRequest, pResponse);
|
pChain.doFilter(pRequest, pResponse);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Stop timing
|
// Stop timing
|
||||||
long end = System.currentTimeMillis();
|
long end = System.currentTimeMillis();
|
||||||
|
|
||||||
// Get time usage of included resources, add to total usage
|
// Get time usage of included resources, add to total usage
|
||||||
usageAttrib = pRequest.getAttribute(attribUsage);
|
usageAttrib = pRequest.getAttribute(attribUsage);
|
||||||
long usage = 0;
|
long usage = 0;
|
||||||
if (usageAttrib instanceof Long) {
|
if (usageAttrib instanceof Long) {
|
||||||
usage = (Long) usageAttrib;
|
usage = (Long) usageAttrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the name of the included resource
|
// Get the name of the included resource
|
||||||
String resourceURI = ServletUtil.getIncludeRequestURI(pRequest);
|
String resourceURI = ServletUtil.getIncludeRequestURI(pRequest);
|
||||||
|
|
||||||
// If none, this is probably the parent page itself
|
// If none, this is probably the parent page itself
|
||||||
if (resourceURI == null) {
|
if (resourceURI == null) {
|
||||||
resourceURI = ((HttpServletRequest) pRequest).getRequestURI();
|
resourceURI = ((HttpServletRequest) pRequest).getRequestURI();
|
||||||
}
|
}
|
||||||
long delta = end - start;
|
long delta = end - start;
|
||||||
|
|
||||||
log(String.format("Request processing time for resource \"%s\": %d ms (accumulated: %d ms).", resourceURI, (delta - usage), delta));
|
log(String.format("Request processing time for resource \"%s\": %d ms (accumulated: %d ms).", resourceURI, (delta - usage), delta));
|
||||||
|
|
||||||
// Store total usage
|
// Store total usage
|
||||||
total += delta;
|
total += delta;
|
||||||
pRequest.setAttribute(attribUsage, total);
|
pRequest.setAttribute(attribUsage, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,238 +1,238 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.ServletResponseWrapper;
|
import javax.servlet.ServletResponseWrapper;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.FilterOutputStream;
|
import java.io.FilterOutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes extra unneccessary white space from a servlet response.
|
* Removes extra unneccessary white space from a servlet response.
|
||||||
* White space is defined as per {@link Character#isWhitespace(char)}.
|
* White space is defined as per {@link Character#isWhitespace(char)}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This filter has no understanding of the content in the reponse, and will
|
* This filter has no understanding of the content in the reponse, and will
|
||||||
* remove repeated white space anywhere in the stream. It is intended for
|
* remove repeated white space anywhere in the stream. It is intended for
|
||||||
* removing white space from HTML or XML streams, but this limitation makes it
|
* removing white space from HTML or XML streams, but this limitation makes it
|
||||||
* less suited for filtering HTML/XHTML with embedded CSS or JavaScript,
|
* less suited for filtering HTML/XHTML with embedded CSS or JavaScript,
|
||||||
* in case white space should be significant here. It is strongly reccommended
|
* in case white space should be significant here. It is strongly reccommended
|
||||||
* you keep CSS and JavaScript in separate files (this will have the added
|
* you keep CSS and JavaScript in separate files (this will have the added
|
||||||
* benefit of further reducing the ammount of data communicated between
|
* benefit of further reducing the ammount of data communicated between
|
||||||
* server and client).
|
* server and client).
|
||||||
* <p/>
|
* <p/>
|
||||||
* <em>At the moment this filter has no concept of encoding</em>.
|
* <em>At the moment this filter has no concept of encoding</em>.
|
||||||
* This means, that if some multi-byte escape sequence contains one or more
|
* This means, that if some multi-byte escape sequence contains one or more
|
||||||
* bytes that <em>individually</em> is treated as a white space, these bytes
|
* bytes that <em>individually</em> is treated as a white space, these bytes
|
||||||
* may be skipped.
|
* may be skipped.
|
||||||
* As <a href="http://en.wikipedia.org/wiki/UTF-8" title="UTF-8">UTF-8</a>
|
* As <a href="http://en.wikipedia.org/wiki/UTF-8" title="UTF-8">UTF-8</a>
|
||||||
* guarantees that no bytes are repeated in this way, this filter can safely
|
* guarantees that no bytes are repeated in this way, this filter can safely
|
||||||
* filter UTF-8.
|
* filter UTF-8.
|
||||||
* Simple 8 bit character encodings, like the
|
* Simple 8 bit character encodings, like the
|
||||||
* <a href="http://en.wikipedia.org/wiki/ISO/IEC_8859"
|
* <a href="http://en.wikipedia.org/wiki/ISO/IEC_8859"
|
||||||
* title="ISO/IEC 8859">ISO/IEC 8859</a> standard, or
|
* title="ISO/IEC 8859">ISO/IEC 8859</a> standard, or
|
||||||
* <a href="http://en.wikipedia.org/wiki/Windows-1252" title="Windows-1252">
|
* <a href="http://en.wikipedia.org/wiki/Windows-1252" title="Windows-1252">
|
||||||
* are always safe.
|
* are always safe.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <b>Configuration</b><br/>
|
* <b>Configuration</b><br/>
|
||||||
* To use {@code TrimWhiteSpaceFilter} in your web-application, you simply need
|
* To use {@code TrimWhiteSpaceFilter} in your web-application, you simply need
|
||||||
* to add it to your web descriptor ({@code web.xml}).
|
* to add it to your web descriptor ({@code web.xml}).
|
||||||
* If using a servlet container that supports the Servlet 2.4 spec, the new
|
* If using a servlet container that supports the Servlet 2.4 spec, the new
|
||||||
* {@code dispatcher} element should be used, and set to
|
* {@code dispatcher} element should be used, and set to
|
||||||
* {@code REQUEST/FORWARD}, to make sure the filter is invoked only once for
|
* {@code REQUEST/FORWARD}, to make sure the filter is invoked only once for
|
||||||
* requests.
|
* requests.
|
||||||
* If using an older web descriptor, set the {@code init-param}
|
* If using an older web descriptor, set the {@code init-param}
|
||||||
* {@code "once-per-request"} to {@code "true"} (this will have the same effect,
|
* {@code "once-per-request"} to {@code "true"} (this will have the same effect,
|
||||||
* but might perform slightly worse than the 2.4 version).
|
* but might perform slightly worse than the 2.4 version).
|
||||||
* Please see the examples below.
|
* Please see the examples below.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <b>Servlet 2.4 version, filter section:</b><br/>
|
* <b>Servlet 2.4 version, filter section:</b><br/>
|
||||||
* <pre>
|
* <pre>
|
||||||
* <!-- TrimWS Filter Configuration -->
|
* <!-- TrimWS Filter Configuration -->
|
||||||
* <filter>
|
* <filter>
|
||||||
* <filter-name>trimws</filter-name>
|
* <filter-name>trimws</filter-name>
|
||||||
* <filter-class>com.twelvemonkeys.servlet.TrimWhiteSpaceFilter</filter-class>
|
* <filter-class>com.twelvemonkeys.servlet.TrimWhiteSpaceFilter</filter-class>
|
||||||
* <!-- auto-flush=true is the default, may be omitted -->
|
* <!-- auto-flush=true is the default, may be omitted -->
|
||||||
* <init-param>
|
* <init-param>
|
||||||
* <param-name>auto-flush</param-name>
|
* <param-name>auto-flush</param-name>
|
||||||
* <param-value>true</param-value>
|
* <param-value>true</param-value>
|
||||||
* </init-param>
|
* </init-param>
|
||||||
* </filter>
|
* </filter>
|
||||||
* </pre>
|
* </pre>
|
||||||
* <b>Filter-mapping section:</b><br/>
|
* <b>Filter-mapping section:</b><br/>
|
||||||
* <pre>
|
* <pre>
|
||||||
* <!-- TimWS Filter Mapping -->
|
* <!-- TimWS Filter Mapping -->
|
||||||
* <filter-mapping>
|
* <filter-mapping>
|
||||||
* <filter-name>trimws</filter-name>
|
* <filter-name>trimws</filter-name>
|
||||||
* <url-pattern>*.html</url-pattern>
|
* <url-pattern>*.html</url-pattern>
|
||||||
* <dispatcher>REQUEST</dispatcher>
|
* <dispatcher>REQUEST</dispatcher>
|
||||||
* <dispatcher>FORWARD</dispatcher>
|
* <dispatcher>FORWARD</dispatcher>
|
||||||
* </filter-mapping>
|
* </filter-mapping>
|
||||||
* <filter-mapping>
|
* <filter-mapping>
|
||||||
* <filter-name>trimws</filter-name>
|
* <filter-name>trimws</filter-name>
|
||||||
* <url-pattern>*.jsp</url-pattern>
|
* <url-pattern>*.jsp</url-pattern>
|
||||||
* <dispatcher>REQUEST</dispatcher>
|
* <dispatcher>REQUEST</dispatcher>
|
||||||
* <dispatcher>FORWARD</dispatcher>
|
* <dispatcher>FORWARD</dispatcher>
|
||||||
* </filter-mapping>
|
* </filter-mapping>
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: TrimWhiteSpaceFilter.java#2 $
|
* @version $Id: TrimWhiteSpaceFilter.java#2 $
|
||||||
*/
|
*/
|
||||||
public class TrimWhiteSpaceFilter extends GenericFilter {
|
public class TrimWhiteSpaceFilter extends GenericFilter {
|
||||||
|
|
||||||
private boolean autoFlush = true;
|
private boolean autoFlush = true;
|
||||||
|
|
||||||
@InitParam
|
@InitParam
|
||||||
public void setAutoFlush(final boolean pAutoFlush) {
|
public void setAutoFlush(final boolean pAutoFlush) {
|
||||||
autoFlush = pAutoFlush;
|
autoFlush = pAutoFlush;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() throws ServletException {
|
public void init() throws ServletException {
|
||||||
super.init();
|
super.init();
|
||||||
log("Automatic flushing is " + (autoFlush ? "enabled" : "disabled"));
|
log("Automatic flushing is " + (autoFlush ? "enabled" : "disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
ServletResponseWrapper wrapped = new TrimWSServletResponseWrapper(pResponse);
|
ServletResponseWrapper wrapped = new TrimWSServletResponseWrapper(pResponse);
|
||||||
pChain.doFilter(pRequest, ServletUtil.createWrapper(wrapped));
|
pChain.doFilter(pRequest, ServletUtil.createWrapper(wrapped));
|
||||||
if (autoFlush) {
|
if (autoFlush) {
|
||||||
wrapped.flushBuffer();
|
wrapped.flushBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class TrimWSFilterOutputStream extends FilterOutputStream {
|
static final class TrimWSFilterOutputStream extends FilterOutputStream {
|
||||||
boolean lastWasWS = true; // Avoids leading WS by init to true
|
boolean lastWasWS = true; // Avoids leading WS by init to true
|
||||||
|
|
||||||
public TrimWSFilterOutputStream(OutputStream pOut) {
|
public TrimWSFilterOutputStream(OutputStream pOut) {
|
||||||
super(pOut);
|
super(pOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override this, in case the wrapped outputstream overrides...
|
// Override this, in case the wrapped outputstream overrides...
|
||||||
public final void write(byte pBytes[]) throws IOException {
|
public final void write(byte pBytes[]) throws IOException {
|
||||||
write(pBytes, 0, pBytes.length);
|
write(pBytes, 0, pBytes.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override this, in case the wrapped outputstream overrides...
|
// Override this, in case the wrapped outputstream overrides...
|
||||||
public final void write(byte pBytes[], int pOff, int pLen) throws IOException {
|
public final void write(byte pBytes[], int pOff, int pLen) throws IOException {
|
||||||
if (pBytes == null) {
|
if (pBytes == null) {
|
||||||
throw new NullPointerException("bytes == null");
|
throw new NullPointerException("bytes == null");
|
||||||
}
|
}
|
||||||
else if (pOff < 0 || pLen < 0 || (pOff + pLen > pBytes.length)) {
|
else if (pOff < 0 || pLen < 0 || (pOff + pLen > pBytes.length)) {
|
||||||
throw new IndexOutOfBoundsException("Bytes: " + pBytes.length + " Offset: " + pOff + " Length: " + pLen);
|
throw new IndexOutOfBoundsException("Bytes: " + pBytes.length + " Offset: " + pOff + " Length: " + pLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < pLen ; i++) {
|
for (int i = 0; i < pLen ; i++) {
|
||||||
write(pBytes[pOff + i]);
|
write(pBytes[pOff + i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(int pByte) throws IOException {
|
public void write(int pByte) throws IOException {
|
||||||
// TODO: Is this good enough for multi-byte encodings like UTF-16?
|
// TODO: Is this good enough for multi-byte encodings like UTF-16?
|
||||||
// Consider writing through a Writer that does that for us, and
|
// Consider writing through a Writer that does that for us, and
|
||||||
// also buffer whitespace, so we write a linefeed every time there's
|
// also buffer whitespace, so we write a linefeed every time there's
|
||||||
// one in the original...
|
// one in the original...
|
||||||
|
|
||||||
// According to http://en.wikipedia.org/wiki/UTF-8:
|
// According to http://en.wikipedia.org/wiki/UTF-8:
|
||||||
// "[...] US-ASCII octet values do not appear otherwise in a UTF-8
|
// "[...] US-ASCII octet values do not appear otherwise in a UTF-8
|
||||||
// encoded character stream. This provides compatibility with file
|
// encoded character stream. This provides compatibility with file
|
||||||
// systems or other software (e.g., the printf() function in
|
// systems or other software (e.g., the printf() function in
|
||||||
// C libraries) that parse based on US-ASCII values but are
|
// C libraries) that parse based on US-ASCII values but are
|
||||||
// transparent to other values."
|
// transparent to other values."
|
||||||
|
|
||||||
if (!Character.isWhitespace((char) pByte)) {
|
if (!Character.isWhitespace((char) pByte)) {
|
||||||
// If char is not WS, just store
|
// If char is not WS, just store
|
||||||
super.write(pByte);
|
super.write(pByte);
|
||||||
lastWasWS = false;
|
lastWasWS = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: Consider writing only 0x0a (LF) and 0x20 (space)
|
// TODO: Consider writing only 0x0a (LF) and 0x20 (space)
|
||||||
// Else, if char is WS, store first, skip the rest
|
// Else, if char is WS, store first, skip the rest
|
||||||
if (!lastWasWS) {
|
if (!lastWasWS) {
|
||||||
if (pByte == 0x0d) { // Convert all CR/LF's to 0x0a
|
if (pByte == 0x0d) { // Convert all CR/LF's to 0x0a
|
||||||
super.write(0x0a);
|
super.write(0x0a);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
super.write(pByte);
|
super.write(pByte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastWasWS = true;
|
lastWasWS = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TrimWSStreamDelegate extends ServletResponseStreamDelegate {
|
private static class TrimWSStreamDelegate extends ServletResponseStreamDelegate {
|
||||||
public TrimWSStreamDelegate(ServletResponse pResponse) {
|
public TrimWSStreamDelegate(ServletResponse pResponse) {
|
||||||
super(pResponse);
|
super(pResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OutputStream createOutputStream() throws IOException {
|
protected OutputStream createOutputStream() throws IOException {
|
||||||
return new TrimWSFilterOutputStream(response.getOutputStream());
|
return new TrimWSFilterOutputStream(response.getOutputStream());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TrimWSServletResponseWrapper extends ServletResponseWrapper {
|
static class TrimWSServletResponseWrapper extends ServletResponseWrapper {
|
||||||
private final ServletResponseStreamDelegate streamDelegate = new TrimWSStreamDelegate(getResponse());
|
private final ServletResponseStreamDelegate streamDelegate = new TrimWSStreamDelegate(getResponse());
|
||||||
|
|
||||||
public TrimWSServletResponseWrapper(ServletResponse pResponse) {
|
public TrimWSServletResponseWrapper(ServletResponse pResponse) {
|
||||||
super(pResponse);
|
super(pResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletOutputStream getOutputStream() throws IOException {
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
return streamDelegate.getOutputStream();
|
return streamDelegate.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrintWriter getWriter() throws IOException {
|
public PrintWriter getWriter() throws IOException {
|
||||||
return streamDelegate.getWriter();
|
return streamDelegate.getWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContentLength(int pLength) {
|
public void setContentLength(int pLength) {
|
||||||
// Will be changed by filter, so don't set.
|
// Will be changed by filter, so don't set.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flushBuffer() throws IOException {
|
public void flushBuffer() throws IOException {
|
||||||
streamDelegate.flushBuffer();
|
streamDelegate.flushBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetBuffer() {
|
public void resetBuffer() {
|
||||||
streamDelegate.resetBuffer();
|
streamDelegate.resetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Consider picking up content-type/encoding, as we can only
|
// TODO: Consider picking up content-type/encoding, as we can only
|
||||||
// filter US-ASCII, UTF-8 and other compatible encodings?
|
// filter US-ASCII, UTF-8 and other compatible encodings?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+199
-199
@@ -1,200 +1,200 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.servlet.GenericFilter;
|
import com.twelvemonkeys.servlet.GenericFilter;
|
||||||
import com.twelvemonkeys.servlet.ServletConfigException;
|
import com.twelvemonkeys.servlet.ServletConfigException;
|
||||||
import com.twelvemonkeys.servlet.ServletUtil;
|
import com.twelvemonkeys.servlet.ServletUtil;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Filter that provides response caching, for HTTP {@code GET} requests.
|
* A Filter that provides response caching, for HTTP {@code GET} requests.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Originally based on ideas and code found in the ONJava article
|
* Originally based on ideas and code found in the ONJava article
|
||||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||||
* Servlet Filters Every Web Application Should Have</a>
|
* Servlet Filters Every Web Application Should Have</a>
|
||||||
* by Jayson Falkner.
|
* by Jayson Falkner.
|
||||||
*
|
*
|
||||||
* @author Jayson Falkner
|
* @author Jayson Falkner
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: CacheFilter.java#4 $
|
* @version $Id: CacheFilter.java#4 $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CacheFilter extends GenericFilter {
|
public class CacheFilter extends GenericFilter {
|
||||||
|
|
||||||
HTTPCache cache;
|
HTTPCache cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the filter
|
* Initializes the filter
|
||||||
*
|
*
|
||||||
* @throws javax.servlet.ServletException
|
* @throws javax.servlet.ServletException
|
||||||
*/
|
*/
|
||||||
public void init() throws ServletException {
|
public void init() throws ServletException {
|
||||||
FilterConfig config = getFilterConfig();
|
FilterConfig config = getFilterConfig();
|
||||||
|
|
||||||
// Default don't delete cache files on exit (persistent cache)
|
// Default don't delete cache files on exit (persistent cache)
|
||||||
boolean deleteCacheOnExit = "TRUE".equalsIgnoreCase(config.getInitParameter("deleteCacheOnExit"));
|
boolean deleteCacheOnExit = "TRUE".equalsIgnoreCase(config.getInitParameter("deleteCacheOnExit"));
|
||||||
|
|
||||||
// Default expiry time 10 minutes
|
// Default expiry time 10 minutes
|
||||||
int expiryTime = 10 * 60 * 1000;
|
int expiryTime = 10 * 60 * 1000;
|
||||||
|
|
||||||
String expiryTimeStr = config.getInitParameter("expiryTime");
|
String expiryTimeStr = config.getInitParameter("expiryTime");
|
||||||
if (!StringUtil.isEmpty(expiryTimeStr)) {
|
if (!StringUtil.isEmpty(expiryTimeStr)) {
|
||||||
try {
|
try {
|
||||||
// TODO: This is insane.. :-P Let the expiry time be in minutes or seconds..
|
// TODO: This is insane.. :-P Let the expiry time be in minutes or seconds..
|
||||||
expiryTime = Integer.parseInt(expiryTimeStr);
|
expiryTime = Integer.parseInt(expiryTimeStr);
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
throw new ServletConfigException("Could not parse expiryTime: " + e.toString(), e);
|
throw new ServletConfigException("Could not parse expiryTime: " + e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default max mem cache size 10 MB
|
// Default max mem cache size 10 MB
|
||||||
int memCacheSize = 10;
|
int memCacheSize = 10;
|
||||||
|
|
||||||
String memCacheSizeStr = config.getInitParameter("memCacheSize");
|
String memCacheSizeStr = config.getInitParameter("memCacheSize");
|
||||||
if (!StringUtil.isEmpty(memCacheSizeStr)) {
|
if (!StringUtil.isEmpty(memCacheSizeStr)) {
|
||||||
try {
|
try {
|
||||||
memCacheSize = Integer.parseInt(memCacheSizeStr);
|
memCacheSize = Integer.parseInt(memCacheSizeStr);
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
throw new ServletConfigException("Could not parse memCacheSize: " + e.toString(), e);
|
throw new ServletConfigException("Could not parse memCacheSize: " + e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxCachedEntites = 10000;
|
int maxCachedEntites = 10000;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cache = new HTTPCache(
|
cache = new HTTPCache(
|
||||||
getTempFolder(),
|
getTempFolder(),
|
||||||
expiryTime,
|
expiryTime,
|
||||||
memCacheSize * 1024 * 1024,
|
memCacheSize * 1024 * 1024,
|
||||||
maxCachedEntites,
|
maxCachedEntites,
|
||||||
deleteCacheOnExit,
|
deleteCacheOnExit,
|
||||||
new ServletContextLoggerAdapter(getFilterName(), getServletContext())
|
new ServletContextLoggerAdapter(getFilterName(), getServletContext())
|
||||||
) {
|
) {
|
||||||
@Override
|
@Override
|
||||||
protected File getRealFile(CacheRequest pRequest) {
|
protected File getRealFile(CacheRequest pRequest) {
|
||||||
String contextRelativeURI = ServletUtil.getContextRelativeURI(((ServletCacheRequest) pRequest).getRequest());
|
String contextRelativeURI = ServletUtil.getContextRelativeURI(((ServletCacheRequest) pRequest).getRequest());
|
||||||
|
|
||||||
String path = getServletContext().getRealPath(contextRelativeURI);
|
String path = getServletContext().getRealPath(contextRelativeURI);
|
||||||
|
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
return new File(path);
|
return new File(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log("Created cache: " + cache);
|
log("Created cache: " + cache);
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
throw new ServletConfigException("Could not create cache: " + e.toString(), e);
|
throw new ServletConfigException("Could not create cache: " + e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getTempFolder() {
|
private File getTempFolder() {
|
||||||
File tempRoot = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");
|
File tempRoot = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");
|
||||||
if (tempRoot == null) {
|
if (tempRoot == null) {
|
||||||
throw new IllegalStateException("Missing context attribute \"javax.servlet.context.tempdir\"");
|
throw new IllegalStateException("Missing context attribute \"javax.servlet.context.tempdir\"");
|
||||||
}
|
}
|
||||||
return new File(tempRoot, getFilterName());
|
return new File(tempRoot, getFilterName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
log("Destroying cache: " + cache);
|
log("Destroying cache: " + cache);
|
||||||
cache = null;
|
cache = null;
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
// We can only cache HTTP GET/HEAD requests
|
// We can only cache HTTP GET/HEAD requests
|
||||||
if (!(pRequest instanceof HttpServletRequest
|
if (!(pRequest instanceof HttpServletRequest
|
||||||
&& pResponse instanceof HttpServletResponse
|
&& pResponse instanceof HttpServletResponse
|
||||||
&& isCachable((HttpServletRequest) pRequest))) {
|
&& isCachable((HttpServletRequest) pRequest))) {
|
||||||
pChain.doFilter(pRequest, pResponse); // Continue chain
|
pChain.doFilter(pRequest, pResponse); // Continue chain
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ServletCacheRequest cacheRequest = new ServletCacheRequest((HttpServletRequest) pRequest);
|
ServletCacheRequest cacheRequest = new ServletCacheRequest((HttpServletRequest) pRequest);
|
||||||
ServletCacheResponse cacheResponse = new ServletCacheResponse((HttpServletResponse) pResponse);
|
ServletCacheResponse cacheResponse = new ServletCacheResponse((HttpServletResponse) pResponse);
|
||||||
ServletResponseResolver resolver = new ServletResponseResolver(cacheRequest, cacheResponse, pChain);
|
ServletResponseResolver resolver = new ServletResponseResolver(cacheRequest, cacheResponse, pChain);
|
||||||
|
|
||||||
// Render fast
|
// Render fast
|
||||||
try {
|
try {
|
||||||
cache.doCached(cacheRequest, cacheResponse, resolver);
|
cache.doCached(cacheRequest, cacheResponse, resolver);
|
||||||
}
|
}
|
||||||
catch (CacheException e) {
|
catch (CacheException e) {
|
||||||
if (e.getCause() instanceof ServletException) {
|
if (e.getCause() instanceof ServletException) {
|
||||||
throw (ServletException) e.getCause();
|
throw (ServletException) e.getCause();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new ServletException(e);
|
throw new ServletException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
pResponse.flushBuffer();
|
pResponse.flushBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCachable(HttpServletRequest pRequest) {
|
private boolean isCachable(HttpServletRequest pRequest) {
|
||||||
// TODO: Get Cache-Control: no-cache/max-age=0 and Pragma: no-cache from REQUEST too?
|
// TODO: Get Cache-Control: no-cache/max-age=0 and Pragma: no-cache from REQUEST too?
|
||||||
return "GET".equals(pRequest.getMethod()) || "HEAD".equals(pRequest.getMethod());
|
return "GET".equals(pRequest.getMethod()) || "HEAD".equals(pRequest.getMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Extract, complete and document this class, might be useful in other cases
|
// TODO: Extract, complete and document this class, might be useful in other cases
|
||||||
// Maybe add it to the ServletUtil class
|
// Maybe add it to the ServletUtil class
|
||||||
static class ServletContextLoggerAdapter extends Logger {
|
static class ServletContextLoggerAdapter extends Logger {
|
||||||
private final ServletContext context;
|
private final ServletContext context;
|
||||||
|
|
||||||
public ServletContextLoggerAdapter(String pName, ServletContext pContext) {
|
public ServletContextLoggerAdapter(String pName, ServletContext pContext) {
|
||||||
super(pName, null);
|
super(pName, null);
|
||||||
context = pContext;
|
context = pContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(Level pLevel, String pMessage) {
|
public void log(Level pLevel, String pMessage) {
|
||||||
context.log(pMessage);
|
context.log(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(Level pLevel, String pMessage, Throwable pThrowable) {
|
public void log(Level pLevel, String pMessage, Throwable pThrowable) {
|
||||||
context.log(pMessage, pThrowable);
|
context.log(pMessage, pThrowable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+260
-260
@@ -1,261 +1,261 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.net.HTTPUtil;
|
import com.twelvemonkeys.net.HTTPUtil;
|
||||||
import com.twelvemonkeys.servlet.ServletResponseStreamDelegate;
|
import com.twelvemonkeys.servlet.ServletResponseStreamDelegate;
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.http.HttpServletResponseWrapper;
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CacheResponseWrapper class description.
|
* CacheResponseWrapper class description.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Based on ideas and code found in the ONJava article
|
* Based on ideas and code found in the ONJava article
|
||||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||||
* Servlet Filters Every Web Application Should Have</a>
|
* Servlet Filters Every Web Application Should Have</a>
|
||||||
* by Jayson Falkner.
|
* by Jayson Falkner.
|
||||||
*
|
*
|
||||||
* @author Jayson Falkner
|
* @author Jayson Falkner
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: CacheResponseWrapper.java#3 $
|
* @version $Id: CacheResponseWrapper.java#3 $
|
||||||
*/
|
*/
|
||||||
class CacheResponseWrapper extends HttpServletResponseWrapper {
|
class CacheResponseWrapper extends HttpServletResponseWrapper {
|
||||||
private ServletResponseStreamDelegate streamDelegate;
|
private ServletResponseStreamDelegate streamDelegate;
|
||||||
|
|
||||||
private CacheResponse response;
|
private CacheResponse response;
|
||||||
private CachedEntity cached;
|
private CachedEntity cached;
|
||||||
private WritableCachedResponse cachedResponse;
|
private WritableCachedResponse cachedResponse;
|
||||||
|
|
||||||
private Boolean cacheable;
|
private Boolean cacheable;
|
||||||
private int status;
|
private int status;
|
||||||
|
|
||||||
public CacheResponseWrapper(final ServletCacheResponse pResponse, final CachedEntity pCached) {
|
public CacheResponseWrapper(final ServletCacheResponse pResponse, final CachedEntity pCached) {
|
||||||
super(pResponse.getResponse());
|
super(pResponse.getResponse());
|
||||||
response = pResponse;
|
response = pResponse;
|
||||||
cached = pCached;
|
cached = pCached;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NOTE: This class defers determining if a response is cacheable until the
|
NOTE: This class defers determining if a response is cacheable until the
|
||||||
output stream is needed.
|
output stream is needed.
|
||||||
This it the reason for the somewhat complicated logic in the add/setHeader
|
This it the reason for the somewhat complicated logic in the add/setHeader
|
||||||
methods below.
|
methods below.
|
||||||
*/
|
*/
|
||||||
private void init() {
|
private void init() {
|
||||||
cacheable = null;
|
cacheable = null;
|
||||||
status = SC_OK;
|
status = SC_OK;
|
||||||
cachedResponse = cached.createCachedResponse();
|
cachedResponse = cached.createCachedResponse();
|
||||||
streamDelegate = new ServletResponseStreamDelegate(this) {
|
streamDelegate = new ServletResponseStreamDelegate(this) {
|
||||||
protected OutputStream createOutputStream() throws IOException {
|
protected OutputStream createOutputStream() throws IOException {
|
||||||
// Test if this request is really cacheable, otherwise,
|
// Test if this request is really cacheable, otherwise,
|
||||||
// just write through to underlying response, and don't cache
|
// just write through to underlying response, and don't cache
|
||||||
if (isCacheable()) {
|
if (isCacheable()) {
|
||||||
return cachedResponse.getOutputStream();
|
return cachedResponse.getOutputStream();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cachedResponse.setStatus(status);
|
cachedResponse.setStatus(status);
|
||||||
cachedResponse.writeHeadersTo(CacheResponseWrapper.this.response);
|
cachedResponse.writeHeadersTo(CacheResponseWrapper.this.response);
|
||||||
return super.getOutputStream();
|
return super.getOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedResponse getCachedResponse() {
|
CachedResponse getCachedResponse() {
|
||||||
return cachedResponse.getCachedResponse();
|
return cachedResponse.getCachedResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCacheable() {
|
public boolean isCacheable() {
|
||||||
// NOTE: Intentionally not synchronized
|
// NOTE: Intentionally not synchronized
|
||||||
if (cacheable == null) {
|
if (cacheable == null) {
|
||||||
cacheable = isCacheableImpl();
|
cacheable = isCacheableImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return cacheable;
|
return cacheable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCacheableImpl() {
|
private boolean isCacheableImpl() {
|
||||||
if (status != SC_OK) {
|
if (status != SC_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vary: *
|
// Vary: *
|
||||||
String[] values = cachedResponse.getHeaderValues(HTTPCache.HEADER_VARY);
|
String[] values = cachedResponse.getHeaderValues(HTTPCache.HEADER_VARY);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if ("*".equals(value)) {
|
if ("*".equals(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache-Control: no-cache, no-store, must-revalidate
|
// Cache-Control: no-cache, no-store, must-revalidate
|
||||||
values = cachedResponse.getHeaderValues(HTTPCache.HEADER_CACHE_CONTROL);
|
values = cachedResponse.getHeaderValues(HTTPCache.HEADER_CACHE_CONTROL);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if (StringUtil.contains(value, "no-cache")
|
if (StringUtil.contains(value, "no-cache")
|
||||||
|| StringUtil.contains(value, "no-store")
|
|| StringUtil.contains(value, "no-store")
|
||||||
|| StringUtil.contains(value, "must-revalidate")) {
|
|| StringUtil.contains(value, "must-revalidate")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pragma: no-cache
|
// Pragma: no-cache
|
||||||
values = cachedResponse.getHeaderValues(HTTPCache.HEADER_PRAGMA);
|
values = cachedResponse.getHeaderValues(HTTPCache.HEADER_PRAGMA);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if (StringUtil.contains(value, "no-cache")) {
|
if (StringUtil.contains(value, "no-cache")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushBuffer() throws IOException {
|
public void flushBuffer() throws IOException {
|
||||||
streamDelegate.flushBuffer();
|
streamDelegate.flushBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetBuffer() {
|
public void resetBuffer() {
|
||||||
// Servlet 2.3
|
// Servlet 2.3
|
||||||
streamDelegate.resetBuffer();
|
streamDelegate.resetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.reset();
|
super.reset();
|
||||||
}
|
}
|
||||||
// No else, might be cacheable after all..
|
// No else, might be cacheable after all..
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletOutputStream getOutputStream() throws IOException {
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
return streamDelegate.getOutputStream();
|
return streamDelegate.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrintWriter getWriter() throws IOException {
|
public PrintWriter getWriter() throws IOException {
|
||||||
return streamDelegate.getWriter();
|
return streamDelegate.getWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsHeader(String name) {
|
public boolean containsHeader(String name) {
|
||||||
return cachedResponse.getHeaderValues(name) != null;
|
return cachedResponse.getHeaderValues(name) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendError(int pStatusCode, String msg) throws IOException {
|
public void sendError(int pStatusCode, String msg) throws IOException {
|
||||||
// NOT cacheable
|
// NOT cacheable
|
||||||
status = pStatusCode;
|
status = pStatusCode;
|
||||||
super.sendError(pStatusCode, msg);
|
super.sendError(pStatusCode, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendError(int pStatusCode) throws IOException {
|
public void sendError(int pStatusCode) throws IOException {
|
||||||
// NOT cacheable
|
// NOT cacheable
|
||||||
status = pStatusCode;
|
status = pStatusCode;
|
||||||
super.sendError(pStatusCode);
|
super.sendError(pStatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(int pStatusCode, String sm) {
|
public void setStatus(int pStatusCode, String sm) {
|
||||||
// NOTE: This method is deprecated
|
// NOTE: This method is deprecated
|
||||||
setStatus(pStatusCode);
|
setStatus(pStatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(int pStatusCode) {
|
public void setStatus(int pStatusCode) {
|
||||||
// NOT cacheable unless pStatusCode == 200 (or a FEW others?)
|
// NOT cacheable unless pStatusCode == 200 (or a FEW others?)
|
||||||
if (pStatusCode != SC_OK) {
|
if (pStatusCode != SC_OK) {
|
||||||
status = pStatusCode;
|
status = pStatusCode;
|
||||||
super.setStatus(pStatusCode);
|
super.setStatus(pStatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendRedirect(String pLocation) throws IOException {
|
public void sendRedirect(String pLocation) throws IOException {
|
||||||
// NOT cacheable
|
// NOT cacheable
|
||||||
status = SC_MOVED_TEMPORARILY;
|
status = SC_MOVED_TEMPORARILY;
|
||||||
super.sendRedirect(pLocation);
|
super.sendRedirect(pLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDateHeader(String pName, long pValue) {
|
public void setDateHeader(String pName, long pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.setDateHeader(pName, pValue);
|
super.setDateHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cachedResponse.setHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
cachedResponse.setHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDateHeader(String pName, long pValue) {
|
public void addDateHeader(String pName, long pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.addDateHeader(pName, pValue);
|
super.addDateHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cachedResponse.addHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
cachedResponse.addHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeader(String pName, String pValue) {
|
public void setHeader(String pName, String pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.setHeader(pName, pValue);
|
super.setHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cachedResponse.setHeader(pName, pValue);
|
cachedResponse.setHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHeader(String pName, String pValue) {
|
public void addHeader(String pName, String pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.addHeader(pName, pValue);
|
super.addHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cachedResponse.addHeader(pName, pValue);
|
cachedResponse.addHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIntHeader(String pName, int pValue) {
|
public void setIntHeader(String pName, int pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.setIntHeader(pName, pValue);
|
super.setIntHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cachedResponse.setHeader(pName, String.valueOf(pValue));
|
cachedResponse.setHeader(pName, String.valueOf(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIntHeader(String pName, int pValue) {
|
public void addIntHeader(String pName, int pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.addIntHeader(pName, pValue);
|
super.addIntHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cachedResponse.addHeader(pName, String.valueOf(pValue));
|
cachedResponse.addHeader(pName, String.valueOf(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setContentType(String type) {
|
public final void setContentType(String type) {
|
||||||
setHeader(HTTPCache.HEADER_CONTENT_TYPE, type);
|
setHeader(HTTPCache.HEADER_CONTENT_TYPE, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,75 +1,75 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CachedEntity
|
* CachedEntity
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: CachedEntity.java#3 $
|
* @version $Id: CachedEntity.java#3 $
|
||||||
*/
|
*/
|
||||||
interface CachedEntity {
|
interface CachedEntity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the cached entity to the response.
|
* Renders the cached entity to the response.
|
||||||
*
|
*
|
||||||
* @param pRequest the request
|
* @param pRequest the request
|
||||||
* @param pResponse the response
|
* @param pResponse the response
|
||||||
* @throws java.io.IOException if an I/O exception occurs
|
* @throws java.io.IOException if an I/O exception occurs
|
||||||
*/
|
*/
|
||||||
void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException;
|
void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Captures (caches) the response for the given request.
|
* Captures (caches) the response for the given request.
|
||||||
*
|
*
|
||||||
* @param pRequest the request
|
* @param pRequest the request
|
||||||
* @param pResponse the response
|
* @param pResponse the response
|
||||||
* @throws java.io.IOException if an I/O exception occurs
|
* @throws java.io.IOException if an I/O exception occurs
|
||||||
*
|
*
|
||||||
* @see #createCachedResponse()
|
* @see #createCachedResponse()
|
||||||
*/
|
*/
|
||||||
void capture(CacheRequest pRequest, CachedResponse pResponse) throws IOException;
|
void capture(CacheRequest pRequest, CachedResponse pResponse) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if the content of this entity is stale for the given request.
|
* Tests if the content of this entity is stale for the given request.
|
||||||
*
|
*
|
||||||
* @param pRequest the request
|
* @param pRequest the request
|
||||||
* @return {@code true} if content is stale
|
* @return {@code true} if content is stale
|
||||||
*/
|
*/
|
||||||
boolean isStale(CacheRequest pRequest);
|
boolean isStale(CacheRequest pRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@code WritableCachedResponse} to use to capture the response.
|
* Creates a {@code WritableCachedResponse} to use to capture the response.
|
||||||
*
|
*
|
||||||
* @return a {@code WritableCachedResponse}
|
* @return a {@code WritableCachedResponse}
|
||||||
*/
|
*/
|
||||||
WritableCachedResponse createCachedResponse();
|
WritableCachedResponse createCachedResponse();
|
||||||
}
|
}
|
||||||
|
|||||||
+169
-169
@@ -1,170 +1,170 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CachedEntity
|
* CachedEntity
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: CachedEntityImpl.java#3 $
|
* @version $Id: CachedEntityImpl.java#3 $
|
||||||
*/
|
*/
|
||||||
class CachedEntityImpl implements CachedEntity {
|
class CachedEntityImpl implements CachedEntity {
|
||||||
private String cacheURI;
|
private String cacheURI;
|
||||||
private HTTPCache cache;
|
private HTTPCache cache;
|
||||||
|
|
||||||
CachedEntityImpl(String pCacheURI, HTTPCache pCache) {
|
CachedEntityImpl(String pCacheURI, HTTPCache pCache) {
|
||||||
cacheURI = Validate.notNull(pCacheURI, "cacheURI");
|
cacheURI = Validate.notNull(pCacheURI, "cacheURI");
|
||||||
cache = pCache;
|
cache = pCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException {
|
public void render(CacheRequest pRequest, CacheResponse pResponse) throws IOException {
|
||||||
// Get cached content
|
// Get cached content
|
||||||
CachedResponse cached = cache.getContent(cacheURI, pRequest);
|
CachedResponse cached = cache.getContent(cacheURI, pRequest);
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
throw new IllegalStateException("Tried to render non-cached response (cache == null).");
|
throw new IllegalStateException("Tried to render non-cached response (cache == null).");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the cached entity is not modified since the date of the browsers
|
// If the cached entity is not modified since the date of the browsers
|
||||||
// version, then simply send a "304 Not Modified" response
|
// version, then simply send a "304 Not Modified" response
|
||||||
// Otherwise send the full response.
|
// Otherwise send the full response.
|
||||||
|
|
||||||
// TODO: WHY DID I COMMENT OUT THIS LINE AND REPLACE IT WITH THE ONE BELOW??
|
// TODO: WHY DID I COMMENT OUT THIS LINE AND REPLACE IT WITH THE ONE BELOW??
|
||||||
//long lastModified = HTTPCache.getDateHeader(cached.getHeaderValue(HTTPCache.HEADER_LAST_MODIFIED));
|
//long lastModified = HTTPCache.getDateHeader(cached.getHeaderValue(HTTPCache.HEADER_LAST_MODIFIED));
|
||||||
long lastModified = HTTPCache.getDateHeader(cached.getHeaderValue(HTTPCache.HEADER_CACHED_TIME));
|
long lastModified = HTTPCache.getDateHeader(cached.getHeaderValue(HTTPCache.HEADER_CACHED_TIME));
|
||||||
|
|
||||||
// TODO: Consider handling time skews between server "now" and client "now"?
|
// TODO: Consider handling time skews between server "now" and client "now"?
|
||||||
// NOTE: The If-Modified-Since is probably right according to the server
|
// NOTE: The If-Modified-Since is probably right according to the server
|
||||||
// even in a time skew situation, as the client should use either the
|
// even in a time skew situation, as the client should use either the
|
||||||
// Date or Last-Modifed dates from the response headers (server generated)
|
// Date or Last-Modifed dates from the response headers (server generated)
|
||||||
long ifModifiedSince = -1L;
|
long ifModifiedSince = -1L;
|
||||||
try {
|
try {
|
||||||
List<String> ifmh = pRequest.getHeaders().get(HTTPCache.HEADER_IF_MODIFIED_SINCE);
|
List<String> ifmh = pRequest.getHeaders().get(HTTPCache.HEADER_IF_MODIFIED_SINCE);
|
||||||
ifModifiedSince = ifmh != null ? HTTPCache.getDateHeader(ifmh.get(0)) : -1L;
|
ifModifiedSince = ifmh != null ? HTTPCache.getDateHeader(ifmh.get(0)) : -1L;
|
||||||
if (ifModifiedSince != -1L) {
|
if (ifModifiedSince != -1L) {
|
||||||
/*
|
/*
|
||||||
long serverTime = DateUtil.currentTimeMinute();
|
long serverTime = DateUtil.currentTimeMinute();
|
||||||
long clientTime = DateUtil.roundToMinute(pRequest.getDateHeader(HTTPCache.HEADER_DATE));
|
long clientTime = DateUtil.roundToMinute(pRequest.getDateHeader(HTTPCache.HEADER_DATE));
|
||||||
|
|
||||||
// Test if time skew is greater than time skew threshold (currently 1 minute)
|
// Test if time skew is greater than time skew threshold (currently 1 minute)
|
||||||
if (Math.abs(serverTime - clientTime) > 1) {
|
if (Math.abs(serverTime - clientTime) > 1) {
|
||||||
// TODO: Correct error in ifModifiedSince?
|
// TODO: Correct error in ifModifiedSince?
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// System.out.println(" << CachedEntity >> If-Modified-Since present: " + ifModifiedSince + " --> " + NetUtil.formatHTTPDate(ifModifiedSince) + "==" + pRequest.getHeader(HTTPCache.HEADER_IF_MODIFIED_SINCE));
|
// System.out.println(" << CachedEntity >> If-Modified-Since present: " + ifModifiedSince + " --> " + NetUtil.formatHTTPDate(ifModifiedSince) + "==" + pRequest.getHeader(HTTPCache.HEADER_IF_MODIFIED_SINCE));
|
||||||
// System.out.println(" << CachedEntity >> Last-Modified for entity: " + lastModified + " --> " + NetUtil.formatHTTPDate(lastModified));
|
// System.out.println(" << CachedEntity >> Last-Modified for entity: " + lastModified + " --> " + NetUtil.formatHTTPDate(lastModified));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
// Seems to be a bug in FireFox 1.0.2..?!
|
// Seems to be a bug in FireFox 1.0.2..?!
|
||||||
cache.log("Error in date header from user-agent. User-Agent: " + pRequest.getHeaders().get("User-Agent"), e);
|
cache.log("Error in date header from user-agent. User-Agent: " + pRequest.getHeaders().get("User-Agent"), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastModified == -1L || (ifModifiedSince < (lastModified / 1000L) * 1000L)) {
|
if (lastModified == -1L || (ifModifiedSince < (lastModified / 1000L) * 1000L)) {
|
||||||
pResponse.setStatus(cached.getStatus());
|
pResponse.setStatus(cached.getStatus());
|
||||||
cached.writeHeadersTo(pResponse);
|
cached.writeHeadersTo(pResponse);
|
||||||
if (isStale(pRequest)) {
|
if (isStale(pRequest)) {
|
||||||
// Add warning header
|
// Add warning header
|
||||||
// Warning: 110 <server>:<port> Content is stale
|
// Warning: 110 <server>:<port> Content is stale
|
||||||
pResponse.addHeader(HTTPCache.HEADER_WARNING, "110 " + getHost(pRequest) + " Content is stale.");
|
pResponse.addHeader(HTTPCache.HEADER_WARNING, "110 " + getHost(pRequest) + " Content is stale.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: At the moment we only ever try to cache HEAD and GET requests
|
// NOTE: At the moment we only ever try to cache HEAD and GET requests
|
||||||
if (!"HEAD".equals(pRequest.getMethod())) {
|
if (!"HEAD".equals(pRequest.getMethod())) {
|
||||||
cached.writeContentsTo(pResponse.getOutputStream());
|
cached.writeContentsTo(pResponse.getOutputStream());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
pResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||||
// System.out.println(" << CachedEntity >> Not modified: " + toString());
|
// System.out.println(" << CachedEntity >> Not modified: " + toString());
|
||||||
if (isStale(pRequest)) {
|
if (isStale(pRequest)) {
|
||||||
// Add warning header
|
// Add warning header
|
||||||
// Warning: 110 <server>:<port> Content is stale
|
// Warning: 110 <server>:<port> Content is stale
|
||||||
pResponse.addHeader(HTTPCache.HEADER_WARNING, "110 " + getHost(pRequest) + " Content is stale.");
|
pResponse.addHeader(HTTPCache.HEADER_WARNING, "110 " + getHost(pRequest) + " Content is stale.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Utility method to get Host header */
|
/* Utility method to get Host header */
|
||||||
private static String getHost(CacheRequest pRequest) {
|
private static String getHost(CacheRequest pRequest) {
|
||||||
return pRequest.getServerName() + ":" + pRequest.getServerPort();
|
return pRequest.getServerName() + ":" + pRequest.getServerPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void capture(CacheRequest pRequest, CachedResponse pResponse) throws IOException {
|
public void capture(CacheRequest pRequest, CachedResponse pResponse) throws IOException {
|
||||||
// if (!(pResponse instanceof CacheResponseWrapper)) {
|
// if (!(pResponse instanceof CacheResponseWrapper)) {
|
||||||
// throw new IllegalArgumentException("Response must be created by CachedEntity.createResponseWrapper()");
|
// throw new IllegalArgumentException("Response must be created by CachedEntity.createResponseWrapper()");
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// CacheResponseWrapper response = (CacheResponseWrapper) pResponse;
|
// CacheResponseWrapper response = (CacheResponseWrapper) pResponse;
|
||||||
|
|
||||||
// if (response.isCacheable()) {
|
// if (response.isCacheable()) {
|
||||||
cache.registerContent(
|
cache.registerContent(
|
||||||
cacheURI,
|
cacheURI,
|
||||||
pRequest,
|
pRequest,
|
||||||
pResponse instanceof WritableCachedResponse ? ((WritableCachedResponse) pResponse).getCachedResponse() : pResponse
|
pResponse instanceof WritableCachedResponse ? ((WritableCachedResponse) pResponse).getCachedResponse() : pResponse
|
||||||
);
|
);
|
||||||
// }
|
// }
|
||||||
// else {
|
// else {
|
||||||
// Else store that the response for this request is not cachable
|
// Else store that the response for this request is not cachable
|
||||||
// pRequest.setAttribute(ATTRIB_NOT_CACHEABLE, Boolean.TRUE);
|
// pRequest.setAttribute(ATTRIB_NOT_CACHEABLE, Boolean.TRUE);
|
||||||
|
|
||||||
// TODO: Store this in HTTPCache, for subsequent requests to same resource?
|
// TODO: Store this in HTTPCache, for subsequent requests to same resource?
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isStale(CacheRequest pRequest) {
|
public boolean isStale(CacheRequest pRequest) {
|
||||||
return cache.isContentStale(cacheURI, pRequest);
|
return cache.isContentStale(cacheURI, pRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WritableCachedResponse createCachedResponse() {
|
public WritableCachedResponse createCachedResponse() {
|
||||||
return new WritableCachedResponseImpl();
|
return new WritableCachedResponseImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return (cacheURI != null ? cacheURI.hashCode() : 0) + 1397;
|
return (cacheURI != null ? cacheURI.hashCode() : 0) + 1397;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object pOther) {
|
public boolean equals(Object pOther) {
|
||||||
return pOther instanceof CachedEntityImpl &&
|
return pOther instanceof CachedEntityImpl &&
|
||||||
((cacheURI == null && ((CachedEntityImpl) pOther).cacheURI == null) ||
|
((cacheURI == null && ((CachedEntityImpl) pOther).cacheURI == null) ||
|
||||||
cacheURI != null && cacheURI.equals(((CachedEntityImpl) pOther).cacheURI));
|
cacheURI != null && cacheURI.equals(((CachedEntityImpl) pOther).cacheURI));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CachedEntity[URI=" + cacheURI + "]";
|
return "CachedEntity[URI=" + cacheURI + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+95
-95
@@ -1,95 +1,95 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CachedResponse
|
* CachedResponse
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: CachedResponse.java#3 $
|
* @version $Id: CachedResponse.java#3 $
|
||||||
*/
|
*/
|
||||||
interface CachedResponse {
|
interface CachedResponse {
|
||||||
/**
|
/**
|
||||||
* Writes the cached headers to the response
|
* Writes the cached headers to the response
|
||||||
*
|
*
|
||||||
* @param pResponse the servlet response
|
* @param pResponse the servlet response
|
||||||
*/
|
*/
|
||||||
void writeHeadersTo(CacheResponse pResponse);
|
void writeHeadersTo(CacheResponse pResponse);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the cahced content to the response
|
* Writes the cahced content to the response
|
||||||
*
|
*
|
||||||
* @param pStream the response output stream
|
* @param pStream the response output stream
|
||||||
* @throws IOException if an I/O exception occurs during write
|
* @throws IOException if an I/O exception occurs during write
|
||||||
*/
|
*/
|
||||||
void writeContentsTo(OutputStream pStream) throws IOException;
|
void writeContentsTo(OutputStream pStream) throws IOException;
|
||||||
|
|
||||||
int getStatus();
|
int getStatus();
|
||||||
|
|
||||||
// TODO: Map<String, List<String>> getHeaders()
|
// TODO: Map<String, List<String>> getHeaders()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the header names of all headers set in this response.
|
* Gets the header names of all headers set in this response.
|
||||||
*
|
*
|
||||||
* @return an array of {@code String}s
|
* @return an array of {@code String}s
|
||||||
*/
|
*/
|
||||||
String[] getHeaderNames();
|
String[] getHeaderNames();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all header values set for the given header in this response. If the
|
* Gets all header values set for the given header in this response. If the
|
||||||
* header is not set, {@code null} is returned.
|
* header is not set, {@code null} is returned.
|
||||||
*
|
*
|
||||||
* @param pHeaderName the header name
|
* @param pHeaderName the header name
|
||||||
* @return an array of {@code String}s, or {@code null} if there is no
|
* @return an array of {@code String}s, or {@code null} if there is no
|
||||||
* such header in this response.
|
* such header in this response.
|
||||||
*/
|
*/
|
||||||
String[] getHeaderValues(String pHeaderName);
|
String[] getHeaderValues(String pHeaderName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the first header value set for the given header in this response.
|
* Gets the first header value set for the given header in this response.
|
||||||
* If the header is not set, {@code null} is returned.
|
* If the header is not set, {@code null} is returned.
|
||||||
* Useful for headers that don't have multiple values, like
|
* Useful for headers that don't have multiple values, like
|
||||||
* {@code "Content-Type"} or {@code "Content-Length"}.
|
* {@code "Content-Type"} or {@code "Content-Length"}.
|
||||||
*
|
*
|
||||||
* @param pHeaderName the header name
|
* @param pHeaderName the header name
|
||||||
* @return a {@code String}, or {@code null} if there is no
|
* @return a {@code String}, or {@code null} if there is no
|
||||||
* such header in this response.
|
* such header in this response.
|
||||||
*/
|
*/
|
||||||
String getHeaderValue(String pHeaderName);
|
String getHeaderValue(String pHeaderName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the size of this cached response in bytes.
|
* Returns the size of this cached response in bytes.
|
||||||
*
|
*
|
||||||
* @return the size
|
* @return the size
|
||||||
*/
|
*/
|
||||||
int size();
|
int size();
|
||||||
}
|
}
|
||||||
|
|||||||
+213
-213
@@ -1,213 +1,213 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CachedResponseImpl
|
* CachedResponseImpl
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: CachedResponseImpl.java#4 $
|
* @version $Id: CachedResponseImpl.java#4 $
|
||||||
*/
|
*/
|
||||||
class CachedResponseImpl implements CachedResponse {
|
class CachedResponseImpl implements CachedResponse {
|
||||||
final protected Map<String, List<String>> headers;
|
final protected Map<String, List<String>> headers;
|
||||||
protected int headersSize;
|
protected int headersSize;
|
||||||
protected ByteArrayOutputStream content = null;
|
protected ByteArrayOutputStream content = null;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
protected CachedResponseImpl() {
|
protected CachedResponseImpl() {
|
||||||
headers = new LinkedHashMap<String, List<String>>(); // Keep headers in insertion order
|
headers = new LinkedHashMap<String, List<String>>(); // Keep headers in insertion order
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use by HTTPCache, when recreating CachedResponses from disk cache
|
// For use by HTTPCache, when recreating CachedResponses from disk cache
|
||||||
CachedResponseImpl(final int pStatus, final LinkedHashMap<String, List<String>> pHeaders, final int pHeaderSize, final byte[] pContent) {
|
CachedResponseImpl(final int pStatus, final LinkedHashMap<String, List<String>> pHeaders, final int pHeaderSize, final byte[] pContent) {
|
||||||
status = pStatus;
|
status = pStatus;
|
||||||
headers = Validate.notNull(pHeaders, "headers");
|
headers = Validate.notNull(pHeaders, "headers");
|
||||||
headersSize = pHeaderSize;
|
headersSize = pHeaderSize;
|
||||||
content = new FastByteArrayOutputStream(pContent);
|
content = new FastByteArrayOutputStream(pContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStatus() {
|
public int getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the cached headers to the response
|
* Writes the cached headers to the response
|
||||||
*
|
*
|
||||||
* @param pResponse the response
|
* @param pResponse the response
|
||||||
*/
|
*/
|
||||||
public void writeHeadersTo(final CacheResponse pResponse) {
|
public void writeHeadersTo(final CacheResponse pResponse) {
|
||||||
String[] headers = getHeaderNames();
|
String[] headers = getHeaderNames();
|
||||||
for (String header : headers) {
|
for (String header : headers) {
|
||||||
// HACK...
|
// HACK...
|
||||||
// Strip away internal headers
|
// Strip away internal headers
|
||||||
if (HTTPCache.HEADER_CACHED_TIME.equals(header)) {
|
if (HTTPCache.HEADER_CACHED_TIME.equals(header)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace Last-Modified with X-Cached-At? See CachedEntityImpl
|
// TODO: Replace Last-Modified with X-Cached-At? See CachedEntityImpl
|
||||||
|
|
||||||
String[] headerValues = getHeaderValues(header);
|
String[] headerValues = getHeaderValues(header);
|
||||||
|
|
||||||
for (int i = 0; i < headerValues.length; i++) {
|
for (int i = 0; i < headerValues.length; i++) {
|
||||||
String headerValue = headerValues[i];
|
String headerValue = headerValues[i];
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
pResponse.setHeader(header, headerValue);
|
pResponse.setHeader(header, headerValue);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pResponse.addHeader(header, headerValue);
|
pResponse.addHeader(header, headerValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the cached content to the response
|
* Writes the cached content to the response
|
||||||
*
|
*
|
||||||
* @param pStream the response stream
|
* @param pStream the response stream
|
||||||
* @throws java.io.IOException
|
* @throws java.io.IOException
|
||||||
*/
|
*/
|
||||||
public void writeContentsTo(final OutputStream pStream) throws IOException {
|
public void writeContentsTo(final OutputStream pStream) throws IOException {
|
||||||
if (content == null) {
|
if (content == null) {
|
||||||
throw new IOException("Cache is null, no content to write.");
|
throw new IOException("Cache is null, no content to write.");
|
||||||
}
|
}
|
||||||
|
|
||||||
content.writeTo(pStream);
|
content.writeTo(pStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the header names of all headers set in this response.
|
* Gets the header names of all headers set in this response.
|
||||||
*
|
*
|
||||||
* @return an array of {@code String}s
|
* @return an array of {@code String}s
|
||||||
*/
|
*/
|
||||||
public String[] getHeaderNames() {
|
public String[] getHeaderNames() {
|
||||||
Set<String> headers = this.headers.keySet();
|
Set<String> headers = this.headers.keySet();
|
||||||
|
|
||||||
return headers.toArray(new String[headers.size()]);
|
return headers.toArray(new String[headers.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all header values set for the given header in this response. If the
|
* Gets all header values set for the given header in this response. If the
|
||||||
* header is not set, {@code null} is returned.
|
* header is not set, {@code null} is returned.
|
||||||
*
|
*
|
||||||
* @param pHeaderName the header name
|
* @param pHeaderName the header name
|
||||||
* @return an array of {@code String}s, or {@code null} if there is no
|
* @return an array of {@code String}s, or {@code null} if there is no
|
||||||
* such header in this response.
|
* such header in this response.
|
||||||
*/
|
*/
|
||||||
public String[] getHeaderValues(final String pHeaderName) {
|
public String[] getHeaderValues(final String pHeaderName) {
|
||||||
List<String> values = headers.get(pHeaderName);
|
List<String> values = headers.get(pHeaderName);
|
||||||
|
|
||||||
return values == null ? null : values.toArray(new String[values.size()]);
|
return values == null ? null : values.toArray(new String[values.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the first header value set for the given header in this response.
|
* Gets the first header value set for the given header in this response.
|
||||||
* If the header is not set, {@code null} is returned.
|
* If the header is not set, {@code null} is returned.
|
||||||
* Useful for headers that don't have multiple values, like
|
* Useful for headers that don't have multiple values, like
|
||||||
* {@code "Content-Type"} or {@code "Content-Length"}.
|
* {@code "Content-Type"} or {@code "Content-Length"}.
|
||||||
*
|
*
|
||||||
* @param pHeaderName the header name
|
* @param pHeaderName the header name
|
||||||
* @return a {@code String}, or {@code null} if there is no
|
* @return a {@code String}, or {@code null} if there is no
|
||||||
* such header in this response.
|
* such header in this response.
|
||||||
*/
|
*/
|
||||||
public String getHeaderValue(final String pHeaderName) {
|
public String getHeaderValue(final String pHeaderName) {
|
||||||
List<String> values = headers.get(pHeaderName);
|
List<String> values = headers.get(pHeaderName);
|
||||||
|
|
||||||
return (values != null && values.size() > 0) ? values.get(0) : null;
|
return (values != null && values.size() > 0) ? values.get(0) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
// content.size() is exact size in bytes, headersSize is an estimate
|
// content.size() is exact size in bytes, headersSize is an estimate
|
||||||
return (content != null ? content.size() : 0) + headersSize;
|
return (content != null ? content.size() : 0) + headersSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(final Object pOther) {
|
public boolean equals(final Object pOther) {
|
||||||
if (this == pOther) {
|
if (this == pOther) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pOther instanceof CachedResponseImpl) {
|
if (pOther instanceof CachedResponseImpl) {
|
||||||
// "Fast"
|
// "Fast"
|
||||||
return equalsImpl((CachedResponseImpl) pOther);
|
return equalsImpl((CachedResponseImpl) pOther);
|
||||||
}
|
}
|
||||||
else if (pOther instanceof CachedResponse) {
|
else if (pOther instanceof CachedResponse) {
|
||||||
// Slow
|
// Slow
|
||||||
return equalsGeneric((CachedResponse) pOther);
|
return equalsGeneric((CachedResponse) pOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean equalsImpl(final CachedResponseImpl pOther) {
|
private boolean equalsImpl(final CachedResponseImpl pOther) {
|
||||||
return headersSize == pOther.headersSize &&
|
return headersSize == pOther.headersSize &&
|
||||||
(content == null ? pOther.content == null : content.equals(pOther.content)) &&
|
(content == null ? pOther.content == null : content.equals(pOther.content)) &&
|
||||||
headers.equals(pOther.headers);
|
headers.equals(pOther.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean equalsGeneric(final CachedResponse pOther) {
|
private boolean equalsGeneric(final CachedResponse pOther) {
|
||||||
if (size() != pOther.size()) {
|
if (size() != pOther.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] headers = getHeaderNames();
|
String[] headers = getHeaderNames();
|
||||||
String[] otherHeaders = pOther.getHeaderNames();
|
String[] otherHeaders = pOther.getHeaderNames();
|
||||||
if (!Arrays.equals(headers, otherHeaders)) {
|
if (!Arrays.equals(headers, otherHeaders)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headers != null) {
|
if (headers != null) {
|
||||||
for (String header : headers) {
|
for (String header : headers) {
|
||||||
String[] values = getHeaderValues(header);
|
String[] values = getHeaderValues(header);
|
||||||
String[] otherValues = pOther.getHeaderValues(header);
|
String[] otherValues = pOther.getHeaderValues(header);
|
||||||
|
|
||||||
if (!Arrays.equals(values, otherValues)) {
|
if (!Arrays.equals(values, otherValues)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result;
|
int result;
|
||||||
result = headers.hashCode();
|
result = headers.hashCode();
|
||||||
result = 29 * result + headersSize;
|
result = 29 * result + headersSize;
|
||||||
result = 37 * result + (content != null ? content.hashCode() : 0);
|
result = 37 * result + (content != null ? content.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1149
-1149
File diff suppressed because it is too large
Load Diff
+272
-272
@@ -1,273 +1,273 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.net.HTTPUtil;
|
import com.twelvemonkeys.net.HTTPUtil;
|
||||||
import com.twelvemonkeys.servlet.ServletResponseStreamDelegate;
|
import com.twelvemonkeys.servlet.ServletResponseStreamDelegate;
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.http.HttpServletResponseWrapper;
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CacheResponseWrapper class description.
|
* CacheResponseWrapper class description.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Based on ideas and code found in the ONJava article
|
* Based on ideas and code found in the ONJava article
|
||||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||||
* Servlet Filters Every Web Application Should Have</a>
|
* Servlet Filters Every Web Application Should Have</a>
|
||||||
* by Jayson Falkner.
|
* by Jayson Falkner.
|
||||||
*
|
*
|
||||||
* @author Jayson Falkner
|
* @author Jayson Falkner
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: SerlvetCacheResponseWrapper.java#2 $
|
* @version $Id: SerlvetCacheResponseWrapper.java#2 $
|
||||||
*/
|
*/
|
||||||
class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
|
class SerlvetCacheResponseWrapper extends HttpServletResponseWrapper {
|
||||||
private ServletResponseStreamDelegate streamDelegate;
|
private ServletResponseStreamDelegate streamDelegate;
|
||||||
|
|
||||||
private CacheResponse cacheResponse;
|
private CacheResponse cacheResponse;
|
||||||
|
|
||||||
private Boolean cacheable;
|
private Boolean cacheable;
|
||||||
private int status;
|
private int status;
|
||||||
|
|
||||||
public SerlvetCacheResponseWrapper(final HttpServletResponse pServletResponse, final CacheResponse pResponse) {
|
public SerlvetCacheResponseWrapper(final HttpServletResponse pServletResponse, final CacheResponse pResponse) {
|
||||||
super(pServletResponse);
|
super(pServletResponse);
|
||||||
cacheResponse = pResponse;
|
cacheResponse = pResponse;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NOTE: This class defers determining if a response is cacheable until the
|
NOTE: This class defers determining if a response is cacheable until the
|
||||||
output stream is needed.
|
output stream is needed.
|
||||||
This it the reason for the somewhat complicated logic in the add/setHeader
|
This it the reason for the somewhat complicated logic in the add/setHeader
|
||||||
methods below.
|
methods below.
|
||||||
*/
|
*/
|
||||||
private void init() {
|
private void init() {
|
||||||
cacheable = null;
|
cacheable = null;
|
||||||
status = SC_OK;
|
status = SC_OK;
|
||||||
streamDelegate = new ServletResponseStreamDelegate(this) {
|
streamDelegate = new ServletResponseStreamDelegate(this) {
|
||||||
protected OutputStream createOutputStream() throws IOException {
|
protected OutputStream createOutputStream() throws IOException {
|
||||||
// Test if this request is really cacheable, otherwise,
|
// Test if this request is really cacheable, otherwise,
|
||||||
// just write through to underlying response, and don't cache
|
// just write through to underlying response, and don't cache
|
||||||
if (isCacheable()) {
|
if (isCacheable()) {
|
||||||
return cacheResponse.getOutputStream();
|
return cacheResponse.getOutputStream();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: We need to tell the cache about this, somehow...
|
// TODO: We need to tell the cache about this, somehow...
|
||||||
writeHeaders(cacheResponse, (HttpServletResponse) getResponse());
|
writeHeaders(cacheResponse, (HttpServletResponse) getResponse());
|
||||||
return super.getOutputStream();
|
return super.getOutputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeHeaders(final CacheResponse pResponse, final HttpServletResponse pServletResponse) {
|
private void writeHeaders(final CacheResponse pResponse, final HttpServletResponse pServletResponse) {
|
||||||
Map<String,List<String>> headers = pResponse.getHeaders();
|
Map<String,List<String>> headers = pResponse.getHeaders();
|
||||||
for (Map.Entry<String, List<String>> header : headers.entrySet()) {
|
for (Map.Entry<String, List<String>> header : headers.entrySet()) {
|
||||||
for (int i = 0; i < header.getValue().size(); i++) {
|
for (int i = 0; i < header.getValue().size(); i++) {
|
||||||
String value = header.getValue().get(i);
|
String value = header.getValue().get(i);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
pServletResponse.setHeader(header.getKey(), value);
|
pServletResponse.setHeader(header.getKey(), value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pServletResponse.addHeader(header.getKey(), value);
|
pServletResponse.addHeader(header.getKey(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCacheable() {
|
public boolean isCacheable() {
|
||||||
// NOTE: Intentionally not synchronized
|
// NOTE: Intentionally not synchronized
|
||||||
if (cacheable == null) {
|
if (cacheable == null) {
|
||||||
cacheable = isCacheableImpl();
|
cacheable = isCacheableImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return cacheable;
|
return cacheable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCacheableImpl() {
|
private boolean isCacheableImpl() {
|
||||||
// TODO: This code is duped in the cache...
|
// TODO: This code is duped in the cache...
|
||||||
if (status != SC_OK) {
|
if (status != SC_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vary: *
|
// Vary: *
|
||||||
List<String> values = cacheResponse.getHeaders().get(HTTPCache.HEADER_VARY);
|
List<String> values = cacheResponse.getHeaders().get(HTTPCache.HEADER_VARY);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if ("*".equals(value)) {
|
if ("*".equals(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache-Control: no-cache, no-store, must-revalidate
|
// Cache-Control: no-cache, no-store, must-revalidate
|
||||||
values = cacheResponse.getHeaders().get(HTTPCache.HEADER_CACHE_CONTROL);
|
values = cacheResponse.getHeaders().get(HTTPCache.HEADER_CACHE_CONTROL);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if (StringUtil.contains(value, "no-cache")
|
if (StringUtil.contains(value, "no-cache")
|
||||||
|| StringUtil.contains(value, "no-store")
|
|| StringUtil.contains(value, "no-store")
|
||||||
|| StringUtil.contains(value, "must-revalidate")) {
|
|| StringUtil.contains(value, "must-revalidate")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pragma: no-cache
|
// Pragma: no-cache
|
||||||
values = cacheResponse.getHeaders().get(HTTPCache.HEADER_PRAGMA);
|
values = cacheResponse.getHeaders().get(HTTPCache.HEADER_PRAGMA);
|
||||||
if (values != null) {
|
if (values != null) {
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
if (StringUtil.contains(value, "no-cache")) {
|
if (StringUtil.contains(value, "no-cache")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushBuffer() throws IOException {
|
public void flushBuffer() throws IOException {
|
||||||
streamDelegate.flushBuffer();
|
streamDelegate.flushBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetBuffer() {
|
public void resetBuffer() {
|
||||||
// Servlet 2.3
|
// Servlet 2.3
|
||||||
streamDelegate.resetBuffer();
|
streamDelegate.resetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.reset();
|
super.reset();
|
||||||
}
|
}
|
||||||
// No else, might be cacheable after all..
|
// No else, might be cacheable after all..
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletOutputStream getOutputStream() throws IOException {
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
return streamDelegate.getOutputStream();
|
return streamDelegate.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrintWriter getWriter() throws IOException {
|
public PrintWriter getWriter() throws IOException {
|
||||||
return streamDelegate.getWriter();
|
return streamDelegate.getWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsHeader(String name) {
|
public boolean containsHeader(String name) {
|
||||||
return cacheResponse.getHeaders().get(name) != null;
|
return cacheResponse.getHeaders().get(name) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendError(int pStatusCode, String msg) throws IOException {
|
public void sendError(int pStatusCode, String msg) throws IOException {
|
||||||
// NOT cacheable
|
// NOT cacheable
|
||||||
status = pStatusCode;
|
status = pStatusCode;
|
||||||
super.sendError(pStatusCode, msg);
|
super.sendError(pStatusCode, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendError(int pStatusCode) throws IOException {
|
public void sendError(int pStatusCode) throws IOException {
|
||||||
// NOT cacheable
|
// NOT cacheable
|
||||||
status = pStatusCode;
|
status = pStatusCode;
|
||||||
super.sendError(pStatusCode);
|
super.sendError(pStatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(int pStatusCode, String sm) {
|
public void setStatus(int pStatusCode, String sm) {
|
||||||
// NOTE: This method is deprecated
|
// NOTE: This method is deprecated
|
||||||
setStatus(pStatusCode);
|
setStatus(pStatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(int pStatusCode) {
|
public void setStatus(int pStatusCode) {
|
||||||
// NOT cacheable unless pStatusCode == 200 (or a FEW others?)
|
// NOT cacheable unless pStatusCode == 200 (or a FEW others?)
|
||||||
if (pStatusCode != SC_OK) {
|
if (pStatusCode != SC_OK) {
|
||||||
status = pStatusCode;
|
status = pStatusCode;
|
||||||
super.setStatus(pStatusCode);
|
super.setStatus(pStatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendRedirect(String pLocation) throws IOException {
|
public void sendRedirect(String pLocation) throws IOException {
|
||||||
// NOT cacheable
|
// NOT cacheable
|
||||||
status = SC_MOVED_TEMPORARILY;
|
status = SC_MOVED_TEMPORARILY;
|
||||||
super.sendRedirect(pLocation);
|
super.sendRedirect(pLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDateHeader(String pName, long pValue) {
|
public void setDateHeader(String pName, long pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.setDateHeader(pName, pValue);
|
super.setDateHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cacheResponse.setHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
cacheResponse.setHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDateHeader(String pName, long pValue) {
|
public void addDateHeader(String pName, long pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.addDateHeader(pName, pValue);
|
super.addDateHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cacheResponse.addHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
cacheResponse.addHeader(pName, HTTPUtil.formatHTTPDate(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeader(String pName, String pValue) {
|
public void setHeader(String pName, String pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.setHeader(pName, pValue);
|
super.setHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cacheResponse.setHeader(pName, pValue);
|
cacheResponse.setHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHeader(String pName, String pValue) {
|
public void addHeader(String pName, String pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.addHeader(pName, pValue);
|
super.addHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cacheResponse.addHeader(pName, pValue);
|
cacheResponse.addHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIntHeader(String pName, int pValue) {
|
public void setIntHeader(String pName, int pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.setIntHeader(pName, pValue);
|
super.setIntHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cacheResponse.setHeader(pName, String.valueOf(pValue));
|
cacheResponse.setHeader(pName, String.valueOf(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIntHeader(String pName, int pValue) {
|
public void addIntHeader(String pName, int pValue) {
|
||||||
// If in write-trough-mode, set headers directly
|
// If in write-trough-mode, set headers directly
|
||||||
if (Boolean.FALSE.equals(cacheable)) {
|
if (Boolean.FALSE.equals(cacheable)) {
|
||||||
super.addIntHeader(pName, pValue);
|
super.addIntHeader(pName, pValue);
|
||||||
}
|
}
|
||||||
cacheResponse.addHeader(pName, String.valueOf(pValue));
|
cacheResponse.addHeader(pName, String.valueOf(pValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setContentType(String type) {
|
public final void setContentType(String type) {
|
||||||
setHeader(HTTPCache.HEADER_CONTENT_TYPE, type);
|
setHeader(HTTPCache.HEADER_CONTENT_TYPE, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+77
-77
@@ -1,77 +1,77 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WritableCachedResponse
|
* WritableCachedResponse
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: WritableCachedResponse.java#2 $
|
* @version $Id: WritableCachedResponse.java#2 $
|
||||||
*/
|
*/
|
||||||
public interface WritableCachedResponse extends CachedResponse, CacheResponse {
|
public interface WritableCachedResponse extends CachedResponse, CacheResponse {
|
||||||
/**
|
/**
|
||||||
* Gets the {@code OutputStream} for this cached response.
|
* Gets the {@code OutputStream} for this cached response.
|
||||||
* This allows a client to write to the cached response.
|
* This allows a client to write to the cached response.
|
||||||
*
|
*
|
||||||
* @return the {@code OutputStream} for this response.
|
* @return the {@code OutputStream} for this response.
|
||||||
*/
|
*/
|
||||||
OutputStream getOutputStream();
|
OutputStream getOutputStream();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a header key/value pair for this response.
|
* Sets a header key/value pair for this response.
|
||||||
* Any prior header value for the given header key will be overwritten.
|
* Any prior header value for the given header key will be overwritten.
|
||||||
*
|
*
|
||||||
* @see #addHeader(String, String)
|
* @see #addHeader(String, String)
|
||||||
*
|
*
|
||||||
* @param pName the header name
|
* @param pName the header name
|
||||||
* @param pValue the header value
|
* @param pValue the header value
|
||||||
*/
|
*/
|
||||||
void setHeader(String pName, String pValue);
|
void setHeader(String pName, String pValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a header key/value pair for this response.
|
* Adds a header key/value pair for this response.
|
||||||
* If a value allready exists for the given key, the value will be appended.
|
* If a value allready exists for the given key, the value will be appended.
|
||||||
*
|
*
|
||||||
* @see #setHeader(String, String)
|
* @see #setHeader(String, String)
|
||||||
*
|
*
|
||||||
* @param pName the header name
|
* @param pName the header name
|
||||||
* @param pValue the header value
|
* @param pValue the header value
|
||||||
*/
|
*/
|
||||||
void addHeader(String pName, String pValue);
|
void addHeader(String pName, String pValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the final (immutable) {@code CachedResponse} created by this
|
* Returns the final (immutable) {@code CachedResponse} created by this
|
||||||
* {@code WritableCachedResponse}.
|
* {@code WritableCachedResponse}.
|
||||||
*
|
*
|
||||||
* @return the {@code CachedResponse}
|
* @return the {@code CachedResponse}
|
||||||
*/
|
*/
|
||||||
CachedResponse getCachedResponse();
|
CachedResponse getCachedResponse();
|
||||||
}
|
}
|
||||||
|
|||||||
+185
-185
@@ -1,186 +1,186 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.cache;
|
package com.twelvemonkeys.servlet.cache;
|
||||||
|
|
||||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||||
import com.twelvemonkeys.net.HTTPUtil;
|
import com.twelvemonkeys.net.HTTPUtil;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WritableCachedResponseImpl
|
* WritableCachedResponseImpl
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: WritableCachedResponseImpl.java#3 $
|
* @version $Id: WritableCachedResponseImpl.java#3 $
|
||||||
*/
|
*/
|
||||||
class WritableCachedResponseImpl implements WritableCachedResponse {
|
class WritableCachedResponseImpl implements WritableCachedResponse {
|
||||||
private final CachedResponseImpl cachedResponse;
|
private final CachedResponseImpl cachedResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@code WritableCachedResponseImpl}.
|
* Creates a {@code WritableCachedResponseImpl}.
|
||||||
*/
|
*/
|
||||||
protected WritableCachedResponseImpl() {
|
protected WritableCachedResponseImpl() {
|
||||||
cachedResponse = new CachedResponseImpl();
|
cachedResponse = new CachedResponseImpl();
|
||||||
// Hmmm..
|
// Hmmm..
|
||||||
setHeader(HTTPCache.HEADER_CACHED_TIME, HTTPUtil.formatHTTPDate(System.currentTimeMillis()));
|
setHeader(HTTPCache.HEADER_CACHED_TIME, HTTPUtil.formatHTTPDate(System.currentTimeMillis()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedResponse getCachedResponse() {
|
public CachedResponse getCachedResponse() {
|
||||||
return cachedResponse;
|
return cachedResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeader(String pName, String pValue) {
|
public void setHeader(String pName, String pValue) {
|
||||||
setHeader(pName, pValue, false);
|
setHeader(pName, pValue, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHeader(String pName, String pValue) {
|
public void addHeader(String pName, String pValue) {
|
||||||
setHeader(pName, pValue, true);
|
setHeader(pName, pValue, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, List<String>> getHeaders() {
|
public Map<String, List<String>> getHeaders() {
|
||||||
return cachedResponse.headers;
|
return cachedResponse.headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param pName the header name
|
* @param pName the header name
|
||||||
* @param pValue the new header value
|
* @param pValue the new header value
|
||||||
* @param pAdd {@code true} if the value should add to the list of values, not replace existing value
|
* @param pAdd {@code true} if the value should add to the list of values, not replace existing value
|
||||||
*/
|
*/
|
||||||
private void setHeader(String pName, String pValue, boolean pAdd) {
|
private void setHeader(String pName, String pValue, boolean pAdd) {
|
||||||
// System.out.println(" ++ CachedResponse ++ " + (pAdd ? "addHeader(" : "setHeader(") + pName + ", " + pValue + ")");
|
// System.out.println(" ++ CachedResponse ++ " + (pAdd ? "addHeader(" : "setHeader(") + pName + ", " + pValue + ")");
|
||||||
// If adding, get list and append, otherwise replace list
|
// If adding, get list and append, otherwise replace list
|
||||||
List<String> values = pAdd ? cachedResponse.headers.get(pName) : null;
|
List<String> values = pAdd ? cachedResponse.headers.get(pName) : null;
|
||||||
|
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
values = new ArrayList<String>();
|
values = new ArrayList<String>();
|
||||||
|
|
||||||
if (pAdd) {
|
if (pAdd) {
|
||||||
// Add length of pName
|
// Add length of pName
|
||||||
cachedResponse.headersSize += (pName != null ? pName.length() : 0);
|
cachedResponse.headersSize += (pName != null ? pName.length() : 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Remove length of potential replaced old values + pName
|
// Remove length of potential replaced old values + pName
|
||||||
String[] oldValues = getHeaderValues(pName);
|
String[] oldValues = getHeaderValues(pName);
|
||||||
|
|
||||||
if (oldValues != null) {
|
if (oldValues != null) {
|
||||||
for (String oldValue : oldValues) {
|
for (String oldValue : oldValues) {
|
||||||
cachedResponse.headersSize -= oldValue.length();
|
cachedResponse.headersSize -= oldValue.length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cachedResponse.headersSize += (pName != null ? pName.length() : 0);
|
cachedResponse.headersSize += (pName != null ? pName.length() : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add value, if not null
|
// Add value, if not null
|
||||||
if (pValue != null) {
|
if (pValue != null) {
|
||||||
values.add(pValue);
|
values.add(pValue);
|
||||||
|
|
||||||
// Add length of pValue
|
// Add length of pValue
|
||||||
cachedResponse.headersSize += pValue.length();
|
cachedResponse.headersSize += pValue.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always add to headers
|
// Always add to headers
|
||||||
cachedResponse.headers.put(pName, values);
|
cachedResponse.headers.put(pName, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() {
|
||||||
// TODO: Hmm.. Smells like DCL..?
|
// TODO: Hmm.. Smells like DCL..?
|
||||||
if (cachedResponse.content == null) {
|
if (cachedResponse.content == null) {
|
||||||
createOutputStream();
|
createOutputStream();
|
||||||
}
|
}
|
||||||
return cachedResponse.content;
|
return cachedResponse.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(int pStatusCode) {
|
public void setStatus(int pStatusCode) {
|
||||||
cachedResponse.status = pStatusCode;
|
cachedResponse.status = pStatusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStatus() {
|
public int getStatus() {
|
||||||
return cachedResponse.getStatus();
|
return cachedResponse.getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void createOutputStream() {
|
private synchronized void createOutputStream() {
|
||||||
ByteArrayOutputStream cache = cachedResponse.content;
|
ByteArrayOutputStream cache = cachedResponse.content;
|
||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
String contentLengthStr = getHeaderValue("Content-Length");
|
String contentLengthStr = getHeaderValue("Content-Length");
|
||||||
if (contentLengthStr != null) {
|
if (contentLengthStr != null) {
|
||||||
int contentLength = Integer.parseInt(contentLengthStr);
|
int contentLength = Integer.parseInt(contentLengthStr);
|
||||||
cache = new FastByteArrayOutputStream(contentLength);
|
cache = new FastByteArrayOutputStream(contentLength);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cache = new FastByteArrayOutputStream(1024);
|
cache = new FastByteArrayOutputStream(1024);
|
||||||
}
|
}
|
||||||
cachedResponse.content = cache;
|
cachedResponse.content = cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeHeadersTo(CacheResponse pResponse) {
|
public void writeHeadersTo(CacheResponse pResponse) {
|
||||||
cachedResponse.writeHeadersTo(pResponse);
|
cachedResponse.writeHeadersTo(pResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeContentsTo(OutputStream pStream) throws IOException {
|
public void writeContentsTo(OutputStream pStream) throws IOException {
|
||||||
cachedResponse.writeContentsTo(pStream);
|
cachedResponse.writeContentsTo(pStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getHeaderNames() {
|
public String[] getHeaderNames() {
|
||||||
return cachedResponse.getHeaderNames();
|
return cachedResponse.getHeaderNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getHeaderValues(String pHeaderName) {
|
public String[] getHeaderValues(String pHeaderName) {
|
||||||
return cachedResponse.getHeaderValues(pHeaderName);
|
return cachedResponse.getHeaderValues(pHeaderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHeaderValue(String pHeaderName) {
|
public String getHeaderValue(String pHeaderName) {
|
||||||
return cachedResponse.getHeaderValue(pHeaderName);
|
return cachedResponse.getHeaderValue(pHeaderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return cachedResponse.size();
|
return cachedResponse.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object pOther) {
|
public boolean equals(Object pOther) {
|
||||||
if (pOther instanceof WritableCachedResponse) {
|
if (pOther instanceof WritableCachedResponse) {
|
||||||
// Take advantage of faster implementation
|
// Take advantage of faster implementation
|
||||||
return cachedResponse.equals(((WritableCachedResponse) pOther).getCachedResponse());
|
return cachedResponse.equals(((WritableCachedResponse) pOther).getCachedResponse());
|
||||||
}
|
}
|
||||||
return cachedResponse.equals(pOther);
|
return cachedResponse.equals(pOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return cachedResponse.hashCode();
|
return cachedResponse.hashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+42
-42
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.fileupload;
|
package com.twelvemonkeys.servlet.fileupload;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FileSizeExceededException
|
* FileSizeExceededException
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: FileSizeExceededException.java#1 $
|
* @version $Id: FileSizeExceededException.java#1 $
|
||||||
*/
|
*/
|
||||||
public class FileSizeExceededException extends FileUploadException {
|
public class FileSizeExceededException extends FileUploadException {
|
||||||
public FileSizeExceededException(Throwable pCause) {
|
public FileSizeExceededException(Throwable pCause) {
|
||||||
super(pCause.getMessage(), pCause);
|
super(pCause.getMessage(), pCause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-52
@@ -1,52 +1,52 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.fileupload;
|
package com.twelvemonkeys.servlet.fileupload;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FileUploadException
|
* FileUploadException
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: FileUploadException.java#1 $
|
* @version $Id: FileUploadException.java#1 $
|
||||||
*/
|
*/
|
||||||
public class FileUploadException extends ServletException {
|
public class FileUploadException extends ServletException {
|
||||||
public FileUploadException(String pMessage) {
|
public FileUploadException(String pMessage) {
|
||||||
super(pMessage);
|
super(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileUploadException(String pMessage, Throwable pCause) {
|
public FileUploadException(String pMessage, Throwable pCause) {
|
||||||
super(pMessage, pCause);
|
super(pMessage, pCause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileUploadException(Throwable pCause) {
|
public FileUploadException(Throwable pCause) {
|
||||||
super(pCause.getMessage(), pCause);
|
super(pCause.getMessage(), pCause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+125
-125
@@ -1,125 +1,125 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.fileupload;
|
package com.twelvemonkeys.servlet.fileupload;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.GenericFilter;
|
import com.twelvemonkeys.servlet.GenericFilter;
|
||||||
import com.twelvemonkeys.servlet.ServletUtil;
|
import com.twelvemonkeys.servlet.ServletUtil;
|
||||||
import com.twelvemonkeys.io.FileUtil;
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A servlet {@code Filter} for processing HTTP file upload requests, as
|
* A servlet {@code Filter} for processing HTTP file upload requests, as
|
||||||
* specified by
|
* specified by
|
||||||
* <a href="http://www.ietf.org/rfc/rfc1867.txt">Form-based File Upload in HTML (RFC1867)</a>.
|
* <a href="http://www.ietf.org/rfc/rfc1867.txt">Form-based File Upload in HTML (RFC1867)</a>.
|
||||||
*
|
*
|
||||||
* @see HttpFileUploadRequest
|
* @see HttpFileUploadRequest
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: FileUploadFilter.java#1 $
|
* @version $Id: FileUploadFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
public class FileUploadFilter extends GenericFilter {
|
public class FileUploadFilter extends GenericFilter {
|
||||||
private File uploadDir;
|
private File uploadDir;
|
||||||
private long maxFileSize = 1024 * 1024; // 1 MByte
|
private long maxFileSize = 1024 * 1024; // 1 MByte
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called by the server before the filter goes into service,
|
* This method is called by the server before the filter goes into service,
|
||||||
* and here it determines the file upload directory.
|
* and here it determines the file upload directory.
|
||||||
*
|
*
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*/
|
*/
|
||||||
public void init() throws ServletException {
|
public void init() throws ServletException {
|
||||||
// Get the name of the upload directory.
|
// Get the name of the upload directory.
|
||||||
String uploadDirParam = getInitParameter("uploadDir");
|
String uploadDirParam = getInitParameter("uploadDir");
|
||||||
|
|
||||||
if (!StringUtil.isEmpty(uploadDirParam)) {
|
if (!StringUtil.isEmpty(uploadDirParam)) {
|
||||||
try {
|
try {
|
||||||
URL uploadDirURL = getServletContext().getResource(uploadDirParam);
|
URL uploadDirURL = getServletContext().getResource(uploadDirParam);
|
||||||
uploadDir = FileUtil.toFile(uploadDirURL);
|
uploadDir = FileUtil.toFile(uploadDirURL);
|
||||||
}
|
}
|
||||||
catch (MalformedURLException e) {
|
catch (MalformedURLException e) {
|
||||||
throw new ServletException(e.getMessage(), e);
|
throw new ServletException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uploadDir == null) {
|
if (uploadDir == null) {
|
||||||
uploadDir = ServletUtil.getTempDir(getServletContext());
|
uploadDir = ServletUtil.getTempDir(getServletContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets max filesize allowed for upload.
|
* Sets max filesize allowed for upload.
|
||||||
* <!-- used by automagic init -->
|
* <!-- used by automagic init -->
|
||||||
*
|
*
|
||||||
* @param pMaxSize
|
* @param pMaxSize
|
||||||
*/
|
*/
|
||||||
public void setMaxFileSize(long pMaxSize) {
|
public void setMaxFileSize(long pMaxSize) {
|
||||||
log("maxFileSize=" + pMaxSize);
|
log("maxFileSize=" + pMaxSize);
|
||||||
maxFileSize = pMaxSize;
|
maxFileSize = pMaxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Examines the request content type, and if it is a
|
* Examines the request content type, and if it is a
|
||||||
* {@code multipart/*} request, wraps the request with a
|
* {@code multipart/*} request, wraps the request with a
|
||||||
* {@code HttpFileUploadRequest}.
|
* {@code HttpFileUploadRequest}.
|
||||||
*
|
*
|
||||||
* @param pRequest The servlet request
|
* @param pRequest The servlet request
|
||||||
* @param pResponse The servlet response
|
* @param pResponse The servlet response
|
||||||
* @param pChain The filter chain
|
* @param pChain The filter chain
|
||||||
*
|
*
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
public void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||||
|
|
||||||
// Get the content type from the request
|
// Get the content type from the request
|
||||||
String contentType = request.getContentType();
|
String contentType = request.getContentType();
|
||||||
|
|
||||||
// If the content type is multipart, wrap
|
// If the content type is multipart, wrap
|
||||||
if (isMultipartFileUpload(contentType)) {
|
if (isMultipartFileUpload(contentType)) {
|
||||||
pRequest = new HttpFileUploadRequestWrapper(request, uploadDir, maxFileSize);
|
pRequest = new HttpFileUploadRequestWrapper(request, uploadDir, maxFileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
pChain.doFilter(pRequest, pResponse);
|
pChain.doFilter(pRequest, pResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMultipartFileUpload(String pContentType) {
|
private boolean isMultipartFileUpload(String pContentType) {
|
||||||
return pContentType != null && pContentType.startsWith("multipart/");
|
return pContentType != null && pContentType.startsWith("multipart/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-63
@@ -1,63 +1,63 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.fileupload;
|
package com.twelvemonkeys.servlet.fileupload;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface represents an HTTP file upload request, as specified by
|
* This interface represents an HTTP file upload request, as specified by
|
||||||
* <a href="http://www.ietf.org/rfc/rfc1867.txt">Form-based File Upload in HTML (RFC1867)</a>.
|
* <a href="http://www.ietf.org/rfc/rfc1867.txt">Form-based File Upload in HTML (RFC1867)</a>.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: HttpFileUploadRequest.java#1 $
|
* @version $Id: HttpFileUploadRequest.java#1 $
|
||||||
*/
|
*/
|
||||||
public interface HttpFileUploadRequest extends HttpServletRequest {
|
public interface HttpFileUploadRequest extends HttpServletRequest {
|
||||||
/**
|
/**
|
||||||
* Returns the value of a request parameter as an {@code UploadedFile},
|
* Returns the value of a request parameter as an {@code UploadedFile},
|
||||||
* or {@code null} if the parameter does not exist.
|
* or {@code null} if the parameter does not exist.
|
||||||
* You should only use this method when you are sure the parameter has only
|
* You should only use this method when you are sure the parameter has only
|
||||||
* one value.
|
* one value.
|
||||||
*
|
*
|
||||||
* @param pName the name of the requested parameter
|
* @param pName the name of the requested parameter
|
||||||
* @return a {@code UoploadedFile} or {@code null}
|
* @return a {@code UoploadedFile} or {@code null}
|
||||||
*
|
*
|
||||||
* @see #getUploadedFiles(String)
|
* @see #getUploadedFiles(String)
|
||||||
*/
|
*/
|
||||||
UploadedFile getUploadedFile(String pName);
|
UploadedFile getUploadedFile(String pName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of {@code UploadedFile} objects containing all the
|
* Returns an array of {@code UploadedFile} objects containing all the
|
||||||
* values for the given request parameter,
|
* values for the given request parameter,
|
||||||
* or {@code null} if the parameter does not exist.
|
* or {@code null} if the parameter does not exist.
|
||||||
*
|
*
|
||||||
* @param pName the name of the requested parameter
|
* @param pName the name of the requested parameter
|
||||||
* @return an array of {@code UoploadedFile}s or {@code null}
|
* @return an array of {@code UoploadedFile}s or {@code null}
|
||||||
*/
|
*/
|
||||||
UploadedFile[] getUploadedFiles(String pName);
|
UploadedFile[] getUploadedFiles(String pName);
|
||||||
}
|
}
|
||||||
|
|||||||
+153
-153
@@ -1,154 +1,154 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.fileupload;
|
package com.twelvemonkeys.servlet.fileupload;
|
||||||
|
|
||||||
import org.apache.commons.fileupload.*;
|
import org.apache.commons.fileupload.*;
|
||||||
import org.apache.commons.fileupload.servlet.ServletRequestContext;
|
import org.apache.commons.fileupload.servlet.ServletRequestContext;
|
||||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequestWrapper;
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@code HttpFileUploadRequest} implementation, based on
|
* An {@code HttpFileUploadRequest} implementation, based on
|
||||||
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
|
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: HttpFileUploadRequestWrapper.java#1 $
|
* @version $Id: HttpFileUploadRequestWrapper.java#1 $
|
||||||
*/
|
*/
|
||||||
class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest {
|
class HttpFileUploadRequestWrapper extends HttpServletRequestWrapper implements HttpFileUploadRequest {
|
||||||
|
|
||||||
private final Map<String, String[]> parameters = new HashMap<String, String[]>();
|
private final Map<String, String[]> parameters = new HashMap<String, String[]>();
|
||||||
private final Map<String, UploadedFile[]> files = new HashMap<String, UploadedFile[]>();
|
private final Map<String, UploadedFile[]> files = new HashMap<String, UploadedFile[]>();
|
||||||
|
|
||||||
public HttpFileUploadRequestWrapper(HttpServletRequest pRequest, File pUploadDir, long pMaxSize) throws ServletException {
|
public HttpFileUploadRequestWrapper(HttpServletRequest pRequest, File pUploadDir, long pMaxSize) throws ServletException {
|
||||||
super(pRequest);
|
super(pRequest);
|
||||||
|
|
||||||
DiskFileItemFactory factory = new DiskFileItemFactory(
|
DiskFileItemFactory factory = new DiskFileItemFactory(
|
||||||
128 * 1024, // 128 KByte
|
128 * 1024, // 128 KByte
|
||||||
new File(pUploadDir.getAbsolutePath())
|
new File(pUploadDir.getAbsolutePath())
|
||||||
);
|
);
|
||||||
FileUpload upload = new FileUpload(factory);
|
FileUpload upload = new FileUpload(factory);
|
||||||
upload.setSizeMax(pMaxSize);
|
upload.setSizeMax(pMaxSize);
|
||||||
|
|
||||||
// TODO: Defer request parsing??
|
// TODO: Defer request parsing??
|
||||||
try {
|
try {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
List<FileItem> items = upload.parseRequest(new ServletRequestContext(pRequest));
|
List<FileItem> items = upload.parseRequest(new ServletRequestContext(pRequest));
|
||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
if (item.isFormField()) {
|
if (item.isFormField()) {
|
||||||
processFormField(item.getFieldName(), item.getString());
|
processFormField(item.getFieldName(), item.getString());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
processeFile(item);
|
processeFile(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (FileUploadBase.SizeLimitExceededException e) {
|
catch (FileUploadBase.SizeLimitExceededException e) {
|
||||||
throw new FileSizeExceededException(e);
|
throw new FileSizeExceededException(e);
|
||||||
}
|
}
|
||||||
catch (org.apache.commons.fileupload.FileUploadException e) {
|
catch (org.apache.commons.fileupload.FileUploadException e) {
|
||||||
throw new FileUploadException(e);
|
throw new FileUploadException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processeFile(final FileItem pItem) {
|
private void processeFile(final FileItem pItem) {
|
||||||
UploadedFile value = new UploadedFileImpl(pItem);
|
UploadedFile value = new UploadedFileImpl(pItem);
|
||||||
String name = pItem.getFieldName();
|
String name = pItem.getFieldName();
|
||||||
|
|
||||||
UploadedFile[] values;
|
UploadedFile[] values;
|
||||||
UploadedFile[] oldValues = files.get(name);
|
UploadedFile[] oldValues = files.get(name);
|
||||||
|
|
||||||
if (oldValues != null) {
|
if (oldValues != null) {
|
||||||
values = new UploadedFile[oldValues.length + 1];
|
values = new UploadedFile[oldValues.length + 1];
|
||||||
System.arraycopy(oldValues, 0, values, 0, oldValues.length);
|
System.arraycopy(oldValues, 0, values, 0, oldValues.length);
|
||||||
values[oldValues.length] = value;
|
values[oldValues.length] = value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
values = new UploadedFile[] {value};
|
values = new UploadedFile[] {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
files.put(name, values);
|
files.put(name, values);
|
||||||
|
|
||||||
// Also add to normal fields
|
// Also add to normal fields
|
||||||
processFormField(name, value.getName());
|
processFormField(name, value.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processFormField(String pName, String pValue) {
|
private void processFormField(String pName, String pValue) {
|
||||||
// Multiple parameter values are not that common, so it's
|
// Multiple parameter values are not that common, so it's
|
||||||
// probably faster to just use arrays...
|
// probably faster to just use arrays...
|
||||||
// TODO: Research and document...
|
// TODO: Research and document...
|
||||||
String[] values;
|
String[] values;
|
||||||
String[] oldValues = parameters.get(pName);
|
String[] oldValues = parameters.get(pName);
|
||||||
|
|
||||||
if (oldValues != null) {
|
if (oldValues != null) {
|
||||||
values = new String[oldValues.length + 1];
|
values = new String[oldValues.length + 1];
|
||||||
System.arraycopy(oldValues, 0, values, 0, oldValues.length);
|
System.arraycopy(oldValues, 0, values, 0, oldValues.length);
|
||||||
values[oldValues.length] = pValue;
|
values[oldValues.length] = pValue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
values = new String[] {pValue};
|
values = new String[] {pValue};
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters.put(pName, values);
|
parameters.put(pName, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map getParameterMap() {
|
public Map getParameterMap() {
|
||||||
// TODO: The spec dicates immutable map, but what about the value arrays?!
|
// TODO: The spec dicates immutable map, but what about the value arrays?!
|
||||||
// Probably just leave as-is, for performance
|
// Probably just leave as-is, for performance
|
||||||
return Collections.unmodifiableMap(parameters);
|
return Collections.unmodifiableMap(parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getParameterNames() {
|
public Enumeration getParameterNames() {
|
||||||
return Collections.enumeration(parameters.keySet());
|
return Collections.enumeration(parameters.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParameter(String pString) {
|
public String getParameter(String pString) {
|
||||||
String[] values = getParameterValues(pString);
|
String[] values = getParameterValues(pString);
|
||||||
return values != null ? values[0] : null;
|
return values != null ? values[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getParameterValues(String pString) {
|
public String[] getParameterValues(String pString) {
|
||||||
// TODO: Optimize?
|
// TODO: Optimize?
|
||||||
return parameters.get(pString).clone();
|
return parameters.get(pString).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UploadedFile getUploadedFile(String pName) {
|
public UploadedFile getUploadedFile(String pName) {
|
||||||
UploadedFile[] files = getUploadedFiles(pName);
|
UploadedFile[] files = getUploadedFiles(pName);
|
||||||
return files != null ? files[0] : null;
|
return files != null ? files[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UploadedFile[] getUploadedFiles(String pName) {
|
public UploadedFile[] getUploadedFiles(String pName) {
|
||||||
// TODO: Optimize?
|
// TODO: Optimize?
|
||||||
return files.get(pName).clone();
|
return files.get(pName).clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,86 +1,86 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.fileupload;
|
package com.twelvemonkeys.servlet.fileupload;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents an uploaded file.
|
* This class represents an uploaded file.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: UploadedFile.java#1 $
|
* @version $Id: UploadedFile.java#1 $
|
||||||
*/
|
*/
|
||||||
public interface UploadedFile {
|
public interface UploadedFile {
|
||||||
/**
|
/**
|
||||||
* Returns the length of file, in bytes.
|
* Returns the length of file, in bytes.
|
||||||
*
|
*
|
||||||
* @return length of file
|
* @return length of file
|
||||||
*/
|
*/
|
||||||
long length();
|
long length();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the original file name (from client).
|
* Returns the original file name (from client).
|
||||||
*
|
*
|
||||||
* @return original name
|
* @return original name
|
||||||
*/
|
*/
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content type of the file.
|
* Returns the content type of the file.
|
||||||
*
|
*
|
||||||
* @return the content type
|
* @return the content type
|
||||||
*/
|
*/
|
||||||
String getContentType();
|
String getContentType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the file data, as an {@code InputStream}.
|
* Returns the file data, as an {@code InputStream}.
|
||||||
* The file data may be read from disk, or from an in-memory source,
|
* The file data may be read from disk, or from an in-memory source,
|
||||||
* depending on implementation.
|
* depending on implementation.
|
||||||
*
|
*
|
||||||
* @return an {@code InputStream} containing the file data
|
* @return an {@code InputStream} containing the file data
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
InputStream getInputStream() throws IOException;
|
InputStream getInputStream() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the file data to the given {@code File}.
|
* Writes the file data to the given {@code File}.
|
||||||
* Note that implementations are free to optimize this to a rename
|
* Note that implementations are free to optimize this to a rename
|
||||||
* operation, if the file is allready cached to disk.
|
* operation, if the file is allready cached to disk.
|
||||||
*
|
*
|
||||||
* @param pFile the {@code File} (file name) to write to.
|
* @param pFile the {@code File} (file name) to write to.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
void writeTo(File pFile) throws IOException;
|
void writeTo(File pFile) throws IOException;
|
||||||
|
|
||||||
// TODO: void delete()?
|
// TODO: void delete()?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,91 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.fileupload;
|
package com.twelvemonkeys.servlet.fileupload;
|
||||||
|
|
||||||
import org.apache.commons.fileupload.FileItem;
|
import org.apache.commons.fileupload.FileItem;
|
||||||
import org.apache.commons.fileupload.FileUploadException;
|
import org.apache.commons.fileupload.FileUploadException;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@code UploadedFile} implementation, based on
|
* An {@code UploadedFile} implementation, based on
|
||||||
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
|
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: UploadedFileImpl.java#1 $
|
* @version $Id: UploadedFileImpl.java#1 $
|
||||||
*/
|
*/
|
||||||
class UploadedFileImpl implements UploadedFile {
|
class UploadedFileImpl implements UploadedFile {
|
||||||
private final FileItem item;
|
private final FileItem item;
|
||||||
|
|
||||||
public UploadedFileImpl(FileItem pItem) {
|
public UploadedFileImpl(FileItem pItem) {
|
||||||
if (pItem == null) {
|
if (pItem == null) {
|
||||||
throw new IllegalArgumentException("fileitem == null");
|
throw new IllegalArgumentException("fileitem == null");
|
||||||
}
|
}
|
||||||
|
|
||||||
item = pItem;
|
item = pItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContentType() {
|
public String getContentType() {
|
||||||
return item.getContentType();
|
return item.getContentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getInputStream() throws IOException {
|
public InputStream getInputStream() throws IOException {
|
||||||
return item.getInputStream();
|
return item.getInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return item.getName();
|
return item.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long length() {
|
public long length() {
|
||||||
return item.getSize();
|
return item.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(File pFile) throws IOException {
|
public void writeTo(File pFile) throws IOException {
|
||||||
try {
|
try {
|
||||||
item.write(pFile);
|
item.write(pFile);
|
||||||
}
|
}
|
||||||
catch(RuntimeException e) {
|
catch(RuntimeException e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
catch (FileUploadException e) {
|
catch (FileUploadException e) {
|
||||||
// We deliberately change this exception to an IOException, as it really is
|
// We deliberately change this exception to an IOException, as it really is
|
||||||
throw (IOException) new IOException(e.getMessage()).initCause(e);
|
throw (IOException) new IOException(e.getMessage()).initCause(e);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// Should not really happen, ever
|
// Should not really happen, ever
|
||||||
throw new RuntimeException(e.getMessage(), e);
|
throw new RuntimeException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,141 +1,141 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.gzip;
|
package com.twelvemonkeys.servlet.gzip;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.GenericFilter;
|
import com.twelvemonkeys.servlet.GenericFilter;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filter to reduce the output size of web resources.
|
* A filter to reduce the output size of web resources.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The HTTP protocol supports compression of the content to reduce network
|
* The HTTP protocol supports compression of the content to reduce network
|
||||||
* bandwidth. The important headers involved, are the {@code Accept-Encoding}
|
* bandwidth. The important headers involved, are the {@code Accept-Encoding}
|
||||||
* request header, and the {@code Content-Encoding} response header.
|
* request header, and the {@code Content-Encoding} response header.
|
||||||
* This feature can be used to further reduce the number of bytes transferred
|
* This feature can be used to further reduce the number of bytes transferred
|
||||||
* over the network, at the cost of some extra processing time at both endpoints.
|
* over the network, at the cost of some extra processing time at both endpoints.
|
||||||
* Most modern browsers supports compression in GZIP format, which is fairly
|
* Most modern browsers supports compression in GZIP format, which is fairly
|
||||||
* efficient in cost/compression ratio.
|
* efficient in cost/compression ratio.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The filter tests for the presence of an {@code Accept-Encoding} header with a
|
* The filter tests for the presence of an {@code Accept-Encoding} header with a
|
||||||
* value of {@code "gzip"} (several different encoding header values are
|
* value of {@code "gzip"} (several different encoding header values are
|
||||||
* possible in one header). If not present, the filter simply passes the
|
* possible in one header). If not present, the filter simply passes the
|
||||||
* request/response pair through, leaving it untouched. If present, the
|
* request/response pair through, leaving it untouched. If present, the
|
||||||
* {@code Content-Encoding} header is set, with the value {@code "gzip"},
|
* {@code Content-Encoding} header is set, with the value {@code "gzip"},
|
||||||
* and the response is wrapped.
|
* and the response is wrapped.
|
||||||
* The response output stream is wrapped in a
|
* The response output stream is wrapped in a
|
||||||
* {@link java.util.zip.GZIPOutputStream} which performs the GZIP encoding.
|
* {@link java.util.zip.GZIPOutputStream} which performs the GZIP encoding.
|
||||||
* For efficiency, the filter does not buffer the response, but writes through
|
* For efficiency, the filter does not buffer the response, but writes through
|
||||||
* the gzipped output stream.
|
* the gzipped output stream.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <b>Configuration</b><br/>
|
* <b>Configuration</b><br/>
|
||||||
* To use {@code GZIPFilter} in your web-application, you simply need to add it
|
* To use {@code GZIPFilter} in your web-application, you simply need to add it
|
||||||
* to your web descriptor ({@code web.xml}). If using a servlet container that
|
* to your web descriptor ({@code web.xml}). If using a servlet container that
|
||||||
* supports the Servlet 2.4 spec, the new {@code dispatcher} element should be
|
* supports the Servlet 2.4 spec, the new {@code dispatcher} element should be
|
||||||
* used, and set to {@code REQUEST/FORWARD}, to make sure the filter is invoked
|
* used, and set to {@code REQUEST/FORWARD}, to make sure the filter is invoked
|
||||||
* only once for requests.
|
* only once for requests.
|
||||||
* If using an older web descriptor, set the {@code init-param}
|
* If using an older web descriptor, set the {@code init-param}
|
||||||
* {@code "once-per-request"} to {@code "true"} (this will have the same effect,
|
* {@code "once-per-request"} to {@code "true"} (this will have the same effect,
|
||||||
* but might perform slightly worse than the 2.4 version).
|
* but might perform slightly worse than the 2.4 version).
|
||||||
* Please see the examples below.
|
* Please see the examples below.
|
||||||
* <b>Servlet 2.4 version, filter section:</b><br/>
|
* <b>Servlet 2.4 version, filter section:</b><br/>
|
||||||
* <pre>
|
* <pre>
|
||||||
* <!-- GZIP Filter Configuration -->
|
* <!-- GZIP Filter Configuration -->
|
||||||
* <filter>
|
* <filter>
|
||||||
* <filter-name>gzip</filter-name>
|
* <filter-name>gzip</filter-name>
|
||||||
* <filter-class>com.twelvemonkeys.servlet.GZIPFilter</filter-class>
|
* <filter-class>com.twelvemonkeys.servlet.GZIPFilter</filter-class>
|
||||||
* </filter>
|
* </filter>
|
||||||
* </pre>
|
* </pre>
|
||||||
* <b>Filter-mapping section:</b><br/>
|
* <b>Filter-mapping section:</b><br/>
|
||||||
* <pre>
|
* <pre>
|
||||||
* <!-- GZIP Filter Mapping -->
|
* <!-- GZIP Filter Mapping -->
|
||||||
* <filter-mapping>
|
* <filter-mapping>
|
||||||
* <filter-name>gzip</filter-name>
|
* <filter-name>gzip</filter-name>
|
||||||
* <url-pattern>*.html</url-pattern>
|
* <url-pattern>*.html</url-pattern>
|
||||||
* <dispatcher>REQUEST</dispatcher>
|
* <dispatcher>REQUEST</dispatcher>
|
||||||
* <dispatcher>FORWARD</dispatcher>
|
* <dispatcher>FORWARD</dispatcher>
|
||||||
* </filter-mapping>
|
* </filter-mapping>
|
||||||
* <filter-mapping>
|
* <filter-mapping>
|
||||||
* <filter-name>gzip</filter-name>
|
* <filter-name>gzip</filter-name>
|
||||||
* <url-pattern>*.jsp< /url-pattern>
|
* <url-pattern>*.jsp< /url-pattern>
|
||||||
* <dispatcher>REQUEST</dispatcher>
|
* <dispatcher>REQUEST</dispatcher>
|
||||||
* <dispatcher>FORWARD</dispatcher>
|
* <dispatcher>FORWARD</dispatcher>
|
||||||
* </filter-mapping>
|
* </filter-mapping>
|
||||||
* </pre>
|
* </pre>
|
||||||
* <p/>
|
* <p/>
|
||||||
* Based on ideas and code found in the ONJava article
|
* Based on ideas and code found in the ONJava article
|
||||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two
|
||||||
* Servlet Filters Every Web Application Should Have</a>
|
* Servlet Filters Every Web Application Should Have</a>
|
||||||
* by Jayson Falkner.
|
* by Jayson Falkner.
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author Jayson Falkner
|
* @author Jayson Falkner
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: GZIPFilter.java#1 $
|
* @version $Id: GZIPFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
public class GZIPFilter extends GenericFilter {
|
public class GZIPFilter extends GenericFilter {
|
||||||
|
|
||||||
{
|
{
|
||||||
oncePerRequest = true;
|
oncePerRequest = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
// Can only filter HTTP responses
|
// Can only filter HTTP responses
|
||||||
if (pRequest instanceof HttpServletRequest) {
|
if (pRequest instanceof HttpServletRequest) {
|
||||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||||
HttpServletResponse response = (HttpServletResponse) pResponse;
|
HttpServletResponse response = (HttpServletResponse) pResponse;
|
||||||
|
|
||||||
// If GZIP is supported, use compression
|
// If GZIP is supported, use compression
|
||||||
String accept = request.getHeader("Accept-Encoding");
|
String accept = request.getHeader("Accept-Encoding");
|
||||||
if (accept != null && accept.contains("gzip")) {
|
if (accept != null && accept.contains("gzip")) {
|
||||||
//System.out.println("GZIP supported, compressing.");
|
//System.out.println("GZIP supported, compressing.");
|
||||||
GZIPResponseWrapper wrapped = new GZIPResponseWrapper(response);
|
GZIPResponseWrapper wrapped = new GZIPResponseWrapper(response);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pChain.doFilter(pRequest, wrapped);
|
pChain.doFilter(pRequest, wrapped);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
wrapped.flushResponse();
|
wrapped.flushResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else, continue chain
|
// Else, continue chain
|
||||||
pChain.doFilter(pRequest, pResponse);
|
pChain.doFilter(pRequest, pResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,147 +1,147 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.gzip;
|
package com.twelvemonkeys.servlet.gzip;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.OutputStreamAdapter;
|
import com.twelvemonkeys.servlet.OutputStreamAdapter;
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpServletResponseWrapper;
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GZIPResponseWrapper class description.
|
* GZIPResponseWrapper class description.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Based on ideas and code found in the ONJava article
|
* Based on ideas and code found in the ONJava article
|
||||||
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two Servlet Filters Every Web Application Should Have</a>
|
* <a href="http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html">Two Servlet Filters Every Web Application Should Have</a>
|
||||||
* by Jayson Falkner.
|
* by Jayson Falkner.
|
||||||
*
|
*
|
||||||
* @author Jayson Falkner
|
* @author Jayson Falkner
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: GZIPResponseWrapper.java#1 $
|
* @version $Id: GZIPResponseWrapper.java#1 $
|
||||||
*/
|
*/
|
||||||
public class GZIPResponseWrapper extends HttpServletResponseWrapper {
|
public class GZIPResponseWrapper extends HttpServletResponseWrapper {
|
||||||
// TODO: Remove/update ETags if needed? Read the spec (RFC 2616) on Vary/ETag for caching
|
// TODO: Remove/update ETags if needed? Read the spec (RFC 2616) on Vary/ETag for caching
|
||||||
|
|
||||||
protected ServletOutputStream out;
|
protected ServletOutputStream out;
|
||||||
protected PrintWriter writer;
|
protected PrintWriter writer;
|
||||||
protected GZIPOutputStream gzipOut;
|
protected GZIPOutputStream gzipOut;
|
||||||
protected int contentLength = -1;
|
protected int contentLength = -1;
|
||||||
|
|
||||||
public GZIPResponseWrapper(final HttpServletResponse response) {
|
public GZIPResponseWrapper(final HttpServletResponse response) {
|
||||||
super(response);
|
super(response);
|
||||||
|
|
||||||
response.addHeader("Content-Encoding", "gzip");
|
response.addHeader("Content-Encoding", "gzip");
|
||||||
response.addHeader("Vary", "Accept");
|
response.addHeader("Vary", "Accept");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletOutputStream createOutputStream() throws IOException {
|
public ServletOutputStream createOutputStream() throws IOException {
|
||||||
// FIX: Write directly to servlet output stream, for faster responses.
|
// FIX: Write directly to servlet output stream, for faster responses.
|
||||||
// Relies on chunked streams, or buffering in the servlet engine.
|
// Relies on chunked streams, or buffering in the servlet engine.
|
||||||
if (contentLength >= 0) {
|
if (contentLength >= 0) {
|
||||||
gzipOut = new GZIPOutputStream(getResponse().getOutputStream(), contentLength);
|
gzipOut = new GZIPOutputStream(getResponse().getOutputStream(), contentLength);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gzipOut = new GZIPOutputStream(getResponse().getOutputStream());
|
gzipOut = new GZIPOutputStream(getResponse().getOutputStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap in ServletOutputStream and return
|
// Wrap in ServletOutputStream and return
|
||||||
return new OutputStreamAdapter(gzipOut);
|
return new OutputStreamAdapter(gzipOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move this to flushbuffer or something? Hmmm..
|
// TODO: Move this to flushbuffer or something? Hmmm..
|
||||||
public void flushResponse() throws IOException {
|
public void flushResponse() throws IOException {
|
||||||
try {
|
try {
|
||||||
// Finish GZIP encodig
|
// Finish GZIP encodig
|
||||||
if (gzipOut != null) {
|
if (gzipOut != null) {
|
||||||
gzipOut.finish();
|
gzipOut.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
flushBuffer();
|
flushBuffer();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Close stream
|
// Close stream
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushBuffer() throws IOException {
|
public void flushBuffer() throws IOException {
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
writer.flush();
|
writer.flush();
|
||||||
}
|
}
|
||||||
else if (out != null) {
|
else if (out != null) {
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletOutputStream getOutputStream() throws IOException {
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
throw new IllegalStateException("getWriter() has already been called!");
|
throw new IllegalStateException("getWriter() has already been called!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
out = createOutputStream();
|
out = createOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrintWriter getWriter() throws IOException {
|
public PrintWriter getWriter() throws IOException {
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
return (writer);
|
return (writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
throw new IllegalStateException("getOutputStream() has already been called!");
|
throw new IllegalStateException("getOutputStream() has already been called!");
|
||||||
}
|
}
|
||||||
|
|
||||||
out = createOutputStream();
|
out = createOutputStream();
|
||||||
|
|
||||||
// TODO: This is wrong. Should use getCharacterEncoding() or "ISO-8859-1" if getCE returns null.
|
// TODO: This is wrong. Should use getCharacterEncoding() or "ISO-8859-1" if getCE returns null.
|
||||||
writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
|
writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
|
||||||
|
|
||||||
return writer;
|
return writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContentLength(int pLength) {
|
public void setContentLength(int pLength) {
|
||||||
// NOTE: Do not call super, as we will shrink the size.
|
// NOTE: Do not call super, as we will shrink the size.
|
||||||
contentLength = pLength;
|
contentLength = pLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AWTImageFilterAdapter
|
* AWTImageFilterAdapter
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: AWTImageFilterAdapter.java#1 $
|
* @version $Id: AWTImageFilterAdapter.java#1 $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class AWTImageFilterAdapter extends ImageFilter {
|
public class AWTImageFilterAdapter extends ImageFilter {
|
||||||
|
|
||||||
private java.awt.image.ImageFilter imageFilter = null;
|
private java.awt.image.ImageFilter imageFilter = null;
|
||||||
|
|
||||||
public void setImageFilter(String pFilterClass) {
|
public void setImageFilter(String pFilterClass) {
|
||||||
try {
|
try {
|
||||||
Class filterClass = Class.forName(pFilterClass);
|
Class filterClass = Class.forName(pFilterClass);
|
||||||
imageFilter = (java.awt.image.ImageFilter) filterClass.newInstance();
|
imageFilter = (java.awt.image.ImageFilter) filterClass.newInstance();
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e) {
|
catch (ClassNotFoundException e) {
|
||||||
log("Could not load filter class.", e);
|
log("Could not load filter class.", e);
|
||||||
}
|
}
|
||||||
catch (InstantiationException e) {
|
catch (InstantiationException e) {
|
||||||
log("Could not instantiate filter.", e);
|
log("Could not instantiate filter.", e);
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e) {
|
catch (IllegalAccessException e) {
|
||||||
log("Could not access filter class.", e);
|
log("Could not access filter class.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||||
// Filter
|
// Filter
|
||||||
Image img = ImageUtil.filter(pImage, imageFilter);
|
Image img = ImageUtil.filter(pImage, imageFilter);
|
||||||
|
|
||||||
// Create BufferedImage & return
|
// Create BufferedImage & return
|
||||||
return ImageUtil.toBuffered(img, BufferedImage.TYPE_INT_RGB); // TODO: This is ok for JPEG only...
|
return ImageUtil.toBuffered(img, BufferedImage.TYPE_INT_RGB); // TODO: This is ok for JPEG only...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,67 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.BufferedImageOp;
|
import java.awt.image.BufferedImageOp;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BufferedImageOpAdapter
|
* BufferedImageOpAdapter
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: BufferedImageOpAdapter.java#1 $
|
* @version $Id: BufferedImageOpAdapter.java#1 $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class BufferedImageOpAdapter extends ImageFilter {
|
public class BufferedImageOpAdapter extends ImageFilter {
|
||||||
|
|
||||||
private BufferedImageOp filter = null;
|
private BufferedImageOp filter = null;
|
||||||
|
|
||||||
public void setImageFilter(String pFilterClass) {
|
public void setImageFilter(String pFilterClass) {
|
||||||
try {
|
try {
|
||||||
Class filterClass = Class.forName(pFilterClass);
|
Class filterClass = Class.forName(pFilterClass);
|
||||||
filter = (BufferedImageOp) filterClass.newInstance();
|
filter = (BufferedImageOp) filterClass.newInstance();
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e) {
|
catch (ClassNotFoundException e) {
|
||||||
log("Could not instantiate filter class.", e);
|
log("Could not instantiate filter class.", e);
|
||||||
}
|
}
|
||||||
catch (InstantiationException e) {
|
catch (InstantiationException e) {
|
||||||
log("Could not instantiate filter.", e);
|
log("Could not instantiate filter.", e);
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException e) {
|
catch (IllegalAccessException e) {
|
||||||
log("Could not access filter class.", e);
|
log("Could not access filter class.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||||
// Filter & return
|
// Filter & return
|
||||||
return filter.filter(pImage, null);
|
return filter.filter(pImage, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,211 +1,211 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.GenericServlet;
|
import com.twelvemonkeys.servlet.GenericServlet;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a minimal 1 x 1 pixel PNG image, in a color specified by the
|
* Creates a minimal 1 x 1 pixel PNG image, in a color specified by the
|
||||||
* {@code "color"} parameter. The color is HTML-style #RRGGBB, with two
|
* {@code "color"} parameter. The color is HTML-style #RRGGBB, with two
|
||||||
* digits hex number for red, green and blue (the hash, '#', is optional).
|
* digits hex number for red, green and blue (the hash, '#', is optional).
|
||||||
* <p/>
|
* <p/>
|
||||||
* The class does only byte manipulation, there is no server-side image
|
* The class does only byte manipulation, there is no server-side image
|
||||||
* processing involving AWT ({@code Toolkit} class) of any kind.
|
* processing involving AWT ({@code Toolkit} class) of any kind.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: ColorServlet.java#2 $
|
* @version $Id: ColorServlet.java#2 $
|
||||||
*/
|
*/
|
||||||
public class ColorServlet extends GenericServlet {
|
public class ColorServlet extends GenericServlet {
|
||||||
private final static String RGB_PARAME = "color";
|
private final static String RGB_PARAME = "color";
|
||||||
|
|
||||||
// A minimal, one color indexed PNG
|
// A minimal, one color indexed PNG
|
||||||
private final static byte[] PNG_IMG = new byte[]{
|
private final static byte[] PNG_IMG = new byte[]{
|
||||||
(byte) 0x89, (byte) 'P', (byte) 'N', (byte) 'G', // PNG signature (8 bytes)
|
(byte) 0x89, (byte) 'P', (byte) 'N', (byte) 'G', // PNG signature (8 bytes)
|
||||||
0x0d, 0x0a, 0x1a, 0x0a,
|
0x0d, 0x0a, 0x1a, 0x0a,
|
||||||
|
|
||||||
0x00, 0x00, 0x00, 0x0d, // IHDR length (13)
|
0x00, 0x00, 0x00, 0x0d, // IHDR length (13)
|
||||||
(byte) 'I', (byte) 'H', (byte) 'D', (byte) 'R', // Image header
|
(byte) 'I', (byte) 'H', (byte) 'D', (byte) 'R', // Image header
|
||||||
0x00, 0x00, 0x00, 0x01, // width
|
0x00, 0x00, 0x00, 0x01, // width
|
||||||
0x00, 0x00, 0x00, 0x01, // height
|
0x00, 0x00, 0x00, 0x01, // height
|
||||||
0x01, 0x03, 0x00, 0x00, 0x00, // bits, color type, compression, filter, interlace
|
0x01, 0x03, 0x00, 0x00, 0x00, // bits, color type, compression, filter, interlace
|
||||||
0x25, (byte) 0xdb, 0x56, (byte) 0xca, // IHDR CRC
|
0x25, (byte) 0xdb, 0x56, (byte) 0xca, // IHDR CRC
|
||||||
|
|
||||||
0x00, 0x00, 0x00, 0x03, // PLTE length (3)
|
0x00, 0x00, 0x00, 0x03, // PLTE length (3)
|
||||||
(byte) 'P', (byte) 'L', (byte) 'T', (byte) 'E', // Palette
|
(byte) 'P', (byte) 'L', (byte) 'T', (byte) 'E', // Palette
|
||||||
0x00, 0x00, (byte) 0xff, // red, green, blue (updated by this servlet)
|
0x00, 0x00, (byte) 0xff, // red, green, blue (updated by this servlet)
|
||||||
(byte) 0x8a, (byte) 0x78, (byte) 0xd2, 0x57, // PLTE CRC
|
(byte) 0x8a, (byte) 0x78, (byte) 0xd2, 0x57, // PLTE CRC
|
||||||
|
|
||||||
0x00, 0x00, 0x00, 0x0a, // IDAT length (10)
|
0x00, 0x00, 0x00, 0x0a, // IDAT length (10)
|
||||||
(byte) 'I', (byte) 'D', (byte) 'A', (byte) 'T', // Image data
|
(byte) 'I', (byte) 'D', (byte) 'A', (byte) 'T', // Image data
|
||||||
0x78, (byte) 0xda, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
|
0x78, (byte) 0xda, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
|
||||||
(byte) 0xe5, 0x27, (byte) 0xde, (byte) 0xfc, // IDAT CRC
|
(byte) 0xe5, 0x27, (byte) 0xde, (byte) 0xfc, // IDAT CRC
|
||||||
|
|
||||||
|
|
||||||
0x00, 0x00, 0x00, 0x00, // IEND length (0)
|
0x00, 0x00, 0x00, 0x00, // IEND length (0)
|
||||||
(byte) 'I', (byte) 'E', (byte) 'N', (byte) 'D', // Image end
|
(byte) 'I', (byte) 'E', (byte) 'N', (byte) 'D', // Image end
|
||||||
(byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 // IEND CRC
|
(byte) 0xae, (byte) 0x42, (byte) 0x60, (byte) 0x82 // IEND CRC
|
||||||
};
|
};
|
||||||
|
|
||||||
private final static int PLTE_CHUNK_START = 37; // after chunk length
|
private final static int PLTE_CHUNK_START = 37; // after chunk length
|
||||||
private final static int PLTE_CHUNK_LENGTH = 7; // chunk name & data
|
private final static int PLTE_CHUNK_LENGTH = 7; // chunk name & data
|
||||||
|
|
||||||
private final static int RED_IDX = 4;
|
private final static int RED_IDX = 4;
|
||||||
private final static int GREEN_IDX = RED_IDX + 1;
|
private final static int GREEN_IDX = RED_IDX + 1;
|
||||||
private final static int BLUE_IDX = GREEN_IDX + 1;
|
private final static int BLUE_IDX = GREEN_IDX + 1;
|
||||||
|
|
||||||
private final CRC32 crc = new CRC32();
|
private final CRC32 crc = new CRC32();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a ColorDroplet.
|
* Creates a ColorDroplet.
|
||||||
*/
|
*/
|
||||||
public ColorServlet() {
|
public ColorServlet() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the 1 x 1 single color PNG to the response.
|
* Renders the 1 x 1 single color PNG to the response.
|
||||||
*
|
*
|
||||||
* @see ColorServlet class description
|
* @see ColorServlet class description
|
||||||
*
|
*
|
||||||
* @param pRequest the request
|
* @param pRequest the request
|
||||||
* @param pResponse the response
|
* @param pResponse the response
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*/
|
*/
|
||||||
public void service(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
public void service(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
||||||
int red = 0;
|
int red = 0;
|
||||||
int green = 0;
|
int green = 0;
|
||||||
int blue = 0;
|
int blue = 0;
|
||||||
|
|
||||||
// Get color parameter and parse color
|
// Get color parameter and parse color
|
||||||
String rgb = pRequest.getParameter(RGB_PARAME);
|
String rgb = pRequest.getParameter(RGB_PARAME);
|
||||||
if (rgb != null && rgb.length() >= 6 && rgb.length() <= 7) {
|
if (rgb != null && rgb.length() >= 6 && rgb.length() <= 7) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
// If the hash ('#') character is included, skip it.
|
// If the hash ('#') character is included, skip it.
|
||||||
if (rgb.length() == 7) {
|
if (rgb.length() == 7) {
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Two digit hex for each color
|
// Two digit hex for each color
|
||||||
String r = rgb.substring(index, index += 2);
|
String r = rgb.substring(index, index += 2);
|
||||||
red = Integer.parseInt(r, 0x10);
|
red = Integer.parseInt(r, 0x10);
|
||||||
|
|
||||||
String g = rgb.substring(index, index += 2);
|
String g = rgb.substring(index, index += 2);
|
||||||
green = Integer.parseInt(g, 0x10);
|
green = Integer.parseInt(g, 0x10);
|
||||||
|
|
||||||
String b = rgb.substring(index, index += 2);
|
String b = rgb.substring(index, index += 2);
|
||||||
blue = Integer.parseInt(b, 0x10);
|
blue = Integer.parseInt(b, 0x10);
|
||||||
}
|
}
|
||||||
catch (NumberFormatException nfe) {
|
catch (NumberFormatException nfe) {
|
||||||
log("Wrong color format for ColorDroplet: " + rgb + ". Must be RRGGBB.");
|
log("Wrong color format for ColorDroplet: " + rgb + ". Must be RRGGBB.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set MIME type for PNG
|
// Set MIME type for PNG
|
||||||
pResponse.setContentType("image/png");
|
pResponse.setContentType("image/png");
|
||||||
ServletOutputStream out = pResponse.getOutputStream();
|
ServletOutputStream out = pResponse.getOutputStream();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Write header (and palette chunk length)
|
// Write header (and palette chunk length)
|
||||||
out.write(PNG_IMG, 0, PLTE_CHUNK_START);
|
out.write(PNG_IMG, 0, PLTE_CHUNK_START);
|
||||||
|
|
||||||
// Create palette chunk, excl lenght, and write
|
// Create palette chunk, excl lenght, and write
|
||||||
byte[] palette = makePalette(red, green, blue);
|
byte[] palette = makePalette(red, green, blue);
|
||||||
out.write(palette);
|
out.write(palette);
|
||||||
|
|
||||||
// Write image data until end
|
// Write image data until end
|
||||||
int pos = PLTE_CHUNK_START + PLTE_CHUNK_LENGTH + 4;
|
int pos = PLTE_CHUNK_START + PLTE_CHUNK_LENGTH + 4;
|
||||||
out.write(PNG_IMG, pos, PNG_IMG.length - pos);
|
out.write(PNG_IMG, pos, PNG_IMG.length - pos);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the CRC for a byte array. Note that the byte array must be at
|
* Updates the CRC for a byte array. Note that the byte array must be at
|
||||||
* least {@code pOff + pLen + 4} bytes long, as the CRC is stored in the
|
* least {@code pOff + pLen + 4} bytes long, as the CRC is stored in the
|
||||||
* 4 last bytes.
|
* 4 last bytes.
|
||||||
*
|
*
|
||||||
* @param pBytes the bytes to create CRC for
|
* @param pBytes the bytes to create CRC for
|
||||||
* @param pOff the offset into the byte array to create CRC for
|
* @param pOff the offset into the byte array to create CRC for
|
||||||
* @param pLen the length of the byte array to create CRC for
|
* @param pLen the length of the byte array to create CRC for
|
||||||
*/
|
*/
|
||||||
private void updateCRC(byte[] pBytes, int pOff, int pLen) {
|
private void updateCRC(byte[] pBytes, int pOff, int pLen) {
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
synchronized (crc) {
|
synchronized (crc) {
|
||||||
crc.reset();
|
crc.reset();
|
||||||
crc.update(pBytes, pOff, pLen);
|
crc.update(pBytes, pOff, pLen);
|
||||||
value = (int) crc.getValue();
|
value = (int) crc.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
pBytes[pOff + pLen ] = (byte) ((value >> 24) & 0xff);
|
pBytes[pOff + pLen ] = (byte) ((value >> 24) & 0xff);
|
||||||
pBytes[pOff + pLen + 1] = (byte) ((value >> 16) & 0xff);
|
pBytes[pOff + pLen + 1] = (byte) ((value >> 16) & 0xff);
|
||||||
pBytes[pOff + pLen + 2] = (byte) ((value >> 8) & 0xff);
|
pBytes[pOff + pLen + 2] = (byte) ((value >> 8) & 0xff);
|
||||||
pBytes[pOff + pLen + 3] = (byte) ( value & 0xff);
|
pBytes[pOff + pLen + 3] = (byte) ( value & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a PNG palette (PLTE) chunk with one color.
|
* Creates a PNG palette (PLTE) chunk with one color.
|
||||||
* The palette chunk data is always 3 bytes in length (one byte per color
|
* The palette chunk data is always 3 bytes in length (one byte per color
|
||||||
* component).
|
* component).
|
||||||
* The returned byte array is then {@code 4 + 3 + 4 = 11} bytes,
|
* The returned byte array is then {@code 4 + 3 + 4 = 11} bytes,
|
||||||
* including chunk header, data and CRC.
|
* including chunk header, data and CRC.
|
||||||
*
|
*
|
||||||
* @param pRed the red component
|
* @param pRed the red component
|
||||||
* @param pGreen the reen component
|
* @param pGreen the reen component
|
||||||
* @param pBlue the blue component
|
* @param pBlue the blue component
|
||||||
*
|
*
|
||||||
* @return the bytes for the PLTE chunk, including CRC (but not length)
|
* @return the bytes for the PLTE chunk, including CRC (but not length)
|
||||||
*/
|
*/
|
||||||
private byte[] makePalette(int pRed, int pGreen, int pBlue) {
|
private byte[] makePalette(int pRed, int pGreen, int pBlue) {
|
||||||
byte[] palette = new byte[PLTE_CHUNK_LENGTH + 4];
|
byte[] palette = new byte[PLTE_CHUNK_LENGTH + 4];
|
||||||
System.arraycopy(PNG_IMG, PLTE_CHUNK_START, palette, 0, PLTE_CHUNK_LENGTH);
|
System.arraycopy(PNG_IMG, PLTE_CHUNK_START, palette, 0, PLTE_CHUNK_LENGTH);
|
||||||
|
|
||||||
palette[RED_IDX] = (byte) pRed;
|
palette[RED_IDX] = (byte) pRed;
|
||||||
palette[GREEN_IDX] = (byte) pGreen;
|
palette[GREEN_IDX] = (byte) pGreen;
|
||||||
palette[BLUE_IDX] = (byte) pBlue;
|
palette[BLUE_IDX] = (byte) pBlue;
|
||||||
|
|
||||||
updateCRC(palette, 0, PLTE_CHUNK_LENGTH);
|
updateCRC(palette, 0, PLTE_CHUNK_LENGTH);
|
||||||
|
|
||||||
return palette;
|
return palette;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,59 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ComposeFilter
|
* ComposeFilter
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: ComposeFilter.java#1 $
|
* @version $Id: ComposeFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
public class ComposeFilter extends ImageFilter {
|
public class ComposeFilter extends ImageFilter {
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException {
|
||||||
// 1. Load different image, locally (using ServletContext.getResource)
|
// 1. Load different image, locally (using ServletContext.getResource)
|
||||||
// - Allow loading other filtered sources, or servlets? For example to
|
// - Allow loading other filtered sources, or servlets? For example to
|
||||||
// apply filename or timestamps?
|
// apply filename or timestamps?
|
||||||
// - Allow applying text directly? Variables?
|
// - Allow applying text directly? Variables?
|
||||||
// 2. Apply transformations from config
|
// 2. Apply transformations from config
|
||||||
// - Relative positioning
|
// - Relative positioning
|
||||||
// - Relative scaling
|
// - Relative scaling
|
||||||
// - Repeat (fill-pattern)?
|
// - Repeat (fill-pattern)?
|
||||||
// - Rotation?
|
// - Rotation?
|
||||||
// - Transparency?
|
// - Transparency?
|
||||||
// - Background or foreground (layers)?
|
// - Background or foreground (layers)?
|
||||||
// 3. Apply loaded image to original image (or vice versa?).
|
// 3. Apply loaded image to original image (or vice versa?).
|
||||||
return pImage;
|
return pImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+439
-439
@@ -1,439 +1,439 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.IndexColorModel;
|
import java.awt.image.IndexColorModel;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This filter implements server side content negotiation and transcoding for
|
* This filter implements server side content negotiation and transcoding for
|
||||||
* images.
|
* images.
|
||||||
*
|
*
|
||||||
* @todo Add support for automatic recognition of known browsers, to avoid
|
* @todo Add support for automatic recognition of known browsers, to avoid
|
||||||
* unneccessary conversion (as IE supports PNG, the latests FireFox supports
|
* unneccessary conversion (as IE supports PNG, the latests FireFox supports
|
||||||
* JPEG and GIF, etc. even though they both don't explicitly list these formats
|
* JPEG and GIF, etc. even though they both don't explicitly list these formats
|
||||||
* in their Accept headers).
|
* in their Accept headers).
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: ContentNegotiationFilter.java#1 $
|
* @version $Id: ContentNegotiationFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
public class ContentNegotiationFilter extends ImageFilter {
|
public class ContentNegotiationFilter extends ImageFilter {
|
||||||
|
|
||||||
private final static String MIME_TYPE_IMAGE_PREFIX = "image/";
|
private final static String MIME_TYPE_IMAGE_PREFIX = "image/";
|
||||||
private static final String MIME_TYPE_IMAGE_ANY = MIME_TYPE_IMAGE_PREFIX + "*";
|
private static final String MIME_TYPE_IMAGE_ANY = MIME_TYPE_IMAGE_PREFIX + "*";
|
||||||
private static final String MIME_TYPE_ANY = "*/*";
|
private static final String MIME_TYPE_ANY = "*/*";
|
||||||
private static final String HTTP_HEADER_ACCEPT = "Accept";
|
private static final String HTTP_HEADER_ACCEPT = "Accept";
|
||||||
private static final String HTTP_HEADER_VARY = "Vary";
|
private static final String HTTP_HEADER_VARY = "Vary";
|
||||||
protected static final String HTTP_HEADER_USER_AGENT = "User-Agent";
|
protected static final String HTTP_HEADER_USER_AGENT = "User-Agent";
|
||||||
|
|
||||||
private static final String FORMAT_JPEG = "image/jpeg";
|
private static final String FORMAT_JPEG = "image/jpeg";
|
||||||
private static final String FORMAT_WBMP = "image/wbmp";
|
private static final String FORMAT_WBMP = "image/wbmp";
|
||||||
private static final String FORMAT_GIF = "image/gif";
|
private static final String FORMAT_GIF = "image/gif";
|
||||||
private static final String FORMAT_PNG = "image/png";
|
private static final String FORMAT_PNG = "image/png";
|
||||||
|
|
||||||
private final static String[] sKnownFormats = new String[] {
|
private final static String[] sKnownFormats = new String[] {
|
||||||
FORMAT_JPEG, FORMAT_PNG, FORMAT_GIF, FORMAT_WBMP
|
FORMAT_JPEG, FORMAT_PNG, FORMAT_GIF, FORMAT_WBMP
|
||||||
};
|
};
|
||||||
private float[] knownFormatQuality = new float[] {
|
private float[] knownFormatQuality = new float[] {
|
||||||
1f, 1f, 0.99f, 0.5f
|
1f, 1f, 0.99f, 0.5f
|
||||||
};
|
};
|
||||||
|
|
||||||
private HashMap<String, Float> formatQuality; // HashMap, as I need to clone this for each request
|
private HashMap<String, Float> formatQuality; // HashMap, as I need to clone this for each request
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private Pattern[] mKnownAgentPatterns;
|
private Pattern[] mKnownAgentPatterns;
|
||||||
private String[] mKnownAgentAccpets;
|
private String[] mKnownAgentAccpets;
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
// Hack: Make sure the filter don't trigger all the time
|
// Hack: Make sure the filter don't trigger all the time
|
||||||
// See: super.trigger(ServletRequest)
|
// See: super.trigger(ServletRequest)
|
||||||
triggerParams = new String[] {};
|
triggerParams = new String[] {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public void setAcceptMappings(String pPropertiesFile) {
|
public void setAcceptMappings(String pPropertiesFile) {
|
||||||
// NOTE: Supposed to be:
|
// NOTE: Supposed to be:
|
||||||
// <agent-name>=<reg-exp>
|
// <agent-name>=<reg-exp>
|
||||||
// <agent-name>.accept=<http-accept-header>
|
// <agent-name>.accept=<http-accept-header>
|
||||||
|
|
||||||
Properties mappings = new Properties();
|
Properties mappings = new Properties();
|
||||||
try {
|
try {
|
||||||
mappings.load(getServletContext().getResourceAsStream(pPropertiesFile));
|
mappings.load(getServletContext().getResourceAsStream(pPropertiesFile));
|
||||||
|
|
||||||
List patterns = new ArrayList();
|
List patterns = new ArrayList();
|
||||||
List accepts = new ArrayList();
|
List accepts = new ArrayList();
|
||||||
|
|
||||||
for (Iterator iterator = mappings.keySet().iterator(); iterator.hasNext();) {
|
for (Iterator iterator = mappings.keySet().iterator(); iterator.hasNext();) {
|
||||||
String agent = (String) iterator.next();
|
String agent = (String) iterator.next();
|
||||||
if (agent.endsWith(".accept")) {
|
if (agent.endsWith(".accept")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
patterns.add(Pattern.compile((String) mappings.get(agent)));
|
patterns.add(Pattern.compile((String) mappings.get(agent)));
|
||||||
|
|
||||||
// TODO: Consider preparsing ACCEPT header??
|
// TODO: Consider preparsing ACCEPT header??
|
||||||
accepts.add(mappings.get(agent + ".accept"));
|
accepts.add(mappings.get(agent + ".accept"));
|
||||||
}
|
}
|
||||||
catch (PatternSyntaxException e) {
|
catch (PatternSyntaxException e) {
|
||||||
log("Could not parse User-Agent identification for " + agent, e);
|
log("Could not parse User-Agent identification for " + agent, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
mKnownAgentPatterns = (Pattern[]) patterns.toArray(new Pattern[patterns.size()]);
|
mKnownAgentPatterns = (Pattern[]) patterns.toArray(new Pattern[patterns.size()]);
|
||||||
mKnownAgentAccpets = (String[]) accepts.toArray(new String[accepts.size()]);
|
mKnownAgentAccpets = (String[]) accepts.toArray(new String[accepts.size()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
log("Could not read accetp-mappings properties file: " + pPropertiesFile, e);
|
log("Could not read accetp-mappings properties file: " + pPropertiesFile, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
// NOTE: super invokes trigger() and image specific doFilter() if needed
|
// NOTE: super invokes trigger() and image specific doFilter() if needed
|
||||||
super.doFilterImpl(pRequest, pResponse, pChain);
|
super.doFilterImpl(pRequest, pResponse, pChain);
|
||||||
|
|
||||||
if (pResponse instanceof HttpServletResponse) {
|
if (pResponse instanceof HttpServletResponse) {
|
||||||
// Update the Vary HTTP header field
|
// Update the Vary HTTP header field
|
||||||
((HttpServletResponse) pResponse).addHeader(HTTP_HEADER_VARY, HTTP_HEADER_ACCEPT);
|
((HttpServletResponse) pResponse).addHeader(HTTP_HEADER_VARY, HTTP_HEADER_ACCEPT);
|
||||||
//((HttpServletResponse) pResponse).addHeader(HTTP_HEADER_VARY, HTTP_HEADER_USER_AGENT);
|
//((HttpServletResponse) pResponse).addHeader(HTTP_HEADER_VARY, HTTP_HEADER_USER_AGENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure the filter triggers for unknown file formats.
|
* Makes sure the filter triggers for unknown file formats.
|
||||||
*
|
*
|
||||||
* @param pRequest the request
|
* @param pRequest the request
|
||||||
* @return {@code true} if the filter should execute, {@code false}
|
* @return {@code true} if the filter should execute, {@code false}
|
||||||
* otherwise
|
* otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean trigger(ServletRequest pRequest) {
|
protected boolean trigger(ServletRequest pRequest) {
|
||||||
boolean trigger = false;
|
boolean trigger = false;
|
||||||
|
|
||||||
if (pRequest instanceof HttpServletRequest) {
|
if (pRequest instanceof HttpServletRequest) {
|
||||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||||
String accept = getAcceptedFormats(request);
|
String accept = getAcceptedFormats(request);
|
||||||
String originalFormat = getServletContext().getMimeType(request.getRequestURI());
|
String originalFormat = getServletContext().getMimeType(request.getRequestURI());
|
||||||
|
|
||||||
//System.out.println("Accept: " + accept);
|
//System.out.println("Accept: " + accept);
|
||||||
//System.out.println("Original format: " + originalFormat);
|
//System.out.println("Original format: " + originalFormat);
|
||||||
|
|
||||||
// Only override original format if it is not accpeted by the client
|
// Only override original format if it is not accpeted by the client
|
||||||
// Note: Only explicit matches are okay, */* or image/* is not.
|
// Note: Only explicit matches are okay, */* or image/* is not.
|
||||||
if (!StringUtil.contains(accept, originalFormat)) {
|
if (!StringUtil.contains(accept, originalFormat)) {
|
||||||
trigger = true;
|
trigger = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call super, to allow content negotiation even though format is supported
|
// Call super, to allow content negotiation even though format is supported
|
||||||
return trigger || super.trigger(pRequest);
|
return trigger || super.trigger(pRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAcceptedFormats(HttpServletRequest pRequest) {
|
private String getAcceptedFormats(HttpServletRequest pRequest) {
|
||||||
return pRequest.getHeader(HTTP_HEADER_ACCEPT);
|
return pRequest.getHeader(HTTP_HEADER_ACCEPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private String getAcceptedFormats(HttpServletRequest pRequest) {
|
private String getAcceptedFormats(HttpServletRequest pRequest) {
|
||||||
String accept = pRequest.getHeader(HTTP_HEADER_ACCEPT);
|
String accept = pRequest.getHeader(HTTP_HEADER_ACCEPT);
|
||||||
|
|
||||||
// Check if User-Agent is in list of known agents
|
// Check if User-Agent is in list of known agents
|
||||||
if (mKnownAgentPatterns != null) {
|
if (mKnownAgentPatterns != null) {
|
||||||
String agent = pRequest.getHeader(HTTP_HEADER_USER_AGENT);
|
String agent = pRequest.getHeader(HTTP_HEADER_USER_AGENT);
|
||||||
for (int i = 0; i < mKnownAgentPatterns.length; i++) {
|
for (int i = 0; i < mKnownAgentPatterns.length; i++) {
|
||||||
Pattern pattern = mKnownAgentPatterns[i];
|
Pattern pattern = mKnownAgentPatterns[i];
|
||||||
if (pattern.matcher(agent).matches()) {
|
if (pattern.matcher(agent).matches()) {
|
||||||
// Merge known with real accpet, in case plugins add extra capabilities
|
// Merge known with real accpet, in case plugins add extra capabilities
|
||||||
accept = mergeAccept(mKnownAgentAccpets[i], accept);
|
accept = mergeAccept(mKnownAgentAccpets[i], accept);
|
||||||
System.out.println("--> User-Agent: " + agent + " accepts: " + accept);
|
System.out.println("--> User-Agent: " + agent + " accepts: " + accept);
|
||||||
return accept;
|
return accept;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("No agent match, defaulting to Accept header: " + accept);
|
System.out.println("No agent match, defaulting to Accept header: " + accept);
|
||||||
return accept;
|
return accept;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String mergeAccept(String pKnown, String pAccept) {
|
private String mergeAccept(String pKnown, String pAccept) {
|
||||||
// TODO: Make sure there are no duplicates...
|
// TODO: Make sure there are no duplicates...
|
||||||
return pKnown + ", " + pAccept;
|
return pKnown + ", " + pAccept;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException {
|
||||||
if (pRequest instanceof HttpServletRequest) {
|
if (pRequest instanceof HttpServletRequest) {
|
||||||
HttpServletRequest request = (HttpServletRequest) pRequest;
|
HttpServletRequest request = (HttpServletRequest) pRequest;
|
||||||
|
|
||||||
Map<String, Float> formatQuality = getFormatQualityMapping();
|
Map<String, Float> formatQuality = getFormatQualityMapping();
|
||||||
|
|
||||||
// TODO: Consider adding original format, and use as fallback in worst case?
|
// TODO: Consider adding original format, and use as fallback in worst case?
|
||||||
// TODO: Original format should have some boost, to avoid unneccesary convertsion?
|
// TODO: Original format should have some boost, to avoid unneccesary convertsion?
|
||||||
|
|
||||||
// Update source quality settings from image properties
|
// Update source quality settings from image properties
|
||||||
adjustQualityFromImage(formatQuality, pImage);
|
adjustQualityFromImage(formatQuality, pImage);
|
||||||
//System.out.println("Source quality mapping: " + formatQuality);
|
//System.out.println("Source quality mapping: " + formatQuality);
|
||||||
|
|
||||||
adjustQualityFromAccept(formatQuality, request);
|
adjustQualityFromAccept(formatQuality, request);
|
||||||
//System.out.println("Final media scores: " + formatQuality);
|
//System.out.println("Final media scores: " + formatQuality);
|
||||||
|
|
||||||
// Find the formats with the highest quality factor, and use the first (predictable)
|
// Find the formats with the highest quality factor, and use the first (predictable)
|
||||||
String acceptable = findBestFormat(formatQuality);
|
String acceptable = findBestFormat(formatQuality);
|
||||||
|
|
||||||
//System.out.println("Acceptable: " + acceptable);
|
//System.out.println("Acceptable: " + acceptable);
|
||||||
|
|
||||||
// Send HTTP 406 Not Acceptable
|
// Send HTTP 406 Not Acceptable
|
||||||
if (acceptable == null) {
|
if (acceptable == null) {
|
||||||
if (pResponse instanceof HttpServletResponse) {
|
if (pResponse instanceof HttpServletResponse) {
|
||||||
((HttpServletResponse) pResponse).sendError(HttpURLConnection.HTTP_NOT_ACCEPTABLE);
|
((HttpServletResponse) pResponse).sendError(HttpURLConnection.HTTP_NOT_ACCEPTABLE);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: Only if the format was changed!
|
// TODO: Only if the format was changed!
|
||||||
// Let other filters/caches/proxies know we changed the image
|
// Let other filters/caches/proxies know we changed the image
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set format
|
// Set format
|
||||||
pResponse.setOutputContentType(acceptable);
|
pResponse.setOutputContentType(acceptable);
|
||||||
//System.out.println("Set format: " + acceptable);
|
//System.out.println("Set format: " + acceptable);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pImage;
|
return pImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Float> getFormatQualityMapping() {
|
private Map<String, Float> getFormatQualityMapping() {
|
||||||
synchronized(lock) {
|
synchronized(lock) {
|
||||||
if (formatQuality == null) {
|
if (formatQuality == null) {
|
||||||
formatQuality = new HashMap<String, Float>();
|
formatQuality = new HashMap<String, Float>();
|
||||||
|
|
||||||
// Use ImageIO to find formats we can actually write
|
// Use ImageIO to find formats we can actually write
|
||||||
String[] formats = ImageIO.getWriterMIMETypes();
|
String[] formats = ImageIO.getWriterMIMETypes();
|
||||||
|
|
||||||
// All known formats qs are initially 1.0
|
// All known formats qs are initially 1.0
|
||||||
// Others should be 0.1 or something like that...
|
// Others should be 0.1 or something like that...
|
||||||
for (String format : formats) {
|
for (String format : formats) {
|
||||||
formatQuality.put(format, getKnownFormatQuality(format));
|
formatQuality.put(format, getKnownFormatQuality(format));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return (Map<String, Float>) formatQuality.clone();
|
return (Map<String, Float>) formatQuality.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the best available format.
|
* Finds the best available format.
|
||||||
*
|
*
|
||||||
* @param pFormatQuality the format to quality mapping
|
* @param pFormatQuality the format to quality mapping
|
||||||
* @return the mime type of the best available format
|
* @return the mime type of the best available format
|
||||||
*/
|
*/
|
||||||
private static String findBestFormat(Map<String, Float> pFormatQuality) {
|
private static String findBestFormat(Map<String, Float> pFormatQuality) {
|
||||||
String acceptable = null;
|
String acceptable = null;
|
||||||
float acceptQuality = 0.0f;
|
float acceptQuality = 0.0f;
|
||||||
for (Map.Entry<String, Float> entry : pFormatQuality.entrySet()) {
|
for (Map.Entry<String, Float> entry : pFormatQuality.entrySet()) {
|
||||||
float qValue = entry.getValue();
|
float qValue = entry.getValue();
|
||||||
if (qValue > acceptQuality) {
|
if (qValue > acceptQuality) {
|
||||||
acceptQuality = qValue;
|
acceptQuality = qValue;
|
||||||
acceptable = entry.getKey();
|
acceptable = entry.getKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//System.out.println("Accepted format: " + acceptable);
|
//System.out.println("Accepted format: " + acceptable);
|
||||||
//System.out.println("Accepted quality: " + acceptQuality);
|
//System.out.println("Accepted quality: " + acceptQuality);
|
||||||
return acceptable;
|
return acceptable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust quality from HTTP Accept header
|
* Adjust quality from HTTP Accept header
|
||||||
*
|
*
|
||||||
* @param pFormatQuality the format to quality mapping
|
* @param pFormatQuality the format to quality mapping
|
||||||
* @param pRequest the request
|
* @param pRequest the request
|
||||||
*/
|
*/
|
||||||
private void adjustQualityFromAccept(Map<String, Float> pFormatQuality, HttpServletRequest pRequest) {
|
private void adjustQualityFromAccept(Map<String, Float> pFormatQuality, HttpServletRequest pRequest) {
|
||||||
// Multiply all q factors with qs factors
|
// Multiply all q factors with qs factors
|
||||||
// No q=.. should be interpreted as q=1.0
|
// No q=.. should be interpreted as q=1.0
|
||||||
|
|
||||||
// Apache does some extras; if both explicit types and wildcards
|
// Apache does some extras; if both explicit types and wildcards
|
||||||
// (without qaulity factor) are present, */* is interpreted as
|
// (without qaulity factor) are present, */* is interpreted as
|
||||||
// */*;q=0.01 and image/* is interpreted as image/*;q=0.02
|
// */*;q=0.01 and image/* is interpreted as image/*;q=0.02
|
||||||
// See: http://httpd.apache.org/docs-2.0/content-negotiation.html
|
// See: http://httpd.apache.org/docs-2.0/content-negotiation.html
|
||||||
|
|
||||||
String accept = getAcceptedFormats(pRequest);
|
String accept = getAcceptedFormats(pRequest);
|
||||||
//System.out.println("Accept: " + accept);
|
//System.out.println("Accept: " + accept);
|
||||||
|
|
||||||
float anyImageFactor = getQualityFactor(accept, MIME_TYPE_IMAGE_ANY);
|
float anyImageFactor = getQualityFactor(accept, MIME_TYPE_IMAGE_ANY);
|
||||||
anyImageFactor = (anyImageFactor == 1) ? 0.02f : anyImageFactor;
|
anyImageFactor = (anyImageFactor == 1) ? 0.02f : anyImageFactor;
|
||||||
|
|
||||||
float anyFactor = getQualityFactor(accept, MIME_TYPE_ANY);
|
float anyFactor = getQualityFactor(accept, MIME_TYPE_ANY);
|
||||||
anyFactor = (anyFactor == 1) ? 0.01f : anyFactor;
|
anyFactor = (anyFactor == 1) ? 0.01f : anyFactor;
|
||||||
|
|
||||||
for (String format : pFormatQuality.keySet()) {
|
for (String format : pFormatQuality.keySet()) {
|
||||||
//System.out.println("Trying format: " + format);
|
//System.out.println("Trying format: " + format);
|
||||||
|
|
||||||
String formatMIME = MIME_TYPE_IMAGE_PREFIX + format;
|
String formatMIME = MIME_TYPE_IMAGE_PREFIX + format;
|
||||||
float qFactor = getQualityFactor(accept, formatMIME);
|
float qFactor = getQualityFactor(accept, formatMIME);
|
||||||
qFactor = (qFactor == 0f) ? Math.max(anyFactor, anyImageFactor) : qFactor;
|
qFactor = (qFactor == 0f) ? Math.max(anyFactor, anyImageFactor) : qFactor;
|
||||||
adjustQuality(pFormatQuality, format, qFactor);
|
adjustQuality(pFormatQuality, format, qFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param pAccept the accpet header value
|
* @param pAccept the accpet header value
|
||||||
* @param pContentType the content type to get the quality factor for
|
* @param pContentType the content type to get the quality factor for
|
||||||
* @return the q factor of the given format, according to the accept header
|
* @return the q factor of the given format, according to the accept header
|
||||||
*/
|
*/
|
||||||
private static float getQualityFactor(String pAccept, String pContentType) {
|
private static float getQualityFactor(String pAccept, String pContentType) {
|
||||||
float qFactor = 0;
|
float qFactor = 0;
|
||||||
int foundIndex = pAccept.indexOf(pContentType);
|
int foundIndex = pAccept.indexOf(pContentType);
|
||||||
if (foundIndex >= 0) {
|
if (foundIndex >= 0) {
|
||||||
int startQIndex = foundIndex + pContentType.length();
|
int startQIndex = foundIndex + pContentType.length();
|
||||||
if (startQIndex < pAccept.length() && pAccept.charAt(startQIndex) == ';') {
|
if (startQIndex < pAccept.length() && pAccept.charAt(startQIndex) == ';') {
|
||||||
while (startQIndex < pAccept.length() && pAccept.charAt(startQIndex++) == ' ') {
|
while (startQIndex < pAccept.length() && pAccept.charAt(startQIndex++) == ' ') {
|
||||||
// Skip over whitespace
|
// Skip over whitespace
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pAccept.charAt(startQIndex++) == 'q' && pAccept.charAt(startQIndex++) == '=') {
|
if (pAccept.charAt(startQIndex++) == 'q' && pAccept.charAt(startQIndex++) == '=') {
|
||||||
int endQIndex = pAccept.indexOf(',', startQIndex);
|
int endQIndex = pAccept.indexOf(',', startQIndex);
|
||||||
if (endQIndex < 0) {
|
if (endQIndex < 0) {
|
||||||
endQIndex = pAccept.length();
|
endQIndex = pAccept.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
qFactor = Float.parseFloat(pAccept.substring(startQIndex, endQIndex));
|
qFactor = Float.parseFloat(pAccept.substring(startQIndex, endQIndex));
|
||||||
//System.out.println("Found qFactor " + qFactor);
|
//System.out.println("Found qFactor " + qFactor);
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
// TODO: Determine what to do here.. Maybe use a very low value?
|
// TODO: Determine what to do here.. Maybe use a very low value?
|
||||||
// Ahem.. The specs don't say anything about how to interpret a wrong q factor..
|
// Ahem.. The specs don't say anything about how to interpret a wrong q factor..
|
||||||
//System.out.println("Unparseable q setting; " + e.getMessage());
|
//System.out.println("Unparseable q setting; " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Determine what to do here.. Maybe use a very low value?
|
// TODO: Determine what to do here.. Maybe use a very low value?
|
||||||
// Unparseable q value, use 0
|
// Unparseable q value, use 0
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Else, assume quality is 1.0
|
// Else, assume quality is 1.0
|
||||||
qFactor = 1;
|
qFactor = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return qFactor;
|
return qFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts source quality settings from image properties.
|
* Adjusts source quality settings from image properties.
|
||||||
*
|
*
|
||||||
* @param pFormatQuality the format to quality mapping
|
* @param pFormatQuality the format to quality mapping
|
||||||
* @param pImage the image
|
* @param pImage the image
|
||||||
*/
|
*/
|
||||||
private static void adjustQualityFromImage(Map<String, Float> pFormatQuality, BufferedImage pImage) {
|
private static void adjustQualityFromImage(Map<String, Float> pFormatQuality, BufferedImage pImage) {
|
||||||
// NOTE: The values are all made-up. May need tuning.
|
// NOTE: The values are all made-up. May need tuning.
|
||||||
|
|
||||||
// If pImage.getColorModel() instanceof IndexColorModel
|
// If pImage.getColorModel() instanceof IndexColorModel
|
||||||
// JPEG qs*=0.6
|
// JPEG qs*=0.6
|
||||||
// If NOT binary or 2 color index
|
// If NOT binary or 2 color index
|
||||||
// WBMP qs*=0.5
|
// WBMP qs*=0.5
|
||||||
// Else
|
// Else
|
||||||
// GIF qs*=0.02
|
// GIF qs*=0.02
|
||||||
// PNG qs*=0.9 // JPEG is smaller/faster
|
// PNG qs*=0.9 // JPEG is smaller/faster
|
||||||
if (pImage.getColorModel() instanceof IndexColorModel) {
|
if (pImage.getColorModel() instanceof IndexColorModel) {
|
||||||
adjustQuality(pFormatQuality, FORMAT_JPEG, 0.6f);
|
adjustQuality(pFormatQuality, FORMAT_JPEG, 0.6f);
|
||||||
|
|
||||||
if (pImage.getType() != BufferedImage.TYPE_BYTE_BINARY || ((IndexColorModel) pImage.getColorModel()).getMapSize() != 2) {
|
if (pImage.getType() != BufferedImage.TYPE_BYTE_BINARY || ((IndexColorModel) pImage.getColorModel()).getMapSize() != 2) {
|
||||||
adjustQuality(pFormatQuality, FORMAT_WBMP, 0.5f);
|
adjustQuality(pFormatQuality, FORMAT_WBMP, 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
adjustQuality(pFormatQuality, FORMAT_GIF, 0.01f);
|
adjustQuality(pFormatQuality, FORMAT_GIF, 0.01f);
|
||||||
adjustQuality(pFormatQuality, FORMAT_PNG, 0.99f); // JPEG is smaller/faster
|
adjustQuality(pFormatQuality, FORMAT_PNG, 0.99f); // JPEG is smaller/faster
|
||||||
}
|
}
|
||||||
|
|
||||||
// If pImage.getColorModel().hasTransparentPixels()
|
// If pImage.getColorModel().hasTransparentPixels()
|
||||||
// JPEG qs*=0.05
|
// JPEG qs*=0.05
|
||||||
// WBMP qs*=0.05
|
// WBMP qs*=0.05
|
||||||
// If NOT transparency == BITMASK
|
// If NOT transparency == BITMASK
|
||||||
// GIF qs*=0.8
|
// GIF qs*=0.8
|
||||||
if (ImageUtil.hasTransparentPixels(pImage, true)) {
|
if (ImageUtil.hasTransparentPixels(pImage, true)) {
|
||||||
adjustQuality(pFormatQuality, FORMAT_JPEG, 0.009f);
|
adjustQuality(pFormatQuality, FORMAT_JPEG, 0.009f);
|
||||||
adjustQuality(pFormatQuality, FORMAT_WBMP, 0.009f);
|
adjustQuality(pFormatQuality, FORMAT_WBMP, 0.009f);
|
||||||
|
|
||||||
if (pImage.getColorModel().getTransparency() != Transparency.BITMASK) {
|
if (pImage.getColorModel().getTransparency() != Transparency.BITMASK) {
|
||||||
adjustQuality(pFormatQuality, FORMAT_GIF, 0.8f);
|
adjustQuality(pFormatQuality, FORMAT_GIF, 0.8f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the quality in the map.
|
* Updates the quality in the map.
|
||||||
*
|
*
|
||||||
* @param pFormatQuality Map<String,Float>
|
* @param pFormatQuality Map<String,Float>
|
||||||
* @param pFormat the format
|
* @param pFormat the format
|
||||||
* @param pFactor the quality factor
|
* @param pFactor the quality factor
|
||||||
*/
|
*/
|
||||||
private static void adjustQuality(Map<String, Float> pFormatQuality, String pFormat, float pFactor) {
|
private static void adjustQuality(Map<String, Float> pFormatQuality, String pFormat, float pFactor) {
|
||||||
Float oldValue = pFormatQuality.get(pFormat);
|
Float oldValue = pFormatQuality.get(pFormat);
|
||||||
if (oldValue != null) {
|
if (oldValue != null) {
|
||||||
pFormatQuality.put(pFormat, oldValue * pFactor);
|
pFormatQuality.put(pFormat, oldValue * pFactor);
|
||||||
//System.out.println("New vallue after multiplying with " + pFactor + " is " + pFormatQuality.get(pFormat));
|
//System.out.println("New vallue after multiplying with " + pFactor + " is " + pFormatQuality.get(pFormat));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the initial quality if this is a known format, otherwise 0.1
|
* Gets the initial quality if this is a known format, otherwise 0.1
|
||||||
*
|
*
|
||||||
* @param pFormat the format name
|
* @param pFormat the format name
|
||||||
* @return the q factor of the given format
|
* @return the q factor of the given format
|
||||||
*/
|
*/
|
||||||
private float getKnownFormatQuality(String pFormat) {
|
private float getKnownFormatQuality(String pFormat) {
|
||||||
for (int i = 0; i < sKnownFormats.length; i++) {
|
for (int i = 0; i < sKnownFormats.length; i++) {
|
||||||
if (pFormat.equals(sKnownFormats[i])) {
|
if (pFormat.equals(sKnownFormats[i])) {
|
||||||
return knownFormatQuality[i];
|
return knownFormatQuality[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0.1f;
|
return 0.1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,232 +1,232 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.ServletUtil;
|
import com.twelvemonkeys.servlet.ServletUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Servlet is able to render a cropped part of an image.
|
* This Servlet is able to render a cropped part of an image.
|
||||||
*
|
*
|
||||||
* <P><HR><P>
|
* <P><HR><P>
|
||||||
*
|
*
|
||||||
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
||||||
* <DL>
|
* <DL>
|
||||||
* <DT>{@code cropX}</DT>
|
* <DT>{@code cropX}</DT>
|
||||||
* <DD>integer, the new left edge of the image.
|
* <DD>integer, the new left edge of the image.
|
||||||
* <DT>{@code cropY}</DT>
|
* <DT>{@code cropY}</DT>
|
||||||
* <DD>integer, the new top of the image.
|
* <DD>integer, the new top of the image.
|
||||||
* <DT>{@code cropWidth}</DT>
|
* <DT>{@code cropWidth}</DT>
|
||||||
* <DD>integer, the new width of the image.
|
* <DD>integer, the new width of the image.
|
||||||
* <DT>{@code cropHeight}</DT>
|
* <DT>{@code cropHeight}</DT>
|
||||||
* <DD>integer, the new height of the image.
|
* <DD>integer, the new height of the image.
|
||||||
* <DT>{@code cropUniform}</DT>
|
* <DT>{@code cropUniform}</DT>
|
||||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||||
* {@code true}.
|
* {@code true}.
|
||||||
* <DT>{@code cropUnits}</DT>
|
* <DT>{@code cropUnits}</DT>
|
||||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||||
* {@code PIXELS} is default.
|
* {@code PIXELS} is default.
|
||||||
*
|
*
|
||||||
* <!-- inherited from ScaleImage below: -->
|
* <!-- inherited from ScaleImage below: -->
|
||||||
*
|
*
|
||||||
* <DT>{@code image}</DT>
|
* <DT>{@code image}</DT>
|
||||||
* <DD>string, the URL of the image to scale.
|
* <DD>string, the URL of the image to scale.
|
||||||
*
|
*
|
||||||
* <DT>{@code scaleX}</DT>
|
* <DT>{@code scaleX}</DT>
|
||||||
* <DD>integer, the new width of the image.
|
* <DD>integer, the new width of the image.
|
||||||
*
|
*
|
||||||
* <DT>{@code scaleY}</DT>
|
* <DT>{@code scaleY}</DT>
|
||||||
* <DD>integer, the new height of the image.
|
* <DD>integer, the new height of the image.
|
||||||
*
|
*
|
||||||
* <DT>{@code scaleUniform}</DT>
|
* <DT>{@code scaleUniform}</DT>
|
||||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||||
* {@code true}.
|
* {@code true}.
|
||||||
*
|
*
|
||||||
* <DT>{@code scaleUnits}</DT>
|
* <DT>{@code scaleUnits}</DT>
|
||||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||||
* {@code PIXELS} is default.
|
* {@code PIXELS} is default.
|
||||||
*
|
*
|
||||||
* <DT>{@code scaleQuality}</DT>
|
* <DT>{@code scaleQuality}</DT>
|
||||||
* <DD>string, one of {@code SCALE_SMOOTH}, {@code SCALE_FAST},
|
* <DD>string, one of {@code SCALE_SMOOTH}, {@code SCALE_FAST},
|
||||||
* {@code SCALE_REPLICATE}, {@code SCALE_AREA_AVERAGING}.
|
* {@code SCALE_REPLICATE}, {@code SCALE_AREA_AVERAGING}.
|
||||||
* {@code SCALE_DEFAULT} is default.
|
* {@code SCALE_DEFAULT} is default.
|
||||||
*
|
*
|
||||||
* </DL>
|
* </DL>
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* <IMG src="/crop/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=500&cropUniform=true">
|
* <IMG src="/crop/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=500&cropUniform=true">
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* <IMG src="/crop/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=50&cropUnits=PERCENT">
|
* <IMG src="/crop/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&cropWidth=50&cropUnits=PERCENT">
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: CropFilter.java#1 $
|
* @version $Id: CropFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
public class CropFilter extends ScaleFilter {
|
public class CropFilter extends ScaleFilter {
|
||||||
/** {@code cropX}*/
|
/** {@code cropX}*/
|
||||||
protected final static String PARAM_CROP_X = "cropX";
|
protected final static String PARAM_CROP_X = "cropX";
|
||||||
/** {@code cropY}*/
|
/** {@code cropY}*/
|
||||||
protected final static String PARAM_CROP_Y = "cropY";
|
protected final static String PARAM_CROP_Y = "cropY";
|
||||||
/** {@code cropWidth}*/
|
/** {@code cropWidth}*/
|
||||||
protected final static String PARAM_CROP_WIDTH = "cropWidth";
|
protected final static String PARAM_CROP_WIDTH = "cropWidth";
|
||||||
/** {@code cropHeight}*/
|
/** {@code cropHeight}*/
|
||||||
protected final static String PARAM_CROP_HEIGHT = "cropHeight";
|
protected final static String PARAM_CROP_HEIGHT = "cropHeight";
|
||||||
/** {@code cropUniform}*/
|
/** {@code cropUniform}*/
|
||||||
protected final static String PARAM_CROP_UNIFORM = "cropUniform";
|
protected final static String PARAM_CROP_UNIFORM = "cropUniform";
|
||||||
/** {@code cropUnits}*/
|
/** {@code cropUnits}*/
|
||||||
protected final static String PARAM_CROP_UNITS = "cropUnits";
|
protected final static String PARAM_CROP_UNITS = "cropUnits";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the image from the requested URL, scales it, crops it, and returns
|
* Reads the image from the requested URL, scales it, crops it, and returns
|
||||||
* it in the
|
* it in the
|
||||||
* Servlet stream. See above for details on parameters.
|
* Servlet stream. See above for details on parameters.
|
||||||
*/
|
*/
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||||
// Get crop coordinates
|
// Get crop coordinates
|
||||||
int x = ServletUtil.getIntParameter(pRequest, PARAM_CROP_X, -1);
|
int x = ServletUtil.getIntParameter(pRequest, PARAM_CROP_X, -1);
|
||||||
int y = ServletUtil.getIntParameter(pRequest, PARAM_CROP_Y, -1);
|
int y = ServletUtil.getIntParameter(pRequest, PARAM_CROP_Y, -1);
|
||||||
int width = ServletUtil.getIntParameter(pRequest, PARAM_CROP_WIDTH, -1);
|
int width = ServletUtil.getIntParameter(pRequest, PARAM_CROP_WIDTH, -1);
|
||||||
int height = ServletUtil.getIntParameter(pRequest, PARAM_CROP_HEIGHT, -1);
|
int height = ServletUtil.getIntParameter(pRequest, PARAM_CROP_HEIGHT, -1);
|
||||||
|
|
||||||
boolean uniform =
|
boolean uniform =
|
||||||
ServletUtil.getBooleanParameter(pRequest, PARAM_CROP_UNIFORM, false);
|
ServletUtil.getBooleanParameter(pRequest, PARAM_CROP_UNIFORM, false);
|
||||||
|
|
||||||
int units = getUnits(ServletUtil.getParameter(pRequest, PARAM_CROP_UNITS, null));
|
int units = getUnits(ServletUtil.getParameter(pRequest, PARAM_CROP_UNITS, null));
|
||||||
|
|
||||||
// Get crop bounds
|
// Get crop bounds
|
||||||
Rectangle bounds =
|
Rectangle bounds =
|
||||||
getBounds(x, y, width, height, units, uniform, pImage);
|
getBounds(x, y, width, height, units, uniform, pImage);
|
||||||
|
|
||||||
// Return cropped version
|
// Return cropped version
|
||||||
return pImage.getSubimage((int) bounds.getX(), (int) bounds.getY(),
|
return pImage.getSubimage((int) bounds.getX(), (int) bounds.getY(),
|
||||||
(int) bounds.getWidth(),
|
(int) bounds.getWidth(),
|
||||||
(int) bounds.getHeight());
|
(int) bounds.getHeight());
|
||||||
//return scaled.getSubimage(x, y, width, height);
|
//return scaled.getSubimage(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Rectangle getBounds(int pX, int pY, int pWidth, int pHeight,
|
protected Rectangle getBounds(int pX, int pY, int pWidth, int pHeight,
|
||||||
int pUnits, boolean pUniform,
|
int pUnits, boolean pUniform,
|
||||||
BufferedImage pImg) {
|
BufferedImage pImg) {
|
||||||
// Algoritm:
|
// Algoritm:
|
||||||
// Try to get x and y (default 0,0).
|
// Try to get x and y (default 0,0).
|
||||||
// Try to get width and height (default width-x, height-y)
|
// Try to get width and height (default width-x, height-y)
|
||||||
//
|
//
|
||||||
// If percent, get ratio
|
// If percent, get ratio
|
||||||
//
|
//
|
||||||
// If uniform
|
// If uniform
|
||||||
//
|
//
|
||||||
|
|
||||||
int oldWidth = pImg.getWidth();
|
int oldWidth = pImg.getWidth();
|
||||||
int oldHeight = pImg.getHeight();
|
int oldHeight = pImg.getHeight();
|
||||||
float ratio;
|
float ratio;
|
||||||
|
|
||||||
if (pUnits == UNITS_PERCENT) {
|
if (pUnits == UNITS_PERCENT) {
|
||||||
if (pWidth >= 0 && pHeight >= 0) {
|
if (pWidth >= 0 && pHeight >= 0) {
|
||||||
// Non-uniform
|
// Non-uniform
|
||||||
pWidth = (int) ((float) oldWidth * (float) pWidth / 100f);
|
pWidth = (int) ((float) oldWidth * (float) pWidth / 100f);
|
||||||
pHeight = (int) ((float) oldHeight * (float) pHeight / 100f);
|
pHeight = (int) ((float) oldHeight * (float) pHeight / 100f);
|
||||||
}
|
}
|
||||||
else if (pWidth >= 0) {
|
else if (pWidth >= 0) {
|
||||||
// Find ratio from pWidth
|
// Find ratio from pWidth
|
||||||
ratio = (float) pWidth / 100f;
|
ratio = (float) pWidth / 100f;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (pHeight >= 0) {
|
else if (pHeight >= 0) {
|
||||||
// Find ratio from pHeight
|
// Find ratio from pHeight
|
||||||
ratio = (float) pHeight / 100f;
|
ratio = (float) pHeight / 100f;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
}
|
}
|
||||||
// Else: No crop
|
// Else: No crop
|
||||||
}
|
}
|
||||||
//else if (UNITS_PIXELS.equalsIgnoreCase(pUnits)) {
|
//else if (UNITS_PIXELS.equalsIgnoreCase(pUnits)) {
|
||||||
else if (pUnits == UNITS_PIXELS) {
|
else if (pUnits == UNITS_PIXELS) {
|
||||||
// Uniform
|
// Uniform
|
||||||
if (pUniform) {
|
if (pUniform) {
|
||||||
if (pWidth >= 0 && pHeight >= 0) {
|
if (pWidth >= 0 && pHeight >= 0) {
|
||||||
// Compute both ratios
|
// Compute both ratios
|
||||||
ratio = (float) pWidth / (float) oldWidth;
|
ratio = (float) pWidth / (float) oldWidth;
|
||||||
float heightRatio = (float) pHeight / (float) oldHeight;
|
float heightRatio = (float) pHeight / (float) oldHeight;
|
||||||
|
|
||||||
// Find the largest ratio, and use that for both
|
// Find the largest ratio, and use that for both
|
||||||
if (heightRatio < ratio) {
|
if (heightRatio < ratio) {
|
||||||
ratio = heightRatio;
|
ratio = heightRatio;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (pWidth >= 0) {
|
else if (pWidth >= 0) {
|
||||||
// Find ratio from pWidth
|
// Find ratio from pWidth
|
||||||
ratio = (float) pWidth / (float) oldWidth;
|
ratio = (float) pWidth / (float) oldWidth;
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
}
|
}
|
||||||
else if (pHeight >= 0) {
|
else if (pHeight >= 0) {
|
||||||
// Find ratio from pHeight
|
// Find ratio from pHeight
|
||||||
ratio = (float) pHeight / (float) oldHeight;
|
ratio = (float) pHeight / (float) oldHeight;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
}
|
}
|
||||||
// Else: No crop
|
// Else: No crop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Else: No crop
|
// Else: No crop
|
||||||
|
|
||||||
// Not specified, or outside bounds: Use original dimensions
|
// Not specified, or outside bounds: Use original dimensions
|
||||||
if (pWidth < 0 || (pX < 0 && pWidth > oldWidth)
|
if (pWidth < 0 || (pX < 0 && pWidth > oldWidth)
|
||||||
|| (pX >= 0 && (pX + pWidth) > oldWidth)) {
|
|| (pX >= 0 && (pX + pWidth) > oldWidth)) {
|
||||||
pWidth = (pX >= 0 ? oldWidth - pX : oldWidth);
|
pWidth = (pX >= 0 ? oldWidth - pX : oldWidth);
|
||||||
}
|
}
|
||||||
if (pHeight < 0 || (pY < 0 && pHeight > oldHeight)
|
if (pHeight < 0 || (pY < 0 && pHeight > oldHeight)
|
||||||
|| (pY >= 0 && (pY + pHeight) > oldHeight)) {
|
|| (pY >= 0 && (pY + pHeight) > oldHeight)) {
|
||||||
pHeight = (pY >= 0 ? oldHeight - pY : oldHeight);
|
pHeight = (pY >= 0 ? oldHeight - pY : oldHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Center
|
// Center
|
||||||
if (pX < 0) {
|
if (pX < 0) {
|
||||||
pX = (pImg.getWidth() - pWidth) / 2;
|
pX = (pImg.getWidth() - pWidth) / 2;
|
||||||
}
|
}
|
||||||
if (pY < 0) {
|
if (pY < 0) {
|
||||||
pY = (pImg.getHeight() - pHeight) / 2;
|
pY = (pImg.getHeight() - pHeight) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//System.out.println("x: " + pX + " y: " + pY
|
//System.out.println("x: " + pX + " y: " + pY
|
||||||
// + " w: " + pWidth + " h " + pHeight);
|
// + " w: " + pWidth + " h " + pHeight);
|
||||||
|
|
||||||
return new Rectangle(pX, pY, pWidth, pHeight);
|
return new Rectangle(pX, pY, pWidth, pHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,217 +1,217 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.servlet.GenericFilter;
|
import com.twelvemonkeys.servlet.GenericFilter;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for image filters. Automatically decoding and encoding of
|
* Abstract base class for image filters. Automatically decoding and encoding of
|
||||||
* the image is handled in the {@code doFilterImpl} method.
|
* the image is handled in the {@code doFilterImpl} method.
|
||||||
*
|
*
|
||||||
* @see #doFilter(java.awt.image.BufferedImage,javax.servlet.ServletRequest,ImageServletResponse)
|
* @see #doFilter(java.awt.image.BufferedImage,javax.servlet.ServletRequest,ImageServletResponse)
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: ImageFilter.java#2 $
|
* @version $Id: ImageFilter.java#2 $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class ImageFilter extends GenericFilter {
|
public abstract class ImageFilter extends GenericFilter {
|
||||||
// TODO: Take the design back to the drawing board (see ImageServletResponseImpl)
|
// TODO: Take the design back to the drawing board (see ImageServletResponseImpl)
|
||||||
// - Allow multiple filters to set size attribute
|
// - Allow multiple filters to set size attribute
|
||||||
// - Allow a later filter to reset, to get pass-through given certain criteria...
|
// - Allow a later filter to reset, to get pass-through given certain criteria...
|
||||||
// - Or better yet, allow a filter to decide if it wants to decode, based on image metadata on the original image (ie: width/height)
|
// - Or better yet, allow a filter to decide if it wants to decode, based on image metadata on the original image (ie: width/height)
|
||||||
|
|
||||||
protected String[] triggerParams = null;
|
protected String[] triggerParams = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@code doFilterImpl} method is called once, or each time a
|
* The {@code doFilterImpl} method is called once, or each time a
|
||||||
* request/response pair is passed through the chain, depending on the
|
* request/response pair is passed through the chain, depending on the
|
||||||
* {@link #oncePerRequest} member variable.
|
* {@link #oncePerRequest} member variable.
|
||||||
*
|
*
|
||||||
* @see #oncePerRequest
|
* @see #oncePerRequest
|
||||||
* @see com.twelvemonkeys.servlet.GenericFilter#doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilter
|
* @see com.twelvemonkeys.servlet.GenericFilter#doFilterImpl(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilter
|
||||||
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
* @see Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) Filter.doFilter
|
||||||
*
|
*
|
||||||
* @param pRequest the servlet request
|
* @param pRequest the servlet request
|
||||||
* @param pResponse the servlet response
|
* @param pResponse the servlet response
|
||||||
* @param pChain the filter chain
|
* @param pChain the filter chain
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*/
|
*/
|
||||||
protected void doFilterImpl(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pChain)
|
protected void doFilterImpl(final ServletRequest pRequest, final ServletResponse pResponse, final FilterChain pChain)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
|
||||||
//System.out.println("Starting filtering...");
|
//System.out.println("Starting filtering...");
|
||||||
// Test for trigger params
|
// Test for trigger params
|
||||||
if (!trigger(pRequest)) {
|
if (!trigger(pRequest)) {
|
||||||
//System.out.println("Passing request on to next in chain (skipping " + getFilterName() + ")...");
|
//System.out.println("Passing request on to next in chain (skipping " + getFilterName() + ")...");
|
||||||
// Pass the request on
|
// Pass the request on
|
||||||
pChain.doFilter(pRequest, pResponse);
|
pChain.doFilter(pRequest, pResponse);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If already wrapped, the image will be encoded later in the chain
|
// If already wrapped, the image will be encoded later in the chain
|
||||||
// Or, if this is first filter in chain, we must encode when done
|
// Or, if this is first filter in chain, we must encode when done
|
||||||
boolean encode = !(pResponse instanceof ImageServletResponse);
|
boolean encode = !(pResponse instanceof ImageServletResponse);
|
||||||
|
|
||||||
// For images, we do post filtering only and need to wrap the response
|
// For images, we do post filtering only and need to wrap the response
|
||||||
ImageServletResponse imageResponse = createImageServletResponse(pRequest, pResponse);
|
ImageServletResponse imageResponse = createImageServletResponse(pRequest, pResponse);
|
||||||
|
|
||||||
//System.out.println("Passing request on to next in chain...");
|
//System.out.println("Passing request on to next in chain...");
|
||||||
// Pass the request on
|
// Pass the request on
|
||||||
pChain.doFilter(pRequest, imageResponse);
|
pChain.doFilter(pRequest, imageResponse);
|
||||||
|
|
||||||
//System.out.println("Post filtering...");
|
//System.out.println("Post filtering...");
|
||||||
|
|
||||||
// Get image
|
// Get image
|
||||||
//System.out.println("Getting image from ImageServletResponse...");
|
//System.out.println("Getting image from ImageServletResponse...");
|
||||||
// Get the image from the wrapped response
|
// Get the image from the wrapped response
|
||||||
RenderedImage image = imageResponse.getImage();
|
RenderedImage image = imageResponse.getImage();
|
||||||
//System.out.println("Got image: " + image);
|
//System.out.println("Got image: " + image);
|
||||||
|
|
||||||
// Note: Image will be null if this is a HEAD request, the
|
// Note: Image will be null if this is a HEAD request, the
|
||||||
// If-Modified-Since header is present, or similar.
|
// If-Modified-Since header is present, or similar.
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
// Do the image filtering
|
// Do the image filtering
|
||||||
//System.out.println("Filtering image (" + getFilterName() + ")...");
|
//System.out.println("Filtering image (" + getFilterName() + ")...");
|
||||||
image = doFilter(ImageUtil.toBuffered(image), pRequest, imageResponse);
|
image = doFilter(ImageUtil.toBuffered(image), pRequest, imageResponse);
|
||||||
//System.out.println("Done filtering.");
|
//System.out.println("Done filtering.");
|
||||||
|
|
||||||
//System.out.println("Making image available...");
|
//System.out.println("Making image available...");
|
||||||
// Make image available to other filters (avoid unnecessary serializing/deserializing)
|
// Make image available to other filters (avoid unnecessary serializing/deserializing)
|
||||||
imageResponse.setImage(image);
|
imageResponse.setImage(image);
|
||||||
//System.out.println("Done.");
|
//System.out.println("Done.");
|
||||||
}
|
}
|
||||||
if (encode) {
|
if (encode) {
|
||||||
//System.out.println("Encoding image...");
|
//System.out.println("Encoding image...");
|
||||||
// Encode image to original response
|
// Encode image to original response
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
// TODO: Be smarter than this...
|
// TODO: Be smarter than this...
|
||||||
// TODO: Make sure ETag is same, if image content is the same...
|
// TODO: Make sure ETag is same, if image content is the same...
|
||||||
// Use ETag of original response (or derived from)
|
// Use ETag of original response (or derived from)
|
||||||
// Use last modified of original response? Or keep original resource's, don't set at all?
|
// Use last modified of original response? Or keep original resource's, don't set at all?
|
||||||
// TODO: Why weak ETag?
|
// TODO: Why weak ETag?
|
||||||
String etag = "W/\"" + Integer.toHexString(hashCode()) + "-" + Integer.toHexString(image.hashCode()) + "\"";
|
String etag = "W/\"" + Integer.toHexString(hashCode()) + "-" + Integer.toHexString(image.hashCode()) + "\"";
|
||||||
// TODO: This breaks for wrapped instances, need to either unwrap or test for HttpSR...
|
// TODO: This breaks for wrapped instances, need to either unwrap or test for HttpSR...
|
||||||
((HttpServletResponse) pResponse).setHeader("ETag", etag);
|
((HttpServletResponse) pResponse).setHeader("ETag", etag);
|
||||||
((HttpServletResponse) pResponse).setDateHeader("Last-Modified", (System.currentTimeMillis() / 1000) * 1000);
|
((HttpServletResponse) pResponse).setDateHeader("Last-Modified", (System.currentTimeMillis() / 1000) * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
imageResponse.flush();
|
imageResponse.flush();
|
||||||
//System.out.println("Done encoding.");
|
//System.out.println("Done encoding.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//System.out.println("Filtering done.");
|
//System.out.println("Filtering done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the image servlet response for this response.
|
* Creates the image servlet response for this response.
|
||||||
*
|
*
|
||||||
* @param pResponse the original response
|
* @param pResponse the original response
|
||||||
* @param pRequest the original request
|
* @param pRequest the original request
|
||||||
* @return the new response, or {@code pResponse} if the response is already wrapped
|
* @return the new response, or {@code pResponse} if the response is already wrapped
|
||||||
*
|
*
|
||||||
* @see com.twelvemonkeys.servlet.image.ImageServletResponseWrapper
|
* @see com.twelvemonkeys.servlet.image.ImageServletResponseWrapper
|
||||||
*/
|
*/
|
||||||
private ImageServletResponse createImageServletResponse(final ServletRequest pRequest, final ServletResponse pResponse) {
|
private ImageServletResponse createImageServletResponse(final ServletRequest pRequest, final ServletResponse pResponse) {
|
||||||
if (pResponse instanceof ImageServletResponseImpl) {
|
if (pResponse instanceof ImageServletResponseImpl) {
|
||||||
ImageServletResponseImpl response = (ImageServletResponseImpl) pResponse;
|
ImageServletResponseImpl response = (ImageServletResponseImpl) pResponse;
|
||||||
// response.setRequest(pRequest);
|
// response.setRequest(pRequest);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ImageServletResponseImpl(pRequest, pResponse, getServletContext());
|
return new ImageServletResponseImpl(pRequest, pResponse, getServletContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if the filter should do image filtering/processing.
|
* Tests if the filter should do image filtering/processing.
|
||||||
* <P/>
|
* <P/>
|
||||||
* This default implementation uses {@link #triggerParams} to test if:
|
* This default implementation uses {@link #triggerParams} to test if:
|
||||||
* <dl>
|
* <dl>
|
||||||
* <dt>{@code mTriggerParams == null}</dt>
|
* <dt>{@code mTriggerParams == null}</dt>
|
||||||
* <dd>{@code return true}</dd>
|
* <dd>{@code return true}</dd>
|
||||||
* <dt>{@code mTriggerParams != null}, loop through parameters, and test
|
* <dt>{@code mTriggerParams != null}, loop through parameters, and test
|
||||||
* if {@code pRequest} contains the parameter. If match</dt>
|
* if {@code pRequest} contains the parameter. If match</dt>
|
||||||
* <dd>{@code return true}</dd>
|
* <dd>{@code return true}</dd>
|
||||||
* <dt>Otherwise</dt>
|
* <dt>Otherwise</dt>
|
||||||
* <dd>{@code return false}</dd>
|
* <dd>{@code return false}</dd>
|
||||||
* </dl>
|
* </dl>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param pRequest the servlet request
|
* @param pRequest the servlet request
|
||||||
* @return {@code true} if the filter should do image filtering
|
* @return {@code true} if the filter should do image filtering
|
||||||
*/
|
*/
|
||||||
protected boolean trigger(final ServletRequest pRequest) {
|
protected boolean trigger(final ServletRequest pRequest) {
|
||||||
// If triggerParams not set, assume always trigger
|
// If triggerParams not set, assume always trigger
|
||||||
if (triggerParams == null) {
|
if (triggerParams == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger only for certain request parameters
|
// Trigger only for certain request parameters
|
||||||
for (String triggerParam : triggerParams) {
|
for (String triggerParam : triggerParams) {
|
||||||
if (pRequest.getParameter(triggerParam) != null) {
|
if (pRequest.getParameter(triggerParam) != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Didn't trigger
|
// Didn't trigger
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the trigger parameters.
|
* Sets the trigger parameters.
|
||||||
* The parameter is supposed to be a comma-separated string of parameter
|
* The parameter is supposed to be a comma-separated string of parameter
|
||||||
* names.
|
* names.
|
||||||
*
|
*
|
||||||
* @param pTriggerParams a comma-separated string of parameter names.
|
* @param pTriggerParams a comma-separated string of parameter names.
|
||||||
*/
|
*/
|
||||||
// TODO: Make it an @InitParam, and make sure we may set String[]/Collection<String> as parameter?
|
// TODO: Make it an @InitParam, and make sure we may set String[]/Collection<String> as parameter?
|
||||||
public void setTriggerParams(final String pTriggerParams) {
|
public void setTriggerParams(final String pTriggerParams) {
|
||||||
triggerParams = StringUtil.toStringArray(pTriggerParams);
|
triggerParams = StringUtil.toStringArray(pTriggerParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters the image for this request.
|
* Filters the image for this request.
|
||||||
*
|
*
|
||||||
* @param pImage the image to filter
|
* @param pImage the image to filter
|
||||||
* @param pRequest the servlet request
|
* @param pRequest the servlet request
|
||||||
* @param pResponse the servlet response
|
* @param pResponse the servlet response
|
||||||
*
|
*
|
||||||
* @return the filtered image
|
* @return the filtered image
|
||||||
* @throws java.io.IOException if an I/O error occurs during filtering
|
* @throws java.io.IOException if an I/O error occurs during filtering
|
||||||
*/
|
*/
|
||||||
protected abstract RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException;
|
protected abstract RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This exception is a subclass of ServletException, and acts just as a marker
|
* This exception is a subclass of ServletException, and acts just as a marker
|
||||||
* for exceptions thrown by the ImageServlet API.
|
* for exceptions thrown by the ImageServlet API.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
*
|
*
|
||||||
* @version $Id: ImageServletException.java#2 $
|
* @version $Id: ImageServletException.java#2 $
|
||||||
*/
|
*/
|
||||||
public class ImageServletException extends ServletException {
|
public class ImageServletException extends ServletException {
|
||||||
|
|
||||||
public ImageServletException(String pMessage) {
|
public ImageServletException(String pMessage) {
|
||||||
super(pMessage);
|
super(pMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageServletException(Throwable pThrowable) {
|
public ImageServletException(Throwable pThrowable) {
|
||||||
super(pThrowable);
|
super(pThrowable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageServletException(String pMessage, Throwable pThrowable) {
|
public ImageServletException(String pMessage, Throwable pThrowable) {
|
||||||
super(pMessage, pThrowable);
|
super(pMessage, pThrowable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,193 +1,193 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageServletResponse.
|
* ImageServletResponse.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The request attributes regarding image size and source region (AOI) are used
|
* The request attributes regarding image size and source region (AOI) are used
|
||||||
* in the decoding process, and must be set before the first invocation of
|
* in the decoding process, and must be set before the first invocation of
|
||||||
* {@link #getImage()} to have any effect.
|
* {@link #getImage()} to have any effect.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: ImageServletResponse.java#4 $
|
* @version $Id: ImageServletResponse.java#4 $
|
||||||
*/
|
*/
|
||||||
public interface ImageServletResponse extends ServletResponse {
|
public interface ImageServletResponse extends ServletResponse {
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link java.awt.Dimension} controlling image
|
* Request attribute of type {@link java.awt.Dimension} controlling image
|
||||||
* size.
|
* size.
|
||||||
* If either {@code width} or {@code height} is negative, the size is
|
* If either {@code width} or {@code height} is negative, the size is
|
||||||
* computed, using uniform scaling.
|
* computed, using uniform scaling.
|
||||||
* Else, if {@code SIZE_UNIFORM} is {@code true}, the size will be
|
* Else, if {@code SIZE_UNIFORM} is {@code true}, the size will be
|
||||||
* computed to the largest possible area (with correct aspect ratio)
|
* computed to the largest possible area (with correct aspect ratio)
|
||||||
* fitting inside the target area.
|
* fitting inside the target area.
|
||||||
* Otherwise, the image is scaled to the given size, with no regard to
|
* Otherwise, the image is scaled to the given size, with no regard to
|
||||||
* aspect ratio.
|
* aspect ratio.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code null} (original image size).
|
* Defaults to {@code null} (original image size).
|
||||||
*/
|
*/
|
||||||
String ATTRIB_SIZE = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE";
|
String ATTRIB_SIZE = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link Boolean} controlling image sizing.
|
* Request attribute of type {@link Boolean} controlling image sizing.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code Boolean.TRUE}.
|
* Defaults to {@code Boolean.TRUE}.
|
||||||
*/
|
*/
|
||||||
String ATTRIB_SIZE_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE_UNIFORM";
|
String ATTRIB_SIZE_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE_UNIFORM";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link Boolean} controlling image sizing.
|
* Request attribute of type {@link Boolean} controlling image sizing.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code Boolean.FALSE}.
|
* Defaults to {@code Boolean.FALSE}.
|
||||||
*/
|
*/
|
||||||
String ATTRIB_SIZE_PERCENT = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE_PERCENT";
|
String ATTRIB_SIZE_PERCENT = "com.twelvemonkeys.servlet.image.ImageServletResponse.SIZE_PERCENT";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link java.awt.Rectangle} controlling image
|
* Request attribute of type {@link java.awt.Rectangle} controlling image
|
||||||
* source region (area of interest).
|
* source region (area of interest).
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code null} (the entire image).
|
* Defaults to {@code null} (the entire image).
|
||||||
*/
|
*/
|
||||||
String ATTRIB_AOI = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI";
|
String ATTRIB_AOI = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link Boolean} controlling image AOI.
|
* Request attribute of type {@link Boolean} controlling image AOI.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code Boolean.FALSE}.
|
* Defaults to {@code Boolean.FALSE}.
|
||||||
*/
|
*/
|
||||||
String ATTRIB_AOI_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI_UNIFORM";
|
String ATTRIB_AOI_UNIFORM = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI_UNIFORM";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link Boolean} controlling image AOI.
|
* Request attribute of type {@link Boolean} controlling image AOI.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code Boolean.FALSE}.
|
* Defaults to {@code Boolean.FALSE}.
|
||||||
*/
|
*/
|
||||||
String ATTRIB_AOI_PERCENT = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI_PERCENT";
|
String ATTRIB_AOI_PERCENT = "com.twelvemonkeys.servlet.image.ImageServletResponse.AOI_PERCENT";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link java.awt.Color} controlling background
|
* Request attribute of type {@link java.awt.Color} controlling background
|
||||||
* color for any transparent/translucent areas of the image.
|
* color for any transparent/translucent areas of the image.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code null} (keeps the transparent areas transparent).
|
* Defaults to {@code null} (keeps the transparent areas transparent).
|
||||||
*/
|
*/
|
||||||
String ATTRIB_BG_COLOR = "com.twelvemonkeys.servlet.image.ImageServletResponse.BG_COLOR";
|
String ATTRIB_BG_COLOR = "com.twelvemonkeys.servlet.image.ImageServletResponse.BG_COLOR";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link Float} controlling image output compression/quality.
|
* Request attribute of type {@link Float} controlling image output compression/quality.
|
||||||
* Used for formats that accepts compression or quality settings,
|
* Used for formats that accepts compression or quality settings,
|
||||||
* like JPEG (quality), PNG (compression only) etc.
|
* like JPEG (quality), PNG (compression only) etc.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code 0.8f} for JPEG.
|
* Defaults to {@code 0.8f} for JPEG.
|
||||||
*/
|
*/
|
||||||
String ATTRIB_OUTPUT_QUALITY = "com.twelvemonkeys.servlet.image.ImageServletResponse.OUTPUT_QUALITY";
|
String ATTRIB_OUTPUT_QUALITY = "com.twelvemonkeys.servlet.image.ImageServletResponse.OUTPUT_QUALITY";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link Double} controlling image read
|
* Request attribute of type {@link Double} controlling image read
|
||||||
* subsampling factor. Controls the maximum sample pixels in each direction,
|
* subsampling factor. Controls the maximum sample pixels in each direction,
|
||||||
* that is read per pixel in the output image, if the result will be
|
* that is read per pixel in the output image, if the result will be
|
||||||
* downscaled.
|
* downscaled.
|
||||||
* Larger values will result in better quality, at the expense of higher
|
* Larger values will result in better quality, at the expense of higher
|
||||||
* memory consumption and CPU usage.
|
* memory consumption and CPU usage.
|
||||||
* However, using values above {@code 3.0} will usually not improve image
|
* However, using values above {@code 3.0} will usually not improve image
|
||||||
* quality.
|
* quality.
|
||||||
* Legal values are in the range {@code [1.0 .. positive infinity>}.
|
* Legal values are in the range {@code [1.0 .. positive infinity>}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code 2.0}.
|
* Defaults to {@code 2.0}.
|
||||||
*/
|
*/
|
||||||
String ATTRIB_READ_SUBSAMPLING_FACTOR = "com.twelvemonkeys.servlet.image.ImageServletResponse.READ_SUBSAMPLING_FACTOR";
|
String ATTRIB_READ_SUBSAMPLING_FACTOR = "com.twelvemonkeys.servlet.image.ImageServletResponse.READ_SUBSAMPLING_FACTOR";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request attribute of type {@link Integer} controlling image resample
|
* Request attribute of type {@link Integer} controlling image resample
|
||||||
* algorithm.
|
* algorithm.
|
||||||
* Legal values are {@link java.awt.Image#SCALE_DEFAULT SCALE_DEFAULT},
|
* Legal values are {@link java.awt.Image#SCALE_DEFAULT SCALE_DEFAULT},
|
||||||
* {@link java.awt.Image#SCALE_FAST SCALE_FAST} or
|
* {@link java.awt.Image#SCALE_FAST SCALE_FAST} or
|
||||||
* {@link java.awt.Image#SCALE_SMOOTH SCALE_SMOOTH}.
|
* {@link java.awt.Image#SCALE_SMOOTH SCALE_SMOOTH}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note: When using a value of {@code SCALE_FAST}, you should also use a
|
* Note: When using a value of {@code SCALE_FAST}, you should also use a
|
||||||
* subsampling factor of {@code 1.0}, for fast read/scale.
|
* subsampling factor of {@code 1.0}, for fast read/scale.
|
||||||
* Otherwise, use a subsampling factor of {@code 2.0} for better quality.
|
* Otherwise, use a subsampling factor of {@code 2.0} for better quality.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Defaults to {@code SCALE_DEFAULT}.
|
* Defaults to {@code SCALE_DEFAULT}.
|
||||||
*/
|
*/
|
||||||
String ATTRIB_IMAGE_RESAMPLE_ALGORITHM = "com.twelvemonkeys.servlet.image.ImageServletResponse.IMAGE_RESAMPLE_ALGORITHM";
|
String ATTRIB_IMAGE_RESAMPLE_ALGORITHM = "com.twelvemonkeys.servlet.image.ImageServletResponse.IMAGE_RESAMPLE_ALGORITHM";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the image format for this response, such as "image/gif" or "image/jpeg".
|
* Gets the image format for this response, such as "image/gif" or "image/jpeg".
|
||||||
* If not set, the default format is that of the original image.
|
* If not set, the default format is that of the original image.
|
||||||
*
|
*
|
||||||
* @return the image format for this response.
|
* @return the image format for this response.
|
||||||
* @see #setOutputContentType(String)
|
* @see #setOutputContentType(String)
|
||||||
*/
|
*/
|
||||||
String getOutputContentType();
|
String getOutputContentType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the image format for this response, such as "image/gif" or "image/jpeg".
|
* Sets the image format for this response, such as "image/gif" or "image/jpeg".
|
||||||
* <p/>
|
* <p/>
|
||||||
* As an example, a custom filter could do content negotiation based on the
|
* As an example, a custom filter could do content negotiation based on the
|
||||||
* request header fields and write the image back in an appropriate format.
|
* request header fields and write the image back in an appropriate format.
|
||||||
* <p/>
|
* <p/>
|
||||||
* If not set, the default format is that of the original image.
|
* If not set, the default format is that of the original image.
|
||||||
*
|
*
|
||||||
* @param pImageFormat the image format for this response.
|
* @param pImageFormat the image format for this response.
|
||||||
*/
|
*/
|
||||||
void setOutputContentType(String pImageFormat);
|
void setOutputContentType(String pImageFormat);
|
||||||
|
|
||||||
//TODO: ?? void setCompressionQuality(float pQualityFactor);
|
//TODO: ?? void setCompressionQuality(float pQualityFactor);
|
||||||
//TODO: ?? float getCompressionQuality();
|
//TODO: ?? float getCompressionQuality();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the image to the original {@code ServletOutputStream}.
|
* Writes the image to the original {@code ServletOutputStream}.
|
||||||
* If no format is {@linkplain #setOutputContentType(String) set} in this response,
|
* If no format is {@linkplain #setOutputContentType(String) set} in this response,
|
||||||
* the image is encoded in the same format as the original image.
|
* the image is encoded in the same format as the original image.
|
||||||
*
|
*
|
||||||
* @throws java.io.IOException if an I/O exception occurs during writing
|
* @throws java.io.IOException if an I/O exception occurs during writing
|
||||||
*/
|
*/
|
||||||
void flush() throws IOException;
|
void flush() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the decoded image from the response.
|
* Gets the decoded image from the response.
|
||||||
*
|
*
|
||||||
* @return a {@code BufferedImage} or {@code null} if the image could not be read.
|
* @return a {@code BufferedImage} or {@code null} if the image could not be read.
|
||||||
*
|
*
|
||||||
* @throws java.io.IOException if an I/O exception occurs during reading
|
* @throws java.io.IOException if an I/O exception occurs during reading
|
||||||
*/
|
*/
|
||||||
BufferedImage getImage() throws IOException;
|
BufferedImage getImage() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the image for this response.
|
* Sets the image for this response.
|
||||||
*
|
*
|
||||||
* @param pImage the new response image.
|
* @param pImage the new response image.
|
||||||
*/
|
*/
|
||||||
void setImage(RenderedImage pImage);
|
void setImage(RenderedImage pImage);
|
||||||
}
|
}
|
||||||
|
|||||||
+804
-804
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@code ImageFilter} that does nothing. Useful for debugging purposes.
|
* An {@code ImageFilter} that does nothing. Useful for debugging purposes.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: NullImageFilter.java $
|
* @version $Id: NullImageFilter.java $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final class NullImageFilter extends ImageFilter {
|
public final class NullImageFilter extends ImageFilter {
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||||
return pImage;
|
return pImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,202 +1,202 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.servlet.ServletUtil;
|
import com.twelvemonkeys.servlet.ServletUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Servlet is able to render a cropped part of an image.
|
* This Servlet is able to render a cropped part of an image.
|
||||||
*
|
*
|
||||||
* <P><HR><P>
|
* <P><HR><P>
|
||||||
*
|
*
|
||||||
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
||||||
* <DL>
|
* <DL>
|
||||||
* <DT>{@code cropX}</DT>
|
* <DT>{@code cropX}</DT>
|
||||||
* <DD>integer, the new left edge of the image.
|
* <DD>integer, the new left edge of the image.
|
||||||
* <DT>{@code cropY}</DT>
|
* <DT>{@code cropY}</DT>
|
||||||
* <DD>integer, the new top of the image.
|
* <DD>integer, the new top of the image.
|
||||||
* <DT>{@code cropWidth}</DT>
|
* <DT>{@code cropWidth}</DT>
|
||||||
* <DD>integer, the new width of the image.
|
* <DD>integer, the new width of the image.
|
||||||
* <DT>{@code cropHeight}</DT>
|
* <DT>{@code cropHeight}</DT>
|
||||||
* <DD>integer, the new height of the image.
|
* <DD>integer, the new height of the image.
|
||||||
* <!--
|
* <!--
|
||||||
* <DT>{@code cropUniform}</DT>
|
* <DT>{@code cropUniform}</DT>
|
||||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||||
* {@code true}.
|
* {@code true}.
|
||||||
* <DT>{@code cropUnits}</DT>
|
* <DT>{@code cropUnits}</DT>
|
||||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||||
* {@code PIXELS} is default. -->
|
* {@code PIXELS} is default. -->
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* </DL>
|
* </DL>
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* JPEG:
|
* JPEG:
|
||||||
* <IMG src="/scale/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=500&uniform=true">
|
* <IMG src="/scale/test.jpg?image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=500&uniform=true">
|
||||||
*
|
*
|
||||||
* PNG:
|
* PNG:
|
||||||
* <IMG src="/scale/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=50&units=PERCENT">
|
* <IMG src="/scale/test.png?cache=false&image=http://www.iconmedialab.com/images/random/home_image_12.jpg&width=50&units=PERCENT">
|
||||||
*
|
*
|
||||||
* @todo Correct rounding errors, resulting in black borders when rotating 90
|
* @todo Correct rounding errors, resulting in black borders when rotating 90
|
||||||
* degrees, and one of width or height is odd length...
|
* degrees, and one of width or height is odd length...
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: RotateFilter.java#1 $
|
* @version $Id: RotateFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class RotateFilter extends ImageFilter {
|
public class RotateFilter extends ImageFilter {
|
||||||
/** {@code angle}*/
|
/** {@code angle}*/
|
||||||
protected final static String PARAM_ANGLE = "angle";
|
protected final static String PARAM_ANGLE = "angle";
|
||||||
/** {@code angleUnits (RADIANS|DEGREES)}*/
|
/** {@code angleUnits (RADIANS|DEGREES)}*/
|
||||||
protected final static String PARAM_ANGLE_UNITS = "angleUnits";
|
protected final static String PARAM_ANGLE_UNITS = "angleUnits";
|
||||||
/** {@code crop}*/
|
/** {@code crop}*/
|
||||||
protected final static String PARAM_CROP = "rotateCrop";
|
protected final static String PARAM_CROP = "rotateCrop";
|
||||||
/** {@code bgcolor}*/
|
/** {@code bgcolor}*/
|
||||||
protected final static String PARAM_BGCOLOR = "rotateBgcolor";
|
protected final static String PARAM_BGCOLOR = "rotateBgcolor";
|
||||||
|
|
||||||
/** {@code degrees}*/
|
/** {@code degrees}*/
|
||||||
private final static String ANGLE_DEGREES = "degrees";
|
private final static String ANGLE_DEGREES = "degrees";
|
||||||
/** {@code radians}*/
|
/** {@code radians}*/
|
||||||
//private final static String ANGLE_RADIANS = "radians";
|
//private final static String ANGLE_RADIANS = "radians";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the image from the requested URL, rotates it, and returns
|
* Reads the image from the requested URL, rotates it, and returns
|
||||||
* it in the
|
* it in the
|
||||||
* Servlet stream. See above for details on parameters.
|
* Servlet stream. See above for details on parameters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||||
// Get angle
|
// Get angle
|
||||||
double ang = getAngle(pRequest);
|
double ang = getAngle(pRequest);
|
||||||
|
|
||||||
// Get bounds
|
// Get bounds
|
||||||
Rectangle2D rect = getBounds(pRequest, pImage, ang);
|
Rectangle2D rect = getBounds(pRequest, pImage, ang);
|
||||||
int width = (int) rect.getWidth();
|
int width = (int) rect.getWidth();
|
||||||
int height = (int) rect.getHeight();
|
int height = (int) rect.getHeight();
|
||||||
|
|
||||||
// Create result image
|
// Create result image
|
||||||
BufferedImage res = ImageUtil.createTransparent(width, height, BufferedImage.TYPE_INT_ARGB);
|
BufferedImage res = ImageUtil.createTransparent(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
Graphics2D g = res.createGraphics();
|
Graphics2D g = res.createGraphics();
|
||||||
|
|
||||||
// Get background color and clear
|
// Get background color and clear
|
||||||
String str = pRequest.getParameter(PARAM_BGCOLOR);
|
String str = pRequest.getParameter(PARAM_BGCOLOR);
|
||||||
if (!StringUtil.isEmpty(str)) {
|
if (!StringUtil.isEmpty(str)) {
|
||||||
Color bgcolor = StringUtil.toColor(str);
|
Color bgcolor = StringUtil.toColor(str);
|
||||||
g.setBackground(bgcolor);
|
g.setBackground(bgcolor);
|
||||||
g.clearRect(0, 0, width, height);
|
g.clearRect(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set mHints (why do I always get jagged edgdes?)
|
// Set mHints (why do I always get jagged edgdes?)
|
||||||
RenderingHints hints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
RenderingHints hints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||||
hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
|
hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
|
||||||
hints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
|
hints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
|
||||||
hints.add(new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC));
|
hints.add(new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC));
|
||||||
|
|
||||||
g.setRenderingHints(hints);
|
g.setRenderingHints(hints);
|
||||||
|
|
||||||
// Rotate around center
|
// Rotate around center
|
||||||
AffineTransform at = AffineTransform
|
AffineTransform at = AffineTransform
|
||||||
.getRotateInstance(ang, width / 2.0, height / 2.0);
|
.getRotateInstance(ang, width / 2.0, height / 2.0);
|
||||||
|
|
||||||
// Move to center
|
// Move to center
|
||||||
at.translate(width / 2.0 - pImage.getWidth() / 2.0,
|
at.translate(width / 2.0 - pImage.getWidth() / 2.0,
|
||||||
height / 2.0 - pImage.getHeight() / 2.0);
|
height / 2.0 - pImage.getHeight() / 2.0);
|
||||||
|
|
||||||
// Draw it, centered
|
// Draw it, centered
|
||||||
g.drawImage(pImage, at, null);
|
g.drawImage(pImage, at, null);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the angle of rotation.
|
* Gets the angle of rotation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private double getAngle(ServletRequest pReq) {
|
private double getAngle(ServletRequest pReq) {
|
||||||
double angle = 0.0;
|
double angle = 0.0;
|
||||||
String str = pReq.getParameter(PARAM_ANGLE);
|
String str = pReq.getParameter(PARAM_ANGLE);
|
||||||
if (!StringUtil.isEmpty(str)) {
|
if (!StringUtil.isEmpty(str)) {
|
||||||
angle = Double.parseDouble(str);
|
angle = Double.parseDouble(str);
|
||||||
|
|
||||||
// Convert to radians, if needed
|
// Convert to radians, if needed
|
||||||
str = pReq.getParameter(PARAM_ANGLE_UNITS);
|
str = pReq.getParameter(PARAM_ANGLE_UNITS);
|
||||||
if (!StringUtil.isEmpty(str)
|
if (!StringUtil.isEmpty(str)
|
||||||
&& ANGLE_DEGREES.equalsIgnoreCase(str)) {
|
&& ANGLE_DEGREES.equalsIgnoreCase(str)) {
|
||||||
angle = Math.toRadians(angle);
|
angle = Math.toRadians(angle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the bounding rectangle of the rotated image.
|
* Get the bounding rectangle of the rotated image.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private Rectangle2D getBounds(ServletRequest pReq, BufferedImage pImage,
|
private Rectangle2D getBounds(ServletRequest pReq, BufferedImage pImage,
|
||||||
double pAng) {
|
double pAng) {
|
||||||
// Get dimensions of original image
|
// Get dimensions of original image
|
||||||
int width = pImage.getWidth(); // loads the image
|
int width = pImage.getWidth(); // loads the image
|
||||||
int height = pImage.getHeight();
|
int height = pImage.getHeight();
|
||||||
|
|
||||||
// Test if we want to crop image (default)
|
// Test if we want to crop image (default)
|
||||||
// if true
|
// if true
|
||||||
// - find the largest bounding box INSIDE the rotated image,
|
// - find the largest bounding box INSIDE the rotated image,
|
||||||
// that matches the original proportions (nearest 90deg)
|
// that matches the original proportions (nearest 90deg)
|
||||||
// (scale up to fit dimensions?)
|
// (scale up to fit dimensions?)
|
||||||
// else
|
// else
|
||||||
// - find the smallest bounding box OUTSIDE the rotated image.
|
// - find the smallest bounding box OUTSIDE the rotated image.
|
||||||
// - that matches the original proportions (nearest 90deg) ?
|
// - that matches the original proportions (nearest 90deg) ?
|
||||||
// (scale down to fit dimensions?)
|
// (scale down to fit dimensions?)
|
||||||
AffineTransform at =
|
AffineTransform at =
|
||||||
AffineTransform.getRotateInstance(pAng, width / 2.0, height / 2.0);
|
AffineTransform.getRotateInstance(pAng, width / 2.0, height / 2.0);
|
||||||
|
|
||||||
Rectangle2D orig = new Rectangle(width, height);
|
Rectangle2D orig = new Rectangle(width, height);
|
||||||
Shape rotated = at.createTransformedShape(orig);
|
Shape rotated = at.createTransformedShape(orig);
|
||||||
|
|
||||||
if (ServletUtil.getBooleanParameter(pReq, PARAM_CROP, false)) {
|
if (ServletUtil.getBooleanParameter(pReq, PARAM_CROP, false)) {
|
||||||
// TODO: Inside box
|
// TODO: Inside box
|
||||||
return rotated.getBounds2D();
|
return rotated.getBounds2D();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return rotated.getBounds2D();
|
return rotated.getBounds2D();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,322 +1,322 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name "TwelveMonkeys" nor the
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import com.twelvemonkeys.servlet.ServletUtil;
|
import com.twelvemonkeys.servlet.ServletUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This filter renders a scaled version of an image read from a
|
* This filter renders a scaled version of an image read from a
|
||||||
* given URL. The image can be output as a GIF, JPEG or PNG image
|
* given URL. The image can be output as a GIF, JPEG or PNG image
|
||||||
* or similar<!--,
|
* or similar<!--,
|
||||||
* with optional caching of the rendered image files-->.
|
* with optional caching of the rendered image files-->.
|
||||||
* <P>
|
* <P>
|
||||||
* <P><HR><P>
|
* <P><HR><P>
|
||||||
* <p/>
|
* <p/>
|
||||||
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
||||||
* <DL>
|
* <DL>
|
||||||
* <DT>{@code scaleX}</DT>
|
* <DT>{@code scaleX}</DT>
|
||||||
* <DD>integer, the new width of the image.
|
* <DD>integer, the new width of the image.
|
||||||
* <DT>{@code scaleY}</DT>
|
* <DT>{@code scaleY}</DT>
|
||||||
* <DD>integer, the new height of the image.
|
* <DD>integer, the new height of the image.
|
||||||
* <DT>{@code scaleUniform}</DT>
|
* <DT>{@code scaleUniform}</DT>
|
||||||
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
* <DD>boolean, wether or not uniform scalnig should be used. Default is
|
||||||
* {@code true}.
|
* {@code true}.
|
||||||
* <DT>{@code scaleUnits}</DT>
|
* <DT>{@code scaleUnits}</DT>
|
||||||
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
* <DD>string, one of {@code PIXELS}, {@code PERCENT}.
|
||||||
* {@code PIXELS} is default.
|
* {@code PIXELS} is default.
|
||||||
* <DT>{@code scaleQuality}</DT>
|
* <DT>{@code scaleQuality}</DT>
|
||||||
* <DD>string, one of {@code SCALE_SMOOTH}, {@code SCALE_FAST},
|
* <DD>string, one of {@code SCALE_SMOOTH}, {@code SCALE_FAST},
|
||||||
* {@code SCALE_REPLICATE}, {@code SCALE_AREA_AVERAGING}.
|
* {@code SCALE_REPLICATE}, {@code SCALE_AREA_AVERAGING}.
|
||||||
* {@code SCALE_DEFAULT} is default (see
|
* {@code SCALE_DEFAULT} is default (see
|
||||||
* {@link java.awt.Image#getScaledInstance(int,int,int)}, {@link java.awt.Image}
|
* {@link java.awt.Image#getScaledInstance(int,int,int)}, {@link java.awt.Image}
|
||||||
* for more details).
|
* for more details).
|
||||||
* </DL>
|
* </DL>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: ScaleFilter.java#1 $
|
* @version $Id: ScaleFilter.java#1 $
|
||||||
*
|
*
|
||||||
* @example <IMG src="/scale/test.jpg?scaleX=500&scaleUniform=false">
|
* @example <IMG src="/scale/test.jpg?scaleX=500&scaleUniform=false">
|
||||||
* @example <IMG src="/scale/test.png?scaleY=50&scaleUnits=PERCENT">
|
* @example <IMG src="/scale/test.png?scaleY=50&scaleUnits=PERCENT">
|
||||||
*/
|
*/
|
||||||
public class ScaleFilter extends ImageFilter {
|
public class ScaleFilter extends ImageFilter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Width and height are absolute pixels. The default.
|
* Width and height are absolute pixels. The default.
|
||||||
*/
|
*/
|
||||||
public static final int UNITS_PIXELS = 1;
|
public static final int UNITS_PIXELS = 1;
|
||||||
/**
|
/**
|
||||||
* Width and height are percentage of original width and height.
|
* Width and height are percentage of original width and height.
|
||||||
*/
|
*/
|
||||||
public static final int UNITS_PERCENT = 5;
|
public static final int UNITS_PERCENT = 5;
|
||||||
/**
|
/**
|
||||||
* Ahh, good choice!
|
* Ahh, good choice!
|
||||||
*/
|
*/
|
||||||
//private static final int UNITS_METRIC = 42;
|
//private static final int UNITS_METRIC = 42;
|
||||||
/**
|
/**
|
||||||
* The root of all evil...
|
* The root of all evil...
|
||||||
*/
|
*/
|
||||||
//private static final int UNITS_INCHES = 666;
|
//private static final int UNITS_INCHES = 666;
|
||||||
/**
|
/**
|
||||||
* Unknown units. <!-- Oops, what now? -->
|
* Unknown units. <!-- Oops, what now? -->
|
||||||
*/
|
*/
|
||||||
public static final int UNITS_UNKNOWN = 0;
|
public static final int UNITS_UNKNOWN = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code scaleQuality}
|
* {@code scaleQuality}
|
||||||
*/
|
*/
|
||||||
protected final static String PARAM_SCALE_QUALITY = "scaleQuality";
|
protected final static String PARAM_SCALE_QUALITY = "scaleQuality";
|
||||||
/**
|
/**
|
||||||
* {@code scaleUnits}
|
* {@code scaleUnits}
|
||||||
*/
|
*/
|
||||||
protected final static String PARAM_SCALE_UNITS = "scaleUnits";
|
protected final static String PARAM_SCALE_UNITS = "scaleUnits";
|
||||||
/**
|
/**
|
||||||
* {@code scaleUniform}
|
* {@code scaleUniform}
|
||||||
*/
|
*/
|
||||||
protected final static String PARAM_SCALE_UNIFORM = "scaleUniform";
|
protected final static String PARAM_SCALE_UNIFORM = "scaleUniform";
|
||||||
/**
|
/**
|
||||||
* {@code scaleX}
|
* {@code scaleX}
|
||||||
*/
|
*/
|
||||||
protected final static String PARAM_SCALE_X = "scaleX";
|
protected final static String PARAM_SCALE_X = "scaleX";
|
||||||
/**
|
/**
|
||||||
* {@code scaleY}
|
* {@code scaleY}
|
||||||
*/
|
*/
|
||||||
protected final static String PARAM_SCALE_Y = "scaleY";
|
protected final static String PARAM_SCALE_Y = "scaleY";
|
||||||
/**
|
/**
|
||||||
* {@code image}
|
* {@code image}
|
||||||
*/
|
*/
|
||||||
protected final static String PARAM_IMAGE = "image";
|
protected final static String PARAM_IMAGE = "image";
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
protected int defaultScaleQuality = Image.SCALE_DEFAULT;
|
protected int defaultScaleQuality = Image.SCALE_DEFAULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the image from the requested URL, scales it, and returns it in the
|
* Reads the image from the requested URL, scales it, and returns it in the
|
||||||
* Servlet stream. See above for details on parameters.
|
* Servlet stream. See above for details on parameters.
|
||||||
*/
|
*/
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||||
|
|
||||||
// Get quality setting
|
// Get quality setting
|
||||||
// SMOOTH | FAST | REPLICATE | DEFAULT | AREA_AVERAGING
|
// SMOOTH | FAST | REPLICATE | DEFAULT | AREA_AVERAGING
|
||||||
// See Image (mHints)
|
// See Image (mHints)
|
||||||
int quality = getQuality(pRequest.getParameter(PARAM_SCALE_QUALITY));
|
int quality = getQuality(pRequest.getParameter(PARAM_SCALE_QUALITY));
|
||||||
|
|
||||||
// Get units, default is pixels
|
// Get units, default is pixels
|
||||||
// PIXELS | PERCENT | METRIC | INCHES
|
// PIXELS | PERCENT | METRIC | INCHES
|
||||||
int units = getUnits(pRequest.getParameter(PARAM_SCALE_UNITS));
|
int units = getUnits(pRequest.getParameter(PARAM_SCALE_UNITS));
|
||||||
if (units == UNITS_UNKNOWN) {
|
if (units == UNITS_UNKNOWN) {
|
||||||
log("Unknown units for scale, returning original.");
|
log("Unknown units for scale, returning original.");
|
||||||
return pImage;
|
return pImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use uniform scaling? Default is true
|
// Use uniform scaling? Default is true
|
||||||
boolean uniformScale = ServletUtil.getBooleanParameter(pRequest, PARAM_SCALE_UNIFORM, true);
|
boolean uniformScale = ServletUtil.getBooleanParameter(pRequest, PARAM_SCALE_UNIFORM, true);
|
||||||
|
|
||||||
// Get dimensions
|
// Get dimensions
|
||||||
int width = ServletUtil.getIntParameter(pRequest, PARAM_SCALE_X, -1);
|
int width = ServletUtil.getIntParameter(pRequest, PARAM_SCALE_X, -1);
|
||||||
int height = ServletUtil.getIntParameter(pRequest, PARAM_SCALE_Y, -1);
|
int height = ServletUtil.getIntParameter(pRequest, PARAM_SCALE_Y, -1);
|
||||||
|
|
||||||
// Get dimensions for scaled image
|
// Get dimensions for scaled image
|
||||||
Dimension dim = getDimensions(pImage, width, height, units, uniformScale);
|
Dimension dim = getDimensions(pImage, width, height, units, uniformScale);
|
||||||
|
|
||||||
width = (int) dim.getWidth();
|
width = (int) dim.getWidth();
|
||||||
height = (int) dim.getHeight();
|
height = (int) dim.getHeight();
|
||||||
|
|
||||||
// Return scaled instance directly
|
// Return scaled instance directly
|
||||||
return ImageUtil.createScaled(pImage, width, height, quality);
|
return ImageUtil.createScaled(pImage, width, height, quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the quality constant for the scaling, from the string argument.
|
* Gets the quality constant for the scaling, from the string argument.
|
||||||
*
|
*
|
||||||
* @param pQualityStr The string representation of the scale quality
|
* @param pQualityStr The string representation of the scale quality
|
||||||
* constant.
|
* constant.
|
||||||
* @return The matching quality constant, or the default quality if none
|
* @return The matching quality constant, or the default quality if none
|
||||||
* was found.
|
* was found.
|
||||||
* @see java.awt.Image
|
* @see java.awt.Image
|
||||||
* @see java.awt.Image#getScaledInstance(int,int,int)
|
* @see java.awt.Image#getScaledInstance(int,int,int)
|
||||||
*/
|
*/
|
||||||
protected int getQuality(String pQualityStr) {
|
protected int getQuality(String pQualityStr) {
|
||||||
if (!StringUtil.isEmpty(pQualityStr)) {
|
if (!StringUtil.isEmpty(pQualityStr)) {
|
||||||
try {
|
try {
|
||||||
// Get quality constant from Image using reflection
|
// Get quality constant from Image using reflection
|
||||||
Class cl = Image.class;
|
Class cl = Image.class;
|
||||||
Field field = cl.getField(pQualityStr.toUpperCase());
|
Field field = cl.getField(pQualityStr.toUpperCase());
|
||||||
|
|
||||||
return field.getInt(null);
|
return field.getInt(null);
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException ia) {
|
catch (IllegalAccessException ia) {
|
||||||
log("Unable to get quality.", ia);
|
log("Unable to get quality.", ia);
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException nsf) {
|
catch (NoSuchFieldException nsf) {
|
||||||
log("Unable to get quality.", nsf);
|
log("Unable to get quality.", nsf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultScaleQuality;
|
return defaultScaleQuality;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultScaleQuality(String pDefaultScaleQuality) {
|
public void setDefaultScaleQuality(String pDefaultScaleQuality) {
|
||||||
defaultScaleQuality = getQuality(pDefaultScaleQuality);
|
defaultScaleQuality = getQuality(pDefaultScaleQuality);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the units constant for the width and height arguments, from the
|
* Gets the units constant for the width and height arguments, from the
|
||||||
* given string argument.
|
* given string argument.
|
||||||
*
|
*
|
||||||
* @param pUnitStr The string representation of the units constant,
|
* @param pUnitStr The string representation of the units constant,
|
||||||
* can be one of "PIXELS" or "PERCENT".
|
* can be one of "PIXELS" or "PERCENT".
|
||||||
* @return The mathcing units constant, or UNITS_UNKNOWN if none was found.
|
* @return The mathcing units constant, or UNITS_UNKNOWN if none was found.
|
||||||
*/
|
*/
|
||||||
protected int getUnits(String pUnitStr) {
|
protected int getUnits(String pUnitStr) {
|
||||||
if (StringUtil.isEmpty(pUnitStr)
|
if (StringUtil.isEmpty(pUnitStr)
|
||||||
|| pUnitStr.equalsIgnoreCase("PIXELS")) {
|
|| pUnitStr.equalsIgnoreCase("PIXELS")) {
|
||||||
return UNITS_PIXELS;
|
return UNITS_PIXELS;
|
||||||
}
|
}
|
||||||
else if (pUnitStr.equalsIgnoreCase("PERCENT")) {
|
else if (pUnitStr.equalsIgnoreCase("PERCENT")) {
|
||||||
return UNITS_PERCENT;
|
return UNITS_PERCENT;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return UNITS_UNKNOWN;
|
return UNITS_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the dimensions (height and width) of the scaled image. The
|
* Gets the dimensions (height and width) of the scaled image. The
|
||||||
* dimensions are computed based on the old image's dimensions, the units
|
* dimensions are computed based on the old image's dimensions, the units
|
||||||
* used for specifying new dimensions and whether or not uniform scaling
|
* used for specifying new dimensions and whether or not uniform scaling
|
||||||
* should be used (se algorithm below).
|
* should be used (se algorithm below).
|
||||||
*
|
*
|
||||||
* @param pImage the image to be scaled
|
* @param pImage the image to be scaled
|
||||||
* @param pWidth the new width of the image, or -1 if unknown
|
* @param pWidth the new width of the image, or -1 if unknown
|
||||||
* @param pHeight the new height of the image, or -1 if unknown
|
* @param pHeight the new height of the image, or -1 if unknown
|
||||||
* @param pUnits the constant specifying units for width and height
|
* @param pUnits the constant specifying units for width and height
|
||||||
* parameter (UNITS_PIXELS or UNITS_PERCENT)
|
* parameter (UNITS_PIXELS or UNITS_PERCENT)
|
||||||
* @param pUniformScale boolean specifying uniform scale or not
|
* @param pUniformScale boolean specifying uniform scale or not
|
||||||
* @return a Dimension object, with the correct width and heigth
|
* @return a Dimension object, with the correct width and heigth
|
||||||
* in pixels, for the scaled version of the image.
|
* in pixels, for the scaled version of the image.
|
||||||
*/
|
*/
|
||||||
protected Dimension getDimensions(Image pImage, int pWidth, int pHeight,
|
protected Dimension getDimensions(Image pImage, int pWidth, int pHeight,
|
||||||
int pUnits, boolean pUniformScale) {
|
int pUnits, boolean pUniformScale) {
|
||||||
|
|
||||||
// If uniform, make sure width and height are scaled the same ammount
|
// If uniform, make sure width and height are scaled the same ammount
|
||||||
// (use ONLY height or ONLY width).
|
// (use ONLY height or ONLY width).
|
||||||
//
|
//
|
||||||
// Algoritm:
|
// Algoritm:
|
||||||
// if uniform
|
// if uniform
|
||||||
// if newHeight not set
|
// if newHeight not set
|
||||||
// find ratio newWidth / oldWidth
|
// find ratio newWidth / oldWidth
|
||||||
// oldHeight *= ratio
|
// oldHeight *= ratio
|
||||||
// else if newWidth not set
|
// else if newWidth not set
|
||||||
// find ratio newWidth / oldWidth
|
// find ratio newWidth / oldWidth
|
||||||
// oldHeight *= ratio
|
// oldHeight *= ratio
|
||||||
// else
|
// else
|
||||||
// find both ratios and use the smallest one
|
// find both ratios and use the smallest one
|
||||||
// (this will be the largest version of the image that fits
|
// (this will be the largest version of the image that fits
|
||||||
// inside the rectangle given)
|
// inside the rectangle given)
|
||||||
// (if PERCENT, just use smallest percentage).
|
// (if PERCENT, just use smallest percentage).
|
||||||
//
|
//
|
||||||
// If units is percent, we only need old height and width
|
// If units is percent, we only need old height and width
|
||||||
|
|
||||||
int oldWidth = ImageUtil.getWidth(pImage);
|
int oldWidth = ImageUtil.getWidth(pImage);
|
||||||
int oldHeight = ImageUtil.getHeight(pImage);
|
int oldHeight = ImageUtil.getHeight(pImage);
|
||||||
float ratio;
|
float ratio;
|
||||||
|
|
||||||
if (pUnits == UNITS_PERCENT) {
|
if (pUnits == UNITS_PERCENT) {
|
||||||
if (pWidth >= 0 && pHeight >= 0) {
|
if (pWidth >= 0 && pHeight >= 0) {
|
||||||
// Non-uniform
|
// Non-uniform
|
||||||
pWidth = (int) ((float) oldWidth * (float) pWidth / 100f);
|
pWidth = (int) ((float) oldWidth * (float) pWidth / 100f);
|
||||||
pHeight = (int) ((float) oldHeight * (float) pHeight / 100f);
|
pHeight = (int) ((float) oldHeight * (float) pHeight / 100f);
|
||||||
}
|
}
|
||||||
else if (pWidth >= 0) {
|
else if (pWidth >= 0) {
|
||||||
// Find ratio from pWidth
|
// Find ratio from pWidth
|
||||||
ratio = (float) pWidth / 100f;
|
ratio = (float) pWidth / 100f;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
}
|
}
|
||||||
else if (pHeight >= 0) {
|
else if (pHeight >= 0) {
|
||||||
// Find ratio from pHeight
|
// Find ratio from pHeight
|
||||||
ratio = (float) pHeight / 100f;
|
ratio = (float) pHeight / 100f;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
}
|
}
|
||||||
// Else: No scale
|
// Else: No scale
|
||||||
}
|
}
|
||||||
else if (pUnits == UNITS_PIXELS) {
|
else if (pUnits == UNITS_PIXELS) {
|
||||||
if (pUniformScale) {
|
if (pUniformScale) {
|
||||||
if (pWidth >= 0 && pHeight >= 0) {
|
if (pWidth >= 0 && pHeight >= 0) {
|
||||||
// Compute both ratios
|
// Compute both ratios
|
||||||
ratio = (float) pWidth / (float) oldWidth;
|
ratio = (float) pWidth / (float) oldWidth;
|
||||||
float heightRatio = (float) pHeight / (float) oldHeight;
|
float heightRatio = (float) pHeight / (float) oldHeight;
|
||||||
|
|
||||||
// Find the largest ratio, and use that for both
|
// Find the largest ratio, and use that for both
|
||||||
if (heightRatio < ratio) {
|
if (heightRatio < ratio) {
|
||||||
ratio = heightRatio;
|
ratio = heightRatio;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (pWidth >= 0) {
|
else if (pWidth >= 0) {
|
||||||
// Find ratio from pWidth
|
// Find ratio from pWidth
|
||||||
ratio = (float) pWidth / (float) oldWidth;
|
ratio = (float) pWidth / (float) oldWidth;
|
||||||
pHeight = (int) ((float) oldHeight * ratio);
|
pHeight = (int) ((float) oldHeight * ratio);
|
||||||
}
|
}
|
||||||
else if (pHeight >= 0) {
|
else if (pHeight >= 0) {
|
||||||
// Find ratio from pHeight
|
// Find ratio from pHeight
|
||||||
ratio = (float) pHeight / (float) oldHeight;
|
ratio = (float) pHeight / (float) oldHeight;
|
||||||
pWidth = (int) ((float) oldWidth * ratio);
|
pWidth = (int) ((float) oldWidth * ratio);
|
||||||
}
|
}
|
||||||
// Else: No scale
|
// Else: No scale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default is no scale, just work as a proxy
|
// Default is no scale, just work as a proxy
|
||||||
if (pWidth < 0) {
|
if (pWidth < 0) {
|
||||||
pWidth = oldWidth;
|
pWidth = oldWidth;
|
||||||
}
|
}
|
||||||
if (pHeight < 0) {
|
if (pHeight < 0) {
|
||||||
pHeight = oldHeight;
|
pHeight = oldHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new Dimension object and return
|
// Create new Dimension object and return
|
||||||
return new Dimension(pWidth, pHeight);
|
return new Dimension(pWidth, pHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,154 +1,154 @@
|
|||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
|
|
||||||
import com.twelvemonkeys.servlet.ServletUtil;
|
import com.twelvemonkeys.servlet.ServletUtil;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link javax.servlet.Filter} that extracts request parameters, and sets the
|
* A {@link javax.servlet.Filter} that extracts request parameters, and sets the
|
||||||
* corresponding request attributes from {@link ImageServletResponse}.
|
* corresponding request attributes from {@link ImageServletResponse}.
|
||||||
* Only affects how the image is decoded, and must be applied before any
|
* Only affects how the image is decoded, and must be applied before any
|
||||||
* other image filters in the chain.
|
* other image filters in the chain.
|
||||||
* <p/>
|
* <p/>
|
||||||
* @see ImageServletResponse#ATTRIB_SIZE
|
* @see ImageServletResponse#ATTRIB_SIZE
|
||||||
* @see ImageServletResponse#ATTRIB_AOI
|
* @see ImageServletResponse#ATTRIB_AOI
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: SourceRenderFilter.java#1 $
|
* @version $Id: SourceRenderFilter.java#1 $
|
||||||
*/
|
*/
|
||||||
public class SourceRenderFilter extends ImageFilter {
|
public class SourceRenderFilter extends ImageFilter {
|
||||||
private String sizeWidthParam = "size.w";
|
private String sizeWidthParam = "size.w";
|
||||||
private String sizeHeightParam = "size.h";
|
private String sizeHeightParam = "size.h";
|
||||||
private String sizePercentParam = "size.percent";
|
private String sizePercentParam = "size.percent";
|
||||||
private String sizeUniformParam = "size.uniform";
|
private String sizeUniformParam = "size.uniform";
|
||||||
|
|
||||||
private String regionWidthParam = "aoi.w";
|
private String regionWidthParam = "aoi.w";
|
||||||
private String regionHeightParam = "aoi.h";
|
private String regionHeightParam = "aoi.h";
|
||||||
private String regionLeftParam = "aoi.x";
|
private String regionLeftParam = "aoi.x";
|
||||||
private String regionTopParam = "aoi.y";
|
private String regionTopParam = "aoi.y";
|
||||||
private String regionPercentParam = "aoi.percent";
|
private String regionPercentParam = "aoi.percent";
|
||||||
private String regionUniformParam = "aoi.uniform";
|
private String regionUniformParam = "aoi.uniform";
|
||||||
|
|
||||||
public void setRegionHeightParam(String pRegionHeightParam) {
|
public void setRegionHeightParam(String pRegionHeightParam) {
|
||||||
regionHeightParam = pRegionHeightParam;
|
regionHeightParam = pRegionHeightParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegionWidthParam(String pRegionWidthParam) {
|
public void setRegionWidthParam(String pRegionWidthParam) {
|
||||||
regionWidthParam = pRegionWidthParam;
|
regionWidthParam = pRegionWidthParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegionLeftParam(String pRegionLeftParam) {
|
public void setRegionLeftParam(String pRegionLeftParam) {
|
||||||
regionLeftParam = pRegionLeftParam;
|
regionLeftParam = pRegionLeftParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegionTopParam(String pRegionTopParam) {
|
public void setRegionTopParam(String pRegionTopParam) {
|
||||||
regionTopParam = pRegionTopParam;
|
regionTopParam = pRegionTopParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSizeHeightParam(String pSizeHeightParam) {
|
public void setSizeHeightParam(String pSizeHeightParam) {
|
||||||
sizeHeightParam = pSizeHeightParam;
|
sizeHeightParam = pSizeHeightParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSizeWidthParam(String pSizeWidthParam) {
|
public void setSizeWidthParam(String pSizeWidthParam) {
|
||||||
sizeWidthParam = pSizeWidthParam;
|
sizeWidthParam = pSizeWidthParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegionPercentParam(String pRegionPercentParam) {
|
public void setRegionPercentParam(String pRegionPercentParam) {
|
||||||
regionPercentParam = pRegionPercentParam;
|
regionPercentParam = pRegionPercentParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRegionUniformParam(String pRegionUniformParam) {
|
public void setRegionUniformParam(String pRegionUniformParam) {
|
||||||
regionUniformParam = pRegionUniformParam;
|
regionUniformParam = pRegionUniformParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSizePercentParam(String pSizePercentParam) {
|
public void setSizePercentParam(String pSizePercentParam) {
|
||||||
sizePercentParam = pSizePercentParam;
|
sizePercentParam = pSizePercentParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSizeUniformParam(String pSizeUniformParam) {
|
public void setSizeUniformParam(String pSizeUniformParam) {
|
||||||
sizeUniformParam = pSizeUniformParam;
|
sizeUniformParam = pSizeUniformParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() throws ServletException {
|
public void init() throws ServletException {
|
||||||
if (triggerParams == null) {
|
if (triggerParams == null) {
|
||||||
// Add all params as triggers
|
// Add all params as triggers
|
||||||
triggerParams = new String[]{sizeWidthParam, sizeHeightParam,
|
triggerParams = new String[]{sizeWidthParam, sizeHeightParam,
|
||||||
sizeUniformParam, sizePercentParam,
|
sizeUniformParam, sizePercentParam,
|
||||||
regionLeftParam, regionTopParam,
|
regionLeftParam, regionTopParam,
|
||||||
regionWidthParam, regionHeightParam,
|
regionWidthParam, regionHeightParam,
|
||||||
regionUniformParam, regionPercentParam};
|
regionUniformParam, regionPercentParam};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts request parameters, and sets the corresponding request
|
* Extracts request parameters, and sets the corresponding request
|
||||||
* attributes if specified.
|
* attributes if specified.
|
||||||
*
|
*
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
* @param pChain
|
* @param pChain
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
*/
|
*/
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
// TODO: Max size configuration, to avoid DOS attacks? OutOfMemory
|
// TODO: Max size configuration, to avoid DOS attacks? OutOfMemory
|
||||||
|
|
||||||
// Size parameters
|
// Size parameters
|
||||||
int width = ServletUtil.getIntParameter(pRequest, sizeWidthParam, -1);
|
int width = ServletUtil.getIntParameter(pRequest, sizeWidthParam, -1);
|
||||||
int height = ServletUtil.getIntParameter(pRequest, sizeHeightParam, -1);
|
int height = ServletUtil.getIntParameter(pRequest, sizeHeightParam, -1);
|
||||||
if (width > 0 || height > 0) {
|
if (width > 0 || height > 0) {
|
||||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE, new Dimension(width, height));
|
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE, new Dimension(width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size uniform/percent
|
// Size uniform/percent
|
||||||
boolean uniform = ServletUtil.getBooleanParameter(pRequest, sizeUniformParam, true);
|
boolean uniform = ServletUtil.getBooleanParameter(pRequest, sizeUniformParam, true);
|
||||||
if (!uniform) {
|
if (!uniform) {
|
||||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.FALSE);
|
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.FALSE);
|
||||||
}
|
}
|
||||||
boolean percent = ServletUtil.getBooleanParameter(pRequest, sizePercentParam, false);
|
boolean percent = ServletUtil.getBooleanParameter(pRequest, sizePercentParam, false);
|
||||||
if (percent) {
|
if (percent) {
|
||||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
|
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Area of interest parameters
|
// Area of interest parameters
|
||||||
int x = ServletUtil.getIntParameter(pRequest, regionLeftParam, -1); // Default is center
|
int x = ServletUtil.getIntParameter(pRequest, regionLeftParam, -1); // Default is center
|
||||||
int y = ServletUtil.getIntParameter(pRequest, regionTopParam, -1); // Default is center
|
int y = ServletUtil.getIntParameter(pRequest, regionTopParam, -1); // Default is center
|
||||||
width = ServletUtil.getIntParameter(pRequest, regionWidthParam, -1);
|
width = ServletUtil.getIntParameter(pRequest, regionWidthParam, -1);
|
||||||
height = ServletUtil.getIntParameter(pRequest, regionHeightParam, -1);
|
height = ServletUtil.getIntParameter(pRequest, regionHeightParam, -1);
|
||||||
if (width > 0 || height > 0) {
|
if (width > 0 || height > 0) {
|
||||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_AOI, new Rectangle(x, y, width, height));
|
pRequest.setAttribute(ImageServletResponse.ATTRIB_AOI, new Rectangle(x, y, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
// AOI uniform/percent
|
// AOI uniform/percent
|
||||||
uniform = ServletUtil.getBooleanParameter(pRequest, regionUniformParam, false);
|
uniform = ServletUtil.getBooleanParameter(pRequest, regionUniformParam, false);
|
||||||
if (uniform) {
|
if (uniform) {
|
||||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.TRUE);
|
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_UNIFORM, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
percent = ServletUtil.getBooleanParameter(pRequest, regionPercentParam, false);
|
percent = ServletUtil.getBooleanParameter(pRequest, regionPercentParam, false);
|
||||||
if (percent) {
|
if (percent) {
|
||||||
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
|
pRequest.setAttribute(ImageServletResponse.ATTRIB_SIZE_PERCENT, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.doFilterImpl(pRequest, pResponse, pChain);
|
super.doFilterImpl(pRequest, pResponse, pChain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This implementation does no filtering, and simply returns the image
|
* This implementation does no filtering, and simply returns the image
|
||||||
* passed in.
|
* passed in.
|
||||||
*
|
*
|
||||||
* @param pImage
|
* @param pImage
|
||||||
* @param pRequest
|
* @param pRequest
|
||||||
* @param pResponse
|
* @param pResponse
|
||||||
* @return {@code pImage}
|
* @return {@code pImage}
|
||||||
*/
|
*/
|
||||||
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
protected RenderedImage doFilter(BufferedImage pImage, ServletRequest pRequest, ImageServletResponse pResponse) {
|
||||||
return pImage;
|
return pImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,33 +1,33 @@
|
|||||||
/**
|
/**
|
||||||
* Contains various image-outputting filters, that should run under any
|
* Contains various image-outputting filters, that should run under any
|
||||||
* servlet engine.
|
* servlet engine.
|
||||||
* <P>
|
* <P>
|
||||||
* Some of these methods may require use of the native graphics libraries
|
* Some of these methods may require use of the native graphics libraries
|
||||||
* supported by the JVM, like the X libraries on Unix systems, and should be
|
* supported by the JVM, like the X libraries on Unix systems, and should be
|
||||||
* run with JRE <STRONG>1.4</STRONG> or later, and with the option:
|
* run with JRE <STRONG>1.4</STRONG> or later, and with the option:
|
||||||
* <DL>
|
* <DL>
|
||||||
* <DD>{@code -Djawa.awt.headless=true}</DD>
|
* <DD>{@code -Djawa.awt.headless=true}</DD>
|
||||||
* </DL>
|
* </DL>
|
||||||
* See the document
|
* See the document
|
||||||
* <A href="http://java.sun.com/j2se/1.4/docs/guide/awt/AWTChanges.html#headless">AWT Enhancements</A> and bugtraq report
|
* <A href="http://java.sun.com/j2se/1.4/docs/guide/awt/AWTChanges.html#headless">AWT Enhancements</A> and bugtraq report
|
||||||
* <A href="http://developer.java.sun.com/developer/bugParade/bugs/4281163.html">4281163</A> for more information on this issue.
|
* <A href="http://developer.java.sun.com/developer/bugParade/bugs/4281163.html">4281163</A> for more information on this issue.
|
||||||
* <P>
|
* <P>
|
||||||
* If you cannot use JRE 1.4 or later, or do not want to use the X
|
* If you cannot use JRE 1.4 or later, or do not want to use the X
|
||||||
* libraries, one possibility is to use the
|
* libraries, one possibility is to use the
|
||||||
* <A href="http://www.eteks.com/pja/en/">PJA package</A> (com.eteks.pja),
|
* <A href="http://www.eteks.com/pja/en/">PJA package</A> (com.eteks.pja),
|
||||||
* and start the JVM with the following options:
|
* and start the JVM with the following options:
|
||||||
* <DL>
|
* <DL>
|
||||||
* <DD>{@code -Xbootclasspath/a:<path to pja.jar>}</DD>
|
* <DD>{@code -Xbootclasspath/a:<path to pja.jar>}</DD>
|
||||||
* <DD>{@code -Dawt.toolkit=com.eteks.awt.PJAToolkit}</DD>
|
* <DD>{@code -Dawt.toolkit=com.eteks.awt.PJAToolkit}</DD>
|
||||||
* <DD>{@code -Djava.awt.graphicsenv=com.eteks.java2d.PJAGraphicsEnvironment}</DD>
|
* <DD>{@code -Djava.awt.graphicsenv=com.eteks.java2d.PJAGraphicsEnvironment}</DD>
|
||||||
* <DD>{@code -Djava.awt.fonts=<path where True Type fonts files will be loaded from>}</DD>
|
* <DD>{@code -Djava.awt.fonts=<path where True Type fonts files will be loaded from>}</DD>
|
||||||
* </DL>
|
* </DL>
|
||||||
* <P>
|
* <P>
|
||||||
* Please note that creation of PNG images (from bytes or URL's) are only
|
* Please note that creation of PNG images (from bytes or URL's) are only
|
||||||
* supported in JRE 1.3 and later, trying to load them from an earlier version,
|
* supported in JRE 1.3 and later, trying to load them from an earlier version,
|
||||||
* will result in errors.
|
* will result in errors.
|
||||||
*
|
*
|
||||||
* @see com.twelvemonkeys.servlet.image.ImageServlet
|
* @see com.twelvemonkeys.servlet.image.ImageServlet
|
||||||
* @see com.twelvemonkeys.servlet.image.ImagePainterServlet
|
* @see com.twelvemonkeys.servlet.image.ImagePainterServlet
|
||||||
*/
|
*/
|
||||||
package com.twelvemonkeys.servlet.image;
|
package com.twelvemonkeys.servlet.image;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* Contains servlet support classes.
|
* Contains servlet support classes.
|
||||||
*/
|
*/
|
||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|||||||
@@ -1,438 +1,438 @@
|
|||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FilterAbstractTestCase
|
* FilterAbstractTestCase
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/FilterAbstractTestCase.java#1 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/FilterAbstractTestCase.java#1 $
|
||||||
*/
|
*/
|
||||||
public abstract class FilterAbstractTestCase extends ObjectAbstractTestCase {
|
public abstract class FilterAbstractTestCase extends ObjectAbstractTestCase {
|
||||||
protected Object makeObject() {
|
protected Object makeObject() {
|
||||||
return makeFilter();
|
return makeFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Filter makeFilter();
|
protected abstract Filter makeFilter();
|
||||||
|
|
||||||
// TODO: Is it a good thing to have an API like this?
|
// TODO: Is it a good thing to have an API like this?
|
||||||
protected FilterConfig makeFilterConfig() {
|
protected FilterConfig makeFilterConfig() {
|
||||||
return makeFilterConfig(new HashMap());
|
return makeFilterConfig(new HashMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FilterConfig makeFilterConfig(Map pParams) {
|
protected FilterConfig makeFilterConfig(Map pParams) {
|
||||||
return new MockFilterConfig(pParams);
|
return new MockFilterConfig(pParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ServletRequest makeRequest() {
|
protected ServletRequest makeRequest() {
|
||||||
return new MockServletRequest();
|
return new MockServletRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ServletResponse makeResponse() {
|
protected ServletResponse makeResponse() {
|
||||||
return new MockServletResponse();
|
return new MockServletResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FilterChain makeFilterChain() {
|
protected FilterChain makeFilterChain() {
|
||||||
return new MockFilterChain();
|
return new MockFilterChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitNull() {
|
public void testInitNull() {
|
||||||
Filter filter = makeFilter();
|
Filter filter = makeFilter();
|
||||||
|
|
||||||
// The spec seems to be a little unclear on this issue, but anyway,
|
// The spec seems to be a little unclear on this issue, but anyway,
|
||||||
// the container should never invoke init(null)...
|
// the container should never invoke init(null)...
|
||||||
try {
|
try {
|
||||||
filter.init(null);
|
filter.init(null);
|
||||||
fail("Should throw Exception on init(null)");
|
fail("Should throw Exception on init(null)");
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
// Good
|
// Good
|
||||||
}
|
}
|
||||||
catch (NullPointerException e) {
|
catch (NullPointerException e) {
|
||||||
// Bad (but not unreasonable)
|
// Bad (but not unreasonable)
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
// Hmmm.. The jury is still out.
|
// Hmmm.. The jury is still out.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInit() {
|
public void testInit() {
|
||||||
Filter filter = makeFilter();
|
Filter filter = makeFilter();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig());
|
filter.init(makeFilterConfig());
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
assertNotNull(e.getMessage());
|
assertNotNull(e.getMessage());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLifeCycle() throws ServletException {
|
public void testLifeCycle() throws ServletException {
|
||||||
Filter filter = makeFilter();
|
Filter filter = makeFilter();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig());
|
filter.init(makeFilterConfig());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterBasic() throws ServletException, IOException {
|
public void testFilterBasic() throws ServletException, IOException {
|
||||||
Filter filter = makeFilter();
|
Filter filter = makeFilter();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig());
|
filter.init(makeFilterConfig());
|
||||||
|
|
||||||
filter.doFilter(makeRequest(), makeResponse(), makeFilterChain());
|
filter.doFilter(makeRequest(), makeResponse(), makeFilterChain());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDestroy() {
|
public void testDestroy() {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MockFilterConfig implements FilterConfig {
|
static class MockFilterConfig implements FilterConfig {
|
||||||
private final Map<String, String> params;
|
private final Map<String, String> params;
|
||||||
|
|
||||||
MockFilterConfig(Map<String, String> pParams) {
|
MockFilterConfig(Map<String, String> pParams) {
|
||||||
if (pParams == null) {
|
if (pParams == null) {
|
||||||
throw new IllegalArgumentException("params == null");
|
throw new IllegalArgumentException("params == null");
|
||||||
}
|
}
|
||||||
params = pParams;
|
params = pParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFilterName() {
|
public String getFilterName() {
|
||||||
return "mock-filter";
|
return "mock-filter";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInitParameter(String pName) {
|
public String getInitParameter(String pName) {
|
||||||
return params.get(pName);
|
return params.get(pName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getInitParameterNames() {
|
public Enumeration getInitParameterNames() {
|
||||||
return Collections.enumeration(params.keySet());
|
return Collections.enumeration(params.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletContext getServletContext() {
|
public ServletContext getServletContext() {
|
||||||
return new MockServletContext();
|
return new MockServletContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MockServletContext implements ServletContext {
|
private static class MockServletContext implements ServletContext {
|
||||||
private final Map<String, Object> attributes;
|
private final Map<String, Object> attributes;
|
||||||
private final Map<String, String> params;
|
private final Map<String, String> params;
|
||||||
|
|
||||||
MockServletContext() {
|
MockServletContext() {
|
||||||
attributes = new HashMap<String, Object>();
|
attributes = new HashMap<String, Object>();
|
||||||
params = new HashMap<String, String>();
|
params = new HashMap<String, String>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getAttribute(String s) {
|
public Object getAttribute(String s) {
|
||||||
return attributes.get(s);
|
return attributes.get(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getAttributeNames() {
|
public Enumeration getAttributeNames() {
|
||||||
return Collections.enumeration(attributes.keySet());
|
return Collections.enumeration(attributes.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletContext getContext(String s) {
|
public ServletContext getContext(String s) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInitParameter(String s) {
|
public String getInitParameter(String s) {
|
||||||
return (String) params.get(s);
|
return (String) params.get(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getInitParameterNames() {
|
public Enumeration getInitParameterNames() {
|
||||||
return Collections.enumeration(params.keySet());
|
return Collections.enumeration(params.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMajorVersion() {
|
public int getMajorVersion() {
|
||||||
return 0; // TODO: Implement
|
return 0; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMimeType(String s) {
|
public String getMimeType(String s) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinorVersion() {
|
public int getMinorVersion() {
|
||||||
return 0; // TODO: Implement
|
return 0; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestDispatcher getNamedDispatcher(String s) {
|
public RequestDispatcher getNamedDispatcher(String s) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealPath(String s) {
|
public String getRealPath(String s) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestDispatcher getRequestDispatcher(String s) {
|
public RequestDispatcher getRequestDispatcher(String s) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public URL getResource(String s) throws MalformedURLException {
|
public URL getResource(String s) throws MalformedURLException {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getResourceAsStream(String s) {
|
public InputStream getResourceAsStream(String s) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set getResourcePaths(String s) {
|
public Set getResourcePaths(String s) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServerInfo() {
|
public String getServerInfo() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public Servlet getServlet(String s) throws ServletException {
|
public Servlet getServlet(String s) throws ServletException {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServletContextName() {
|
public String getServletContextName() {
|
||||||
return "mock";
|
return "mock";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getServletNames() {
|
public Enumeration getServletNames() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getServlets() {
|
public Enumeration getServlets() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(Exception exception, String s) {
|
public void log(Exception exception, String s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String s) {
|
public void log(String s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String s, Throwable throwable) {
|
public void log(String s, Throwable throwable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAttribute(String s) {
|
public void removeAttribute(String s) {
|
||||||
attributes.remove(s);
|
attributes.remove(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(String s, Object obj) {
|
public void setAttribute(String s, Object obj) {
|
||||||
attributes.put(s, obj);
|
attributes.put(s, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MockServletRequest implements ServletRequest {
|
static class MockServletRequest implements ServletRequest {
|
||||||
final private Map<String, Object> attributes;
|
final private Map<String, Object> attributes;
|
||||||
|
|
||||||
public MockServletRequest() {
|
public MockServletRequest() {
|
||||||
attributes = new HashMap<String, Object>();
|
attributes = new HashMap<String, Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getAttribute(String pKey) {
|
public Object getAttribute(String pKey) {
|
||||||
return attributes.get(pKey);
|
return attributes.get(pKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getAttributeNames() {
|
public Enumeration getAttributeNames() {
|
||||||
return Collections.enumeration(attributes.keySet());
|
return Collections.enumeration(attributes.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCharacterEncoding() {
|
public String getCharacterEncoding() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCharacterEncoding(String pMessage) throws UnsupportedEncodingException {
|
public void setCharacterEncoding(String pMessage) throws UnsupportedEncodingException {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getContentLength() {
|
public int getContentLength() {
|
||||||
return 0; // TODO: Implement
|
return 0; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContentType() {
|
public String getContentType() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletInputStream getInputStream() throws IOException {
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParameter(String pMessage) {
|
public String getParameter(String pMessage) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getParameterNames() {
|
public Enumeration getParameterNames() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getParameterValues(String pMessage) {
|
public String[] getParameterValues(String pMessage) {
|
||||||
return new String[0]; // TODO: Implement
|
return new String[0]; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map getParameterMap() {
|
public Map getParameterMap() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getProtocol() {
|
public String getProtocol() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getScheme() {
|
public String getScheme() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServerName() {
|
public String getServerName() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getServerPort() {
|
public int getServerPort() {
|
||||||
return 0; // TODO: Implement
|
return 0; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferedReader getReader() throws IOException {
|
public BufferedReader getReader() throws IOException {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRemoteAddr() {
|
public String getRemoteAddr() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRemoteHost() {
|
public String getRemoteHost() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(String pKey, Object pValue) {
|
public void setAttribute(String pKey, Object pValue) {
|
||||||
attributes.put(pKey, pValue);
|
attributes.put(pKey, pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAttribute(String pKey) {
|
public void removeAttribute(String pKey) {
|
||||||
attributes.remove(pKey);
|
attributes.remove(pKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Locale getLocale() {
|
public Locale getLocale() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getLocales() {
|
public Enumeration getLocales() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSecure() {
|
public boolean isSecure() {
|
||||||
return false; // TODO: Implement
|
return false; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestDispatcher getRequestDispatcher(String pMessage) {
|
public RequestDispatcher getRequestDispatcher(String pMessage) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealPath(String pMessage) {
|
public String getRealPath(String pMessage) {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRemotePort() {
|
public int getRemotePort() {
|
||||||
throw new UnsupportedOperationException("Method getRemotePort not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method getRemotePort not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLocalName() {
|
public String getLocalName() {
|
||||||
throw new UnsupportedOperationException("Method getLocalName not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method getLocalName not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLocalAddr() {
|
public String getLocalAddr() {
|
||||||
throw new UnsupportedOperationException("Method getLocalAddr not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method getLocalAddr not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLocalPort() {
|
public int getLocalPort() {
|
||||||
throw new UnsupportedOperationException("Method getLocalPort not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method getLocalPort not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MockServletResponse implements ServletResponse {
|
static class MockServletResponse implements ServletResponse {
|
||||||
public void flushBuffer() throws IOException {
|
public void flushBuffer() throws IOException {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBufferSize() {
|
public int getBufferSize() {
|
||||||
return 0; // TODO: Implement
|
return 0; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCharacterEncoding() {
|
public String getCharacterEncoding() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContentType() {
|
public String getContentType() {
|
||||||
throw new UnsupportedOperationException("Method getContentType not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method getContentType not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public Locale getLocale() {
|
public Locale getLocale() {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletOutputStream getOutputStream() throws IOException {
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrintWriter getWriter() throws IOException {
|
public PrintWriter getWriter() throws IOException {
|
||||||
return null; // TODO: Implement
|
return null; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCharacterEncoding(String charset) {
|
public void setCharacterEncoding(String charset) {
|
||||||
throw new UnsupportedOperationException("Method setCharacterEncoding not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method setCharacterEncoding not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCommitted() {
|
public boolean isCommitted() {
|
||||||
return false; // TODO: Implement
|
return false; // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetBuffer() {
|
public void resetBuffer() {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBufferSize(int pLength) {
|
public void setBufferSize(int pLength) {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContentLength(int pLength) {
|
public void setContentLength(int pLength) {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContentType(String pMessage) {
|
public void setContentType(String pMessage) {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLocale(Locale pLocale) {
|
public void setLocale(Locale pLocale) {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MockFilterChain implements FilterChain {
|
static class MockFilterChain implements FilterChain {
|
||||||
public void doFilter(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
public void doFilter(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,157 +1,157 @@
|
|||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GenericFilterTestCase
|
* GenericFilterTestCase
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/GenericFilterTestCase.java#1 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/GenericFilterTestCase.java#1 $
|
||||||
*/
|
*/
|
||||||
public final class GenericFilterTestCase extends FilterAbstractTestCase {
|
public final class GenericFilterTestCase extends FilterAbstractTestCase {
|
||||||
protected Filter makeFilter() {
|
protected Filter makeFilter() {
|
||||||
return new GenericFilterImpl();
|
return new GenericFilterImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitOncePerRequest() {
|
public void testInitOncePerRequest() {
|
||||||
// Default FALSE
|
// Default FALSE
|
||||||
GenericFilter filter = new GenericFilterImpl();
|
GenericFilter filter = new GenericFilterImpl();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig());
|
filter.init(makeFilterConfig());
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertFalse("OncePerRequest should default to false", filter.oncePerRequest);
|
assertFalse("OncePerRequest should default to false", filter.oncePerRequest);
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
|
|
||||||
// TRUE
|
// TRUE
|
||||||
filter = new GenericFilterImpl();
|
filter = new GenericFilterImpl();
|
||||||
Map<String, String> params = new HashMap<String, String>();
|
Map<String, String> params = new HashMap<String, String>();
|
||||||
params.put("once-per-request", "true");
|
params.put("once-per-request", "true");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig(params));
|
filter.init(makeFilterConfig(params));
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue("oncePerRequest should be true", filter.oncePerRequest);
|
assertTrue("oncePerRequest should be true", filter.oncePerRequest);
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
|
|
||||||
// TRUE
|
// TRUE
|
||||||
filter = new GenericFilterImpl();
|
filter = new GenericFilterImpl();
|
||||||
params = new HashMap<String, String>();
|
params = new HashMap<String, String>();
|
||||||
params.put("oncePerRequest", "true");
|
params.put("oncePerRequest", "true");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig(params));
|
filter.init(makeFilterConfig(params));
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue("oncePerRequest should be true", filter.oncePerRequest);
|
assertTrue("oncePerRequest should be true", filter.oncePerRequest);
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterOnlyOnce() {
|
public void testFilterOnlyOnce() {
|
||||||
final GenericFilterImpl filter = new GenericFilterImpl();
|
final GenericFilterImpl filter = new GenericFilterImpl();
|
||||||
filter.setOncePerRequest(true);
|
filter.setOncePerRequest(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig());
|
filter.init(makeFilterConfig());
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterChain chain = new MyFilterChain(new Filter[] {filter, filter, filter});
|
FilterChain chain = new MyFilterChain(new Filter[] {filter, filter, filter});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
chain.doFilter(makeRequest(), makeResponse());
|
chain.doFilter(makeRequest(), makeResponse());
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals("Filter was invoked more than once!", 1, filter.invocationCount);
|
assertEquals("Filter was invoked more than once!", 1, filter.invocationCount);
|
||||||
|
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterMultiple() {
|
public void testFilterMultiple() {
|
||||||
final GenericFilterImpl filter = new GenericFilterImpl();
|
final GenericFilterImpl filter = new GenericFilterImpl();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.init(makeFilterConfig());
|
filter.init(makeFilterConfig());
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterChain chain = new MyFilterChain(new Filter[] {
|
FilterChain chain = new MyFilterChain(new Filter[] {
|
||||||
filter, filter, filter, filter, filter
|
filter, filter, filter, filter, filter
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
chain.doFilter(makeRequest(), makeResponse());
|
chain.doFilter(makeRequest(), makeResponse());
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
catch (ServletException e) {
|
catch (ServletException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals("Filter was invoked not invoked five times!", 5, filter.invocationCount);
|
assertEquals("Filter was invoked not invoked five times!", 5, filter.invocationCount);
|
||||||
|
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GenericFilterImpl extends GenericFilter {
|
private static class GenericFilterImpl extends GenericFilter {
|
||||||
int invocationCount;
|
int invocationCount;
|
||||||
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
protected void doFilterImpl(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
|
||||||
invocationCount++;
|
invocationCount++;
|
||||||
pChain.doFilter(pRequest, pResponse);
|
pChain.doFilter(pRequest, pResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MyFilterChain implements FilterChain {
|
private static class MyFilterChain implements FilterChain {
|
||||||
|
|
||||||
Filter[] mFilters;
|
Filter[] mFilters;
|
||||||
int mCurrentFilter;
|
int mCurrentFilter;
|
||||||
|
|
||||||
public MyFilterChain(Filter[] pFilters) {
|
public MyFilterChain(Filter[] pFilters) {
|
||||||
if (pFilters == null) {
|
if (pFilters == null) {
|
||||||
throw new IllegalArgumentException("filters == null");
|
throw new IllegalArgumentException("filters == null");
|
||||||
}
|
}
|
||||||
mFilters = pFilters;
|
mFilters = pFilters;
|
||||||
mCurrentFilter = 0;
|
mCurrentFilter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doFilter(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
public void doFilter(ServletRequest pRequest, ServletResponse pResponse) throws IOException, ServletException {
|
||||||
if (mCurrentFilter < mFilters.length) {
|
if (mCurrentFilter < mFilters.length) {
|
||||||
mFilters[mCurrentFilter++].doFilter(pRequest, pResponse, this);
|
mFilters[mCurrentFilter++].doFilter(pRequest, pResponse, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+199
-199
@@ -1,199 +1,199 @@
|
|||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.util.MapAbstractTestCase;
|
import com.twelvemonkeys.util.MapAbstractTestCase;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Suite;
|
import org.junit.runners.Suite;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServletConfigMapAdapterTestCase
|
* ServletConfigMapAdapterTestCase
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTestCase.java#3 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfigMapAdapterTestCase.java#3 $
|
||||||
*/
|
*/
|
||||||
@RunWith(Suite.class)
|
@RunWith(Suite.class)
|
||||||
@Suite.SuiteClasses({AbstractServletConfigMapAdapterTest.ServletConfigMapTest.class, AbstractServletConfigMapAdapterTest.FilterConfigMapTest.class, AbstractServletConfigMapAdapterTest.ServletContextMapTest.class})
|
@Suite.SuiteClasses({AbstractServletConfigMapAdapterTest.ServletConfigMapTest.class, AbstractServletConfigMapAdapterTest.FilterConfigMapTest.class, AbstractServletConfigMapAdapterTest.ServletContextMapTest.class})
|
||||||
public final class ServletConfigMapAdapterTest {
|
public final class ServletConfigMapAdapterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractServletConfigMapAdapterTest extends MapAbstractTestCase {
|
abstract class AbstractServletConfigMapAdapterTest extends MapAbstractTestCase {
|
||||||
|
|
||||||
public boolean isPutAddSupported() {
|
public boolean isPutAddSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPutChangeSupported() {
|
public boolean isPutChangeSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRemoveSupported() {
|
public boolean isRemoveSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSetValueSupported() {
|
public boolean isSetValueSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestConfig implements ServletConfig, FilterConfig, ServletContext, Serializable, Cloneable {
|
private static class TestConfig implements ServletConfig, FilterConfig, ServletContext, Serializable, Cloneable {
|
||||||
Map map = new HashMap();
|
Map map = new HashMap();
|
||||||
|
|
||||||
public String getServletName() {
|
public String getServletName() {
|
||||||
return "dummy"; // Not needed for this test
|
return "dummy"; // Not needed for this test
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFilterName() {
|
public String getFilterName() {
|
||||||
return getServletName();
|
return getServletName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServletContextName() {
|
public String getServletContextName() {
|
||||||
return getServletName();
|
return getServletName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ServletContext getServletContext() {
|
public ServletContext getServletContext() {
|
||||||
throw new UnsupportedOperationException("Method getSerlvetContext not implemented");
|
throw new UnsupportedOperationException("Method getSerlvetContext not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInitParameter(String s) {
|
public String getInitParameter(String s) {
|
||||||
return (String) map.get(s);
|
return (String) map.get(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getInitParameterNames() {
|
public Enumeration getInitParameterNames() {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return Collections.enumeration(map.keySet());
|
return Collections.enumeration(map.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServletContext getContext(String uripath) {
|
public ServletContext getContext(String uripath) {
|
||||||
throw new UnsupportedOperationException("Method getContext not implemented");
|
throw new UnsupportedOperationException("Method getContext not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMajorVersion() {
|
public int getMajorVersion() {
|
||||||
throw new UnsupportedOperationException("Method getMajorVersion not implemented");
|
throw new UnsupportedOperationException("Method getMajorVersion not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinorVersion() {
|
public int getMinorVersion() {
|
||||||
throw new UnsupportedOperationException("Method getMinorVersion not implemented");
|
throw new UnsupportedOperationException("Method getMinorVersion not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMimeType(String file) {
|
public String getMimeType(String file) {
|
||||||
throw new UnsupportedOperationException("Method getMimeType not implemented");
|
throw new UnsupportedOperationException("Method getMimeType not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set getResourcePaths(String path) {
|
public Set getResourcePaths(String path) {
|
||||||
throw new UnsupportedOperationException("Method getResourcePaths not implemented");
|
throw new UnsupportedOperationException("Method getResourcePaths not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public URL getResource(String path) throws MalformedURLException {
|
public URL getResource(String path) throws MalformedURLException {
|
||||||
throw new UnsupportedOperationException("Method getResource not implemented");
|
throw new UnsupportedOperationException("Method getResource not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getResourceAsStream(String path) {
|
public InputStream getResourceAsStream(String path) {
|
||||||
throw new UnsupportedOperationException("Method getResourceAsStream not implemented");
|
throw new UnsupportedOperationException("Method getResourceAsStream not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestDispatcher getRequestDispatcher(String path) {
|
public RequestDispatcher getRequestDispatcher(String path) {
|
||||||
throw new UnsupportedOperationException("Method getRequestDispatcher not implemented");
|
throw new UnsupportedOperationException("Method getRequestDispatcher not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestDispatcher getNamedDispatcher(String name) {
|
public RequestDispatcher getNamedDispatcher(String name) {
|
||||||
throw new UnsupportedOperationException("Method getNamedDispatcher not implemented");
|
throw new UnsupportedOperationException("Method getNamedDispatcher not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Servlet getServlet(String name) throws ServletException {
|
public Servlet getServlet(String name) throws ServletException {
|
||||||
throw new UnsupportedOperationException("Method getServlet not implemented");
|
throw new UnsupportedOperationException("Method getServlet not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getServlets() {
|
public Enumeration getServlets() {
|
||||||
throw new UnsupportedOperationException("Method getServlets not implemented");
|
throw new UnsupportedOperationException("Method getServlets not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getServletNames() {
|
public Enumeration getServletNames() {
|
||||||
throw new UnsupportedOperationException("Method getServletNames not implemented");
|
throw new UnsupportedOperationException("Method getServletNames not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String msg) {
|
public void log(String msg) {
|
||||||
throw new UnsupportedOperationException("Method log not implemented");
|
throw new UnsupportedOperationException("Method log not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(Exception exception, String msg) {
|
public void log(Exception exception, String msg) {
|
||||||
throw new UnsupportedOperationException("Method log not implemented");
|
throw new UnsupportedOperationException("Method log not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String message, Throwable throwable) {
|
public void log(String message, Throwable throwable) {
|
||||||
throw new UnsupportedOperationException("Method log not implemented");
|
throw new UnsupportedOperationException("Method log not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealPath(String path) {
|
public String getRealPath(String path) {
|
||||||
throw new UnsupportedOperationException("Method getRealPath not implemented");
|
throw new UnsupportedOperationException("Method getRealPath not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServerInfo() {
|
public String getServerInfo() {
|
||||||
throw new UnsupportedOperationException("Method getServerInfo not implemented");
|
throw new UnsupportedOperationException("Method getServerInfo not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getAttribute(String name) {
|
public Object getAttribute(String name) {
|
||||||
throw new UnsupportedOperationException("Method getAttribute not implemented");
|
throw new UnsupportedOperationException("Method getAttribute not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration getAttributeNames() {
|
public Enumeration getAttributeNames() {
|
||||||
throw new UnsupportedOperationException("Method getAttributeNames not implemented");
|
throw new UnsupportedOperationException("Method getAttributeNames not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(String name, Object object) {
|
public void setAttribute(String name, Object object) {
|
||||||
throw new UnsupportedOperationException("Method setAttribute not implemented");
|
throw new UnsupportedOperationException("Method setAttribute not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAttribute(String name) {
|
public void removeAttribute(String name) {
|
||||||
throw new UnsupportedOperationException("Method removeAttribute not implemented");
|
throw new UnsupportedOperationException("Method removeAttribute not implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class ServletConfigMapTest extends AbstractServletConfigMapAdapterTest {
|
public static final class ServletConfigMapTest extends AbstractServletConfigMapAdapterTest {
|
||||||
|
|
||||||
public Map makeEmptyMap() {
|
public Map makeEmptyMap() {
|
||||||
ServletConfig config = new TestConfig();
|
ServletConfig config = new TestConfig();
|
||||||
return new ServletConfigMapAdapter(config);
|
return new ServletConfigMapAdapter(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map makeFullMap() {
|
public Map makeFullMap() {
|
||||||
ServletConfig config = new TestConfig();
|
ServletConfig config = new TestConfig();
|
||||||
addSampleMappings(((TestConfig) config).map);
|
addSampleMappings(((TestConfig) config).map);
|
||||||
return new ServletConfigMapAdapter(config);
|
return new ServletConfigMapAdapter(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class FilterConfigMapTest extends AbstractServletConfigMapAdapterTest {
|
public static final class FilterConfigMapTest extends AbstractServletConfigMapAdapterTest {
|
||||||
|
|
||||||
public Map makeEmptyMap() {
|
public Map makeEmptyMap() {
|
||||||
FilterConfig config = new TestConfig();
|
FilterConfig config = new TestConfig();
|
||||||
return new ServletConfigMapAdapter(config);
|
return new ServletConfigMapAdapter(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map makeFullMap() {
|
public Map makeFullMap() {
|
||||||
FilterConfig config = new TestConfig();
|
FilterConfig config = new TestConfig();
|
||||||
addSampleMappings(((TestConfig) config).map);
|
addSampleMappings(((TestConfig) config).map);
|
||||||
return new ServletConfigMapAdapter(config);
|
return new ServletConfigMapAdapter(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class ServletContextMapTest extends AbstractServletConfigMapAdapterTest {
|
public static final class ServletContextMapTest extends AbstractServletConfigMapAdapterTest {
|
||||||
|
|
||||||
public Map makeEmptyMap() {
|
public Map makeEmptyMap() {
|
||||||
ServletContext config = new TestConfig();
|
ServletContext config = new TestConfig();
|
||||||
return new ServletConfigMapAdapter(config);
|
return new ServletConfigMapAdapter(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map makeFullMap() {
|
public Map makeFullMap() {
|
||||||
FilterConfig config = new TestConfig();
|
FilterConfig config = new TestConfig();
|
||||||
addSampleMappings(((TestConfig) config).map);
|
addSampleMappings(((TestConfig) config).map);
|
||||||
return new ServletConfigMapAdapter(config);
|
return new ServletConfigMapAdapter(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,95 +1,95 @@
|
|||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.util.MapAbstractTestCase;
|
import com.twelvemonkeys.util.MapAbstractTestCase;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServletConfigMapAdapterTestCase
|
* ServletConfigMapAdapterTestCase
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: ServletHeadersMapAdapterTestCase.java#1 $
|
* @version $Id: ServletHeadersMapAdapterTestCase.java#1 $
|
||||||
*/
|
*/
|
||||||
public class ServletHeadersMapAdapterTest extends MapAbstractTestCase {
|
public class ServletHeadersMapAdapterTest extends MapAbstractTestCase {
|
||||||
private static final List<String> HEADER_VALUE_ETAG = Arrays.asList("\"1234567890abcdef\"");
|
private static final List<String> HEADER_VALUE_ETAG = Arrays.asList("\"1234567890abcdef\"");
|
||||||
private static final List<String> HEADER_VALUE_DATE = Arrays.asList(new Date().toString());
|
private static final List<String> HEADER_VALUE_DATE = Arrays.asList(new Date().toString());
|
||||||
private static final List<String> HEADER_VALUE_FOO = Arrays.asList("one", "two");
|
private static final List<String> HEADER_VALUE_FOO = Arrays.asList("one", "two");
|
||||||
|
|
||||||
public boolean isPutAddSupported() {
|
public boolean isPutAddSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPutChangeSupported() {
|
public boolean isPutChangeSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRemoveSupported() {
|
public boolean isRemoveSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSetValueSupported() {
|
public boolean isSetValueSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTestSerialization() {
|
public boolean isTestSerialization() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map makeEmptyMap() {
|
public Map makeEmptyMap() {
|
||||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
when(request.getHeaderNames()).thenAnswer(returnEnumeration(Collections.emptyList()));
|
when(request.getHeaderNames()).thenAnswer(returnEnumeration(Collections.emptyList()));
|
||||||
|
|
||||||
return new ServletHeadersMapAdapter(request);
|
return new ServletHeadersMapAdapter(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map makeFullMap() {
|
public Map makeFullMap() {
|
||||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
when(request.getHeaderNames()).thenAnswer(returnEnumeration(Arrays.asList(getSampleKeys())));
|
when(request.getHeaderNames()).thenAnswer(returnEnumeration(Arrays.asList(getSampleKeys())));
|
||||||
when(request.getHeaders("Date")).thenAnswer(returnEnumeration(HEADER_VALUE_DATE));
|
when(request.getHeaders("Date")).thenAnswer(returnEnumeration(HEADER_VALUE_DATE));
|
||||||
when(request.getHeaders("ETag")).thenAnswer(returnEnumeration(HEADER_VALUE_ETAG));
|
when(request.getHeaders("ETag")).thenAnswer(returnEnumeration(HEADER_VALUE_ETAG));
|
||||||
when(request.getHeaders("X-Foo")).thenAnswer(returnEnumeration(HEADER_VALUE_FOO));
|
when(request.getHeaders("X-Foo")).thenAnswer(returnEnumeration(HEADER_VALUE_FOO));
|
||||||
|
|
||||||
return new ServletHeadersMapAdapter(request);
|
return new ServletHeadersMapAdapter(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getSampleKeys() {
|
public Object[] getSampleKeys() {
|
||||||
return new String[] {"Date", "ETag", "X-Foo"};
|
return new String[] {"Date", "ETag", "X-Foo"};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getSampleValues() {
|
public Object[] getSampleValues() {
|
||||||
return new Object[] {HEADER_VALUE_DATE, HEADER_VALUE_ETAG, HEADER_VALUE_FOO};
|
return new Object[] {HEADER_VALUE_DATE, HEADER_VALUE_ETAG, HEADER_VALUE_FOO};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getNewSampleValues() {
|
public Object[] getNewSampleValues() {
|
||||||
// Needs to be same length but different values
|
// Needs to be same length but different values
|
||||||
return new Object[3];
|
return new Object[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static <T> ReturnNewEnumeration<T> returnEnumeration(final Collection<T> collection) {
|
protected static <T> ReturnNewEnumeration<T> returnEnumeration(final Collection<T> collection) {
|
||||||
return new ReturnNewEnumeration<T>(collection);
|
return new ReturnNewEnumeration<T>(collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ReturnNewEnumeration<T> implements Answer<Enumeration<T>> {
|
private static class ReturnNewEnumeration<T> implements Answer<Enumeration<T>> {
|
||||||
private final Collection<T> collection;
|
private final Collection<T> collection;
|
||||||
|
|
||||||
private ReturnNewEnumeration(final Collection<T> collection) {
|
private ReturnNewEnumeration(final Collection<T> collection) {
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration<T> answer(InvocationOnMock invocation) throws Throwable {
|
public Enumeration<T> answer(InvocationOnMock invocation) throws Throwable {
|
||||||
return Collections.enumeration(collection);
|
return Collections.enumeration(collection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+96
-96
@@ -1,96 +1,96 @@
|
|||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.util.MapAbstractTestCase;
|
import com.twelvemonkeys.util.MapAbstractTestCase;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServletConfigMapAdapterTestCase
|
* ServletConfigMapAdapterTestCase
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java#1 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletParametersMapAdapterTestCase.java#1 $
|
||||||
*/
|
*/
|
||||||
public class ServletParametersMapAdapterTest extends MapAbstractTestCase {
|
public class ServletParametersMapAdapterTest extends MapAbstractTestCase {
|
||||||
private static final List<String> PARAM_VALUE_ETAG = Arrays.asList("\"1234567890abcdef\"");
|
private static final List<String> PARAM_VALUE_ETAG = Arrays.asList("\"1234567890abcdef\"");
|
||||||
private static final List<String> PARAM_VALUE_DATE = Arrays.asList(new Date().toString());
|
private static final List<String> PARAM_VALUE_DATE = Arrays.asList(new Date().toString());
|
||||||
private static final List<String> PARAM_VALUE_FOO = Arrays.asList("one", "two");
|
private static final List<String> PARAM_VALUE_FOO = Arrays.asList("one", "two");
|
||||||
|
|
||||||
public boolean isPutAddSupported() {
|
public boolean isPutAddSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPutChangeSupported() {
|
public boolean isPutChangeSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRemoveSupported() {
|
public boolean isRemoveSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSetValueSupported() {
|
public boolean isSetValueSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTestSerialization() {
|
public boolean isTestSerialization() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map makeEmptyMap() {
|
public Map makeEmptyMap() {
|
||||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
when(request.getParameterNames()).thenAnswer(returnEnumeration(Collections.emptyList()));
|
when(request.getParameterNames()).thenAnswer(returnEnumeration(Collections.emptyList()));
|
||||||
|
|
||||||
return new ServletParametersMapAdapter(request);
|
return new ServletParametersMapAdapter(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map makeFullMap() {
|
public Map makeFullMap() {
|
||||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
|
|
||||||
when(request.getParameterNames()).thenAnswer(returnEnumeration(Arrays.asList("tag", "date", "foo")));
|
when(request.getParameterNames()).thenAnswer(returnEnumeration(Arrays.asList("tag", "date", "foo")));
|
||||||
when(request.getParameterValues("date")).thenReturn(PARAM_VALUE_DATE.toArray(new String[PARAM_VALUE_DATE.size()]));
|
when(request.getParameterValues("date")).thenReturn(PARAM_VALUE_DATE.toArray(new String[PARAM_VALUE_DATE.size()]));
|
||||||
when(request.getParameterValues("tag")).thenReturn(PARAM_VALUE_ETAG.toArray(new String[PARAM_VALUE_ETAG.size()]));
|
when(request.getParameterValues("tag")).thenReturn(PARAM_VALUE_ETAG.toArray(new String[PARAM_VALUE_ETAG.size()]));
|
||||||
when(request.getParameterValues("foo")).thenReturn(PARAM_VALUE_FOO.toArray(new String[PARAM_VALUE_FOO.size()]));
|
when(request.getParameterValues("foo")).thenReturn(PARAM_VALUE_FOO.toArray(new String[PARAM_VALUE_FOO.size()]));
|
||||||
|
|
||||||
return new ServletParametersMapAdapter(request);
|
return new ServletParametersMapAdapter(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getSampleKeys() {
|
public Object[] getSampleKeys() {
|
||||||
return new String[] {"date", "tag", "foo"};
|
return new String[] {"date", "tag", "foo"};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getSampleValues() {
|
public Object[] getSampleValues() {
|
||||||
return new Object[] {PARAM_VALUE_DATE, PARAM_VALUE_ETAG, PARAM_VALUE_FOO};
|
return new Object[] {PARAM_VALUE_DATE, PARAM_VALUE_ETAG, PARAM_VALUE_FOO};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getNewSampleValues() {
|
public Object[] getNewSampleValues() {
|
||||||
// Needs to be same length but different values
|
// Needs to be same length but different values
|
||||||
return new Object[3];
|
return new Object[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static <T> ReturnNewEnumeration<T> returnEnumeration(final Collection<T> collection) {
|
protected static <T> ReturnNewEnumeration<T> returnEnumeration(final Collection<T> collection) {
|
||||||
return new ReturnNewEnumeration<T>(collection);
|
return new ReturnNewEnumeration<T>(collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ReturnNewEnumeration<T> implements Answer<Enumeration<T>> {
|
private static class ReturnNewEnumeration<T> implements Answer<Enumeration<T>> {
|
||||||
private final Collection<T> collection;
|
private final Collection<T> collection;
|
||||||
|
|
||||||
private ReturnNewEnumeration(final Collection<T> collection) {
|
private ReturnNewEnumeration(final Collection<T> collection) {
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration<T> answer(InvocationOnMock invocation) throws Throwable {
|
public Enumeration<T> answer(InvocationOnMock invocation) throws Throwable {
|
||||||
return Collections.enumeration(collection);
|
return Collections.enumeration(collection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-23
@@ -1,23 +1,23 @@
|
|||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
|
||||||
|
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServletResponseAbsrtactTestCase
|
* ServletResponseAbsrtactTestCase
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletResponseAbsrtactTestCase.java#1 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/ServletResponseAbsrtactTestCase.java#1 $
|
||||||
*/
|
*/
|
||||||
public abstract class ServletResponseAbsrtactTestCase extends ObjectAbstractTestCase {
|
public abstract class ServletResponseAbsrtactTestCase extends ObjectAbstractTestCase {
|
||||||
protected Object makeObject() {
|
protected Object makeObject() {
|
||||||
return makeServletResponse();
|
return makeServletResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract ServletResponse makeServletResponse();
|
protected abstract ServletResponse makeServletResponse();
|
||||||
|
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|||||||
+115
-115
@@ -1,115 +1,115 @@
|
|||||||
package com.twelvemonkeys.servlet;
|
package com.twelvemonkeys.servlet;
|
||||||
|
|
||||||
import com.twelvemonkeys.io.OutputStreamAbstractTestCase;
|
import com.twelvemonkeys.io.OutputStreamAbstractTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TrimWhiteSpaceFilterTestCase
|
* TrimWhiteSpaceFilterTestCase
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilterTestCase.java#1 $
|
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-servlet/src/test/java/com/twelvemonkeys/servlet/TrimWhiteSpaceFilterTestCase.java#1 $
|
||||||
*/
|
*/
|
||||||
public class TrimWhiteSpaceFilterTestCase extends FilterAbstractTestCase {
|
public class TrimWhiteSpaceFilterTestCase extends FilterAbstractTestCase {
|
||||||
protected Filter makeFilter() {
|
protected Filter makeFilter() {
|
||||||
return new TrimWhiteSpaceFilter();
|
return new TrimWhiteSpaceFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class TrimWSFilterOutputStreamTestCase extends OutputStreamAbstractTestCase {
|
public static final class TrimWSFilterOutputStreamTestCase extends OutputStreamAbstractTestCase {
|
||||||
protected OutputStream makeObject() {
|
protected OutputStream makeObject() {
|
||||||
// NOTE: ByteArrayOutputStream does not implement flush or close...
|
// NOTE: ByteArrayOutputStream does not implement flush or close...
|
||||||
return makeOutputStream(new ByteArrayOutputStream(16));
|
return makeOutputStream(new ByteArrayOutputStream(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OutputStream makeOutputStream(OutputStream pWrapped) {
|
protected OutputStream makeOutputStream(OutputStream pWrapped) {
|
||||||
return new TrimWhiteSpaceFilter.TrimWSFilterOutputStream(pWrapped);
|
return new TrimWhiteSpaceFilter.TrimWSFilterOutputStream(pWrapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrimWSOnlyWS() throws IOException {
|
public void testTrimWSOnlyWS() throws IOException {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
||||||
OutputStream trim = makeOutputStream(out);
|
OutputStream trim = makeOutputStream(out);
|
||||||
|
|
||||||
String input = " \n\n\t \t" + (char) 0x0a + ' ' + (char) 0x0d + "\r ";
|
String input = " \n\n\t \t" + (char) 0x0a + ' ' + (char) 0x0d + "\r ";
|
||||||
|
|
||||||
trim.write(input.getBytes());
|
trim.write(input.getBytes());
|
||||||
trim.flush();
|
trim.flush();
|
||||||
trim.close();
|
trim.close();
|
||||||
|
|
||||||
assertEquals("Should be trimmed", "\"\"", '"' + new String(out.toByteArray()) + '"');
|
assertEquals("Should be trimmed", "\"\"", '"' + new String(out.toByteArray()) + '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrimWSLeading() throws IOException {
|
public void testTrimWSLeading() throws IOException {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
||||||
OutputStream trim = makeOutputStream(out);
|
OutputStream trim = makeOutputStream(out);
|
||||||
|
|
||||||
byte[] input = " \n<?xml version=\"1.0\"?>\n\t <not-really-well-formed/> \t".getBytes();
|
byte[] input = " \n<?xml version=\"1.0\"?>\n\t <not-really-well-formed/> \t".getBytes();
|
||||||
String trimmed = "<?xml version=\"1.0\"?>\n<not-really-well-formed/> "; // TODO: This is pr spec (the trailing space). But probably quite stupid...
|
String trimmed = "<?xml version=\"1.0\"?>\n<not-really-well-formed/> "; // TODO: This is pr spec (the trailing space). But probably quite stupid...
|
||||||
|
|
||||||
trim.write(input);
|
trim.write(input);
|
||||||
trim.flush();
|
trim.flush();
|
||||||
trim.close();
|
trim.close();
|
||||||
|
|
||||||
assertEquals("Should be trimmed", '"' + trimmed + '"', '"' + new String(out.toByteArray()) + '"');
|
assertEquals("Should be trimmed", '"' + trimmed + '"', '"' + new String(out.toByteArray()) + '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrimWSOffsetLength() throws IOException {
|
public void testTrimWSOffsetLength() throws IOException {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
|
||||||
OutputStream trim = makeOutputStream(out);
|
OutputStream trim = makeOutputStream(out);
|
||||||
|
|
||||||
// Kindly generated by http://lipsum.org/ :-)
|
// Kindly generated by http://lipsum.org/ :-)
|
||||||
byte[] input = (" \n\tLorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\r\n\r" +
|
byte[] input = (" \n\tLorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\r\n\r" +
|
||||||
"Etiam arcu neque, \n\rmalesuada blandit,\t\n\r\n\r\n\n\n\r\n\r\r\n\n\t rutrum quis, molestie at, diam.\n" +
|
"Etiam arcu neque, \n\rmalesuada blandit,\t\n\r\n\r\n\n\n\r\n\r\r\n\n\t rutrum quis, molestie at, diam.\n" +
|
||||||
" Nulla elementum elementum eros.\n \t\t\n\r" +
|
" Nulla elementum elementum eros.\n \t\t\n\r" +
|
||||||
"Ut rhoncus, turpis in pellentesque volutpat, sapien sem accumsan augue, a scelerisque nibh erat vel magna.\n" +
|
"Ut rhoncus, turpis in pellentesque volutpat, sapien sem accumsan augue, a scelerisque nibh erat vel magna.\n" +
|
||||||
" Phasellus diam orci, dignissim et, gravida vitae, venenatis eu, elit.\n" +
|
" Phasellus diam orci, dignissim et, gravida vitae, venenatis eu, elit.\n" +
|
||||||
"\t\t\tSuspendisse dictum enim at nisl. Integer magna erat, viverra sit amet, consectetuer nec, accumsan ut, mi.\n" +
|
"\t\t\tSuspendisse dictum enim at nisl. Integer magna erat, viverra sit amet, consectetuer nec, accumsan ut, mi.\n" +
|
||||||
"\n\r\r\r\n\rNunc ultricies \n\n\n consectetuer mauris. " +
|
"\n\r\r\r\n\rNunc ultricies \n\n\n consectetuer mauris. " +
|
||||||
"Nulla lectus mauris, viverra ac, pulvinar a, commodo quis, nulla.\n " +
|
"Nulla lectus mauris, viverra ac, pulvinar a, commodo quis, nulla.\n " +
|
||||||
"Ut eget nulla. In est dolor, convallis \t non, tincidunt \tvestibulum, porttitor et, eros.\n " +
|
"Ut eget nulla. In est dolor, convallis \t non, tincidunt \tvestibulum, porttitor et, eros.\n " +
|
||||||
"\t\t \t \n\rDonec vehicula ultrices nisl.").getBytes();
|
"\t\t \t \n\rDonec vehicula ultrices nisl.").getBytes();
|
||||||
|
|
||||||
String trimmed = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n" +
|
String trimmed = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n" +
|
||||||
"Etiam arcu neque, malesuada blandit,\trutrum quis, molestie at, diam.\n" +
|
"Etiam arcu neque, malesuada blandit,\trutrum quis, molestie at, diam.\n" +
|
||||||
"Nulla elementum elementum eros.\n" +
|
"Nulla elementum elementum eros.\n" +
|
||||||
"Ut rhoncus, turpis in pellentesque volutpat, sapien sem accumsan augue, a scelerisque nibh erat vel magna.\n" +
|
"Ut rhoncus, turpis in pellentesque volutpat, sapien sem accumsan augue, a scelerisque nibh erat vel magna.\n" +
|
||||||
"Phasellus diam orci, dignissim et, gravida vitae, venenatis eu, elit.\n" +
|
"Phasellus diam orci, dignissim et, gravida vitae, venenatis eu, elit.\n" +
|
||||||
"Suspendisse dictum enim at nisl. Integer magna erat, viverra sit amet, consectetuer nec, accumsan ut, mi.\n" +
|
"Suspendisse dictum enim at nisl. Integer magna erat, viverra sit amet, consectetuer nec, accumsan ut, mi.\n" +
|
||||||
"Nunc ultricies consectetuer mauris. Nulla lectus mauris, viverra ac, pulvinar a, commodo quis, nulla.\n" +
|
"Nunc ultricies consectetuer mauris. Nulla lectus mauris, viverra ac, pulvinar a, commodo quis, nulla.\n" +
|
||||||
"Ut eget nulla. In est dolor, convallis non, tincidunt vestibulum, porttitor et, eros.\n" +
|
"Ut eget nulla. In est dolor, convallis non, tincidunt vestibulum, porttitor et, eros.\n" +
|
||||||
"Donec vehicula ultrices nisl.";
|
"Donec vehicula ultrices nisl.";
|
||||||
|
|
||||||
int chunkLenght = 5;
|
int chunkLenght = 5;
|
||||||
int bytesLeft = input.length;
|
int bytesLeft = input.length;
|
||||||
while (bytesLeft > chunkLenght) {
|
while (bytesLeft > chunkLenght) {
|
||||||
trim.write(input, input.length - bytesLeft, chunkLenght);
|
trim.write(input, input.length - bytesLeft, chunkLenght);
|
||||||
bytesLeft -= chunkLenght;
|
bytesLeft -= chunkLenght;
|
||||||
}
|
}
|
||||||
trim.write(input, input.length - bytesLeft, bytesLeft);
|
trim.write(input, input.length - bytesLeft, bytesLeft);
|
||||||
|
|
||||||
trim.flush();
|
trim.flush();
|
||||||
trim.close();
|
trim.close();
|
||||||
|
|
||||||
assertEquals("Should be trimmed", '"' + trimmed + '"', '"' + new String(out.toByteArray()) + '"');
|
assertEquals("Should be trimmed", '"' + trimmed + '"', '"' + new String(out.toByteArray()) + '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test that we DON'T remove too much...
|
// TODO: Test that we DON'T remove too much...
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class TrimWSServletResponseWrapperTestCase extends ServletResponseAbsrtactTestCase {
|
public static final class TrimWSServletResponseWrapperTestCase extends ServletResponseAbsrtactTestCase {
|
||||||
protected ServletResponse makeServletResponse() {
|
protected ServletResponse makeServletResponse() {
|
||||||
return new TrimWhiteSpaceFilter.TrimWSServletResponseWrapper(new MockServletResponse());
|
return new TrimWhiteSpaceFilter.TrimWSServletResponseWrapper(new MockServletResponse());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+341
@@ -0,0 +1,341 @@
|
|||||||
|
package com.twelvemonkeys.servlet.image.aoi;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.servlet.image.aoi.DefaultAreaOfInterest;
|
||||||
|
import com.twelvemonkeys.servlet.image.aoi.UniformAreaOfInterest;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:erlend@escenic.com">Erlend Hamnaberg</a>
|
||||||
|
* @version $Revision: $
|
||||||
|
*/
|
||||||
|
public class AreaOfInterestTestCase {
|
||||||
|
private static final Dimension SQUARE_200_200 = new Dimension(200, 200);
|
||||||
|
private static final Dimension PORTRAIT_100_200 = new Dimension(100, 200);
|
||||||
|
private static final Dimension LANDSCAPE_200_100 = new Dimension(200, 100);
|
||||||
|
private static final Dimension SQUARE_100_100 = new Dimension(100, 100);
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
// Absolute AOI
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIAbsolute() {
|
||||||
|
assertEquals(new Rectangle(10, 10, 100, 100), new DefaultAreaOfInterest(SQUARE_200_200).getAOI(10, 10, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIAbsoluteOverflowX() {
|
||||||
|
assertEquals(new Rectangle(10, 10, 90, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(10, 10, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIAbsoluteOverflowW() {
|
||||||
|
|
||||||
|
assertEquals(new Rectangle(0, 10, 100, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(0, 10, 110, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIAbsoluteOverflowY() {
|
||||||
|
|
||||||
|
assertEquals(new Rectangle(10, 10, 100, 90), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(10, 10, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIAbsoluteOverflowH() {
|
||||||
|
|
||||||
|
assertEquals(new Rectangle(10, 0, 100, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(10, 0, 100, 110));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
// Uniform AOI centered
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredS2SUp() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 333, 333));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredS2SDown() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 33, 33));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredS2SNormalized() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredS2W() {
|
||||||
|
assertEquals(new Rectangle(0, 25, 100, 50), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 200, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredS2WNormalized() {
|
||||||
|
assertEquals(new Rectangle(0, 25, 100, 50), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredS2N() {
|
||||||
|
assertEquals(new Rectangle(25, 0, 50, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredS2NNormalized() {
|
||||||
|
assertEquals(new Rectangle(25, 0, 50, 100), new UniformAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 50, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2S() {
|
||||||
|
assertEquals(new Rectangle(50, 0, 100, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 333, 333));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2SNormalized() {
|
||||||
|
assertEquals(new Rectangle(50, 0, 100, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2W() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 200, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2WW() {
|
||||||
|
assertEquals(new Rectangle(0, 25, 200, 50), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 200, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2WN() {
|
||||||
|
assertEquals(new Rectangle(25, 0, 150, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 75, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2WNNormalized() {
|
||||||
|
assertEquals(new Rectangle(25, 0, 150, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 150, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2WNormalized() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 200, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 200, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2N() {
|
||||||
|
assertEquals(new Rectangle(75, 0, 50, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredW2NNormalized() {
|
||||||
|
assertEquals(new Rectangle(75, 0, 50, 100), new UniformAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 50, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2S() {
|
||||||
|
assertEquals(new Rectangle(0, 50, 100, 100), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 333, 333));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2SNormalized() {
|
||||||
|
assertEquals(new Rectangle(0, 50, 100, 100), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2W() {
|
||||||
|
assertEquals(new Rectangle(0, 75, 100, 50), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 200, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2WNormalized() {
|
||||||
|
assertEquals(new Rectangle(0, 75, 100, 50), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2N() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 200), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 50, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2NN() {
|
||||||
|
assertEquals(new Rectangle(25, 0, 50, 200), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 25, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2NW() {
|
||||||
|
assertEquals(new Rectangle(0, 33, 100, 133), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 75, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2NWNormalized() {
|
||||||
|
assertEquals(new Rectangle(0, 37, 100, 125), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 125));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOIUniformCenteredN2NNormalized() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 200), new UniformAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
// Absolute AOI centered
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2SUp() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 333, 333));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2SDown() {
|
||||||
|
assertEquals(new Rectangle(33, 33, 33, 33), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 33, 33));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2SSame() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2WOverflow() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 200, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2W() {
|
||||||
|
assertEquals(new Rectangle(40, 45, 20, 10), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 20, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2WMax() {
|
||||||
|
assertEquals(new Rectangle(0, 25, 100, 50), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2NOverflow() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 100, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2N() {
|
||||||
|
assertEquals(new Rectangle(45, 40, 10, 20), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 10, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredS2NMax() {
|
||||||
|
assertEquals(new Rectangle(25, 0, 50, 100), new DefaultAreaOfInterest(SQUARE_100_100).getAOI(-1, -1, 50, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2SOverflow() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 200, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 333, 333));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2S() {
|
||||||
|
assertEquals(new Rectangle(75, 25, 50, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 50, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2SMax() {
|
||||||
|
assertEquals(new Rectangle(50, 0, 100, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2WOverflow() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 200, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 300, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2W() {
|
||||||
|
assertEquals(new Rectangle(50, 25, 100, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2WW() {
|
||||||
|
assertEquals(new Rectangle(10, 40, 180, 20), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 180, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2WN() {
|
||||||
|
assertEquals(new Rectangle(62, 25, 75, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 75, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2WSame() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 200, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 200, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2NOverflow() {
|
||||||
|
assertEquals(new Rectangle(50, 0, 100, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 100, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2N() {
|
||||||
|
assertEquals(new Rectangle(83, 25, 33, 50), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 33, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredW2NMax() {
|
||||||
|
assertEquals(new Rectangle(75, 0, 50, 100), new DefaultAreaOfInterest(LANDSCAPE_200_100).getAOI(-1, -1, 50, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2S() {
|
||||||
|
assertEquals(new Rectangle(33, 83, 33, 33), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 33, 33));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2SMax() {
|
||||||
|
assertEquals(new Rectangle(0, 50, 100, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2WOverflow() {
|
||||||
|
assertEquals(new Rectangle(0, 50, 100, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 200, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2W() {
|
||||||
|
assertEquals(new Rectangle(40, 95, 20, 10), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 20, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2WMax() {
|
||||||
|
assertEquals(new Rectangle(0, 75, 100, 50), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2N() {
|
||||||
|
assertEquals(new Rectangle(45, 90, 10, 20), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 10, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2NSame() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 200), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2NN() {
|
||||||
|
assertEquals(new Rectangle(37, 50, 25, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 25, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2NW() {
|
||||||
|
assertEquals(new Rectangle(12, 50, 75, 100), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 75, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2NWMax() {
|
||||||
|
assertEquals(new Rectangle(0, 37, 100, 125), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 125));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAOICenteredN2NMax() {
|
||||||
|
assertEquals(new Rectangle(0, 0, 100, 200), new DefaultAreaOfInterest(PORTRAIT_100_200).getAOI(-1, -1, 100, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user