mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-01-25 00:00:01 -05:00
Merge branch 'master' of https://github.com/haraldk/TwelveMonkeys
This commit is contained in:
150
sandbox/pom.xml
Normal file
150
sandbox/pom.xml
Normal file
@@ -0,0 +1,150 @@
|
||||
<?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>
|
||||
<groupId>com.twelvemonkeys.sandbox</groupId>
|
||||
<artifactId>sandbox</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<name>TwelveMonkeys :: Sandbox</name>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>
|
||||
The TwelveMonkeys Sandbox. Experimental stuff, in progress, not for production use.
|
||||
</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
<module>sandbox-common</module>
|
||||
<module>sandbox-imageio</module>
|
||||
<module>sandbox-servlet</module>
|
||||
<module>sandbox-swing</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-image</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.swing</groupId>
|
||||
<artifactId>swing-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.swing</groupId>
|
||||
<artifactId>swing-application</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Implementation-Title>${project.name}</Implementation-Title>
|
||||
<Implementation-Vendor>TwelveMonkeys</Implementation-Vendor>
|
||||
<Implementation-Version>${project.version}</Implementation-Version>
|
||||
<Implementation-URL>http://github.com/haraldk/TwelveMonkeys</Implementation-URL>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
58
sandbox/sandbox-common/pom.xml
Normal file
58
sandbox/sandbox-common/pom.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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.sandbox</groupId>
|
||||
<artifactId>sandbox</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>sandbox-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Sandbox :: Common</name>
|
||||
<description>
|
||||
The TwelveMonkeys Common Sandbox. Experimental stuff.
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-image</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<scope>test</scope>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<scope>test</scope>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,78 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.renderable.RenderableImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* EasyImage
|
||||
* <p/>
|
||||
*
|
||||
* @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/image/EasyImage.java#1 $
|
||||
*/
|
||||
public class EasyImage extends BufferedImage {
|
||||
public EasyImage(InputStream pInput) throws IOException {
|
||||
this(ImageIO.read(pInput));
|
||||
}
|
||||
|
||||
public EasyImage(BufferedImage pImage) {
|
||||
this(pImage.getColorModel(), pImage.getRaster());
|
||||
}
|
||||
|
||||
public EasyImage(RenderableImage pImage) {
|
||||
this(pImage.createDefaultRendering());
|
||||
}
|
||||
|
||||
public EasyImage(RenderedImage pImage) {
|
||||
this(pImage.getColorModel(), pImage.copyData(pImage.getColorModel().createCompatibleWritableRaster(pImage.getWidth(), pImage.getHeight())));
|
||||
}
|
||||
|
||||
public EasyImage(ImageProducer pImage) {
|
||||
this(new BufferedImageFactory(pImage).getBufferedImage());
|
||||
}
|
||||
|
||||
public EasyImage(Image pImage) {
|
||||
this(new BufferedImageFactory(pImage).getBufferedImage());
|
||||
}
|
||||
|
||||
private EasyImage(ColorModel cm, WritableRaster raster) {
|
||||
super(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
}
|
||||
|
||||
public boolean write(String pFormat, OutputStream pOutput) throws IOException {
|
||||
return ImageIO.write(this, pFormat, pOutput);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.renderable.RenderableImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* EasyImage
|
||||
* <p/>
|
||||
*
|
||||
* @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/image/EasyImage.java#1 $
|
||||
*/
|
||||
public class EasyImage extends BufferedImage {
|
||||
public EasyImage(InputStream pInput) throws IOException {
|
||||
this(ImageIO.read(pInput));
|
||||
}
|
||||
|
||||
public EasyImage(BufferedImage pImage) {
|
||||
this(pImage.getColorModel(), pImage.getRaster());
|
||||
}
|
||||
|
||||
public EasyImage(RenderableImage pImage) {
|
||||
this(pImage.createDefaultRendering());
|
||||
}
|
||||
|
||||
public EasyImage(RenderedImage pImage) {
|
||||
this(pImage.getColorModel(), pImage.copyData(pImage.getColorModel().createCompatibleWritableRaster(pImage.getWidth(), pImage.getHeight())));
|
||||
}
|
||||
|
||||
public EasyImage(ImageProducer pImage) {
|
||||
this(new BufferedImageFactory(pImage).getBufferedImage());
|
||||
}
|
||||
|
||||
public EasyImage(Image pImage) {
|
||||
this(new BufferedImageFactory(pImage).getBufferedImage());
|
||||
}
|
||||
|
||||
private EasyImage(ColorModel cm, WritableRaster raster) {
|
||||
super(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
}
|
||||
|
||||
public boolean write(String pFormat, OutputStream pOutput) throws IOException {
|
||||
return ImageIO.write(this, pFormat, pOutput);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.image.ImageConsumer;
|
||||
import java.awt.image.ColorModel;
|
||||
|
||||
/**
|
||||
* ExtendedImageConsumer
|
||||
* <p/>
|
||||
*
|
||||
* @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/image/ExtendedImageConsumer.java#1 $
|
||||
*/
|
||||
public interface ExtendedImageConsumer extends ImageConsumer {
|
||||
/**
|
||||
*
|
||||
* @param pX
|
||||
* @param pY
|
||||
* @param pWidth
|
||||
* @param pHeight
|
||||
* @param pModel
|
||||
* @param pPixels
|
||||
* @param pOffset
|
||||
* @param pScanSize
|
||||
*/
|
||||
public void setPixels(int pX, int pY, int pWidth, int pHeight,
|
||||
ColorModel pModel,
|
||||
short[] pPixels, int pOffset, int pScanSize);
|
||||
|
||||
// Allow for packed and interleaved models
|
||||
public void setPixels(int pX, int pY, int pWidth, int pHeight,
|
||||
ColorModel pModel,
|
||||
byte[] pPixels, int pOffset, int pScanSize);
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.image.ImageConsumer;
|
||||
import java.awt.image.ColorModel;
|
||||
|
||||
/**
|
||||
* ExtendedImageConsumer
|
||||
* <p/>
|
||||
*
|
||||
* @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/image/ExtendedImageConsumer.java#1 $
|
||||
*/
|
||||
public interface ExtendedImageConsumer extends ImageConsumer {
|
||||
/**
|
||||
*
|
||||
* @param pX
|
||||
* @param pY
|
||||
* @param pWidth
|
||||
* @param pHeight
|
||||
* @param pModel
|
||||
* @param pPixels
|
||||
* @param pOffset
|
||||
* @param pScanSize
|
||||
*/
|
||||
public void setPixels(int pX, int pY, int pWidth, int pHeight,
|
||||
ColorModel pModel,
|
||||
short[] pPixels, int pOffset, int pScanSize);
|
||||
|
||||
// Allow for packed and interleaved models
|
||||
public void setPixels(int pX, int pY, int pWidth, int pHeight,
|
||||
ColorModel pModel,
|
||||
byte[] pPixels, int pOffset, int pScanSize);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
/**
|
||||
* A generic writable raster.
|
||||
* For use when factory methods from {@link java.awt.image.Raster} can't be used,
|
||||
* typically because of custom data buffers.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: GenericWritableRaster.java,v 1.0 Jun 13, 2010 12:27:45 AM haraldk Exp$
|
||||
*/
|
||||
class GenericWritableRaster extends WritableRaster {
|
||||
public GenericWritableRaster(final SampleModel model, final DataBuffer buffer, final Point origin) {
|
||||
super(model, buffer, origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"%s: %s width = %s height = %s #Bands = %s xOff = %s yOff = %s %s",
|
||||
getClass().getSimpleName(),
|
||||
sampleModel,
|
||||
getWidth(), getHeight(), getNumBands(),
|
||||
sampleModelTranslateX, sampleModelTranslateY,
|
||||
dataBuffer
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* MappedBufferImage
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: MappedBufferImage.java,v 1.0 Jun 13, 2010 7:33:19 PM haraldk Exp$
|
||||
*/
|
||||
public class MappedBufferImage {
|
||||
private static int threads = Runtime.getRuntime().availableProcessors();
|
||||
private static ExecutorService executorService = Executors.newFixedThreadPool(threads);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
int argIndex = 0;
|
||||
File file = args.length > 0 ? new File(args[argIndex]) : null;
|
||||
|
||||
int w;
|
||||
int h;
|
||||
BufferedImage image;
|
||||
|
||||
if (file != null && file.exists()) {
|
||||
argIndex++;
|
||||
|
||||
// Load image using ImageIO
|
||||
ImageInputStream input = ImageIO.createImageInputStream(file);
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||
|
||||
if (!readers.hasNext()) {
|
||||
System.err.println("No image reader found for input: " + file.getAbsolutePath());
|
||||
System.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
ImageReader reader = readers.next();
|
||||
try {
|
||||
reader.setInput(input);
|
||||
|
||||
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
|
||||
ImageTypeSpecifier type = types.next();
|
||||
|
||||
// TODO: Negotiate best layout according to the GraphicsConfiguration.
|
||||
|
||||
w = reader.getWidth(0);
|
||||
h = reader.getHeight(0);
|
||||
|
||||
// GraphicsConfiguration configuration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
||||
// ColorModel cm2 = configuration.getColorModel(cm.getTransparency());
|
||||
|
||||
// image = MappedImageFactory.createCompatibleMappedImage(w, h, cm2);
|
||||
// image = MappedImageFactory.createCompatibleMappedImage(w, h, cm);
|
||||
// image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
// image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_INT_BGR);
|
||||
// image = MappedImageFactory.createCompatibleMappedImage(w, h, type);
|
||||
// if (w > 1024 || h > 1024) {
|
||||
image = MappedImageFactory.createCompatibleMappedImage(w, h, type);
|
||||
// }
|
||||
// else {
|
||||
// image = type.createBufferedImage(w, h);
|
||||
// }
|
||||
|
||||
System.out.println("image = " + image);
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
param.setDestination(image);
|
||||
|
||||
reader.addIIOReadProgressListener(new ConsoleProgressListener());
|
||||
reader.read(0, param);
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
else {
|
||||
w = args.length > argIndex && StringUtil.isNumber(args[argIndex]) ? Integer.parseInt(args[argIndex++]) : 6000;
|
||||
h = args.length > argIndex && StringUtil.isNumber(args[argIndex]) ? Integer.parseInt(args[argIndex++]) : w * 2 / 3;
|
||||
|
||||
GraphicsConfiguration configuration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
||||
image = MappedImageFactory.createCompatibleMappedImage(w, h, configuration, Transparency.TRANSLUCENT);
|
||||
// image = MappedImageFactory.createCompatibleMappedImage(w, h, configuration, Transparency.OPAQUE);
|
||||
// image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
|
||||
System.out.println("image = " + image);
|
||||
|
||||
DataBuffer buffer = image.getRaster().getDataBuffer();
|
||||
final boolean alpha = image.getColorModel().hasAlpha();
|
||||
|
||||
// Mix in some nice colors
|
||||
createBackground(w, h, buffer, alpha);
|
||||
|
||||
// Add some random dots (get out the coffee)
|
||||
paintDots(w, h, image);
|
||||
}
|
||||
|
||||
// Resample down to some fixed size
|
||||
if (args.length > argIndex && "-scale".equals(args[argIndex++])) {
|
||||
image = resampleImage(image, 800);
|
||||
}
|
||||
|
||||
int bytesPerPixel = image.getColorModel().getPixelSize() / 8; // Calculate first to avoid overflow
|
||||
String size = toHumanReadableSize(w * h * bytesPerPixel);
|
||||
showIt(w, h, image, size);
|
||||
}
|
||||
|
||||
private static void showIt(final int w, final int h, BufferedImage image, final String size) {
|
||||
JFrame frame = new JFrame(String.format("Test [%s x %s] (%s)", w, h, size)) {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
// TODO: This looks like a useful util method...
|
||||
DisplayMode displayMode = getGraphicsConfiguration().getDevice().getDisplayMode();
|
||||
Dimension size = super.getPreferredSize();
|
||||
|
||||
size.width = Math.min(size.width, displayMode.getWidth());
|
||||
size.height = Math.min(size.height, displayMode.getHeight());
|
||||
|
||||
return size;
|
||||
}
|
||||
};
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
JScrollPane scroll = new JScrollPane(new ImageComponent(image));
|
||||
scroll.setBorder(BorderFactory.createEmptyBorder());
|
||||
frame.add(scroll);
|
||||
frame.pack();
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private static BufferedImage resampleImage(final BufferedImage image, final int width) {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
float aspect = image.getHeight() / (float) image.getWidth();
|
||||
int height = Math.round(width * aspect);
|
||||
|
||||
// NOTE: The createCompatibleDestImage takes the byte order/layout into account, unlike the cm.createCompatibleWritableRaster
|
||||
final BufferedImage output = new ResampleOp(width, height).createCompatibleDestImage(image, null);
|
||||
|
||||
final int inStep = (int) Math.ceil(image.getHeight() / (double) threads);
|
||||
final int outStep = (int) Math.ceil(height / (double) threads);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(threads);
|
||||
|
||||
// Resample image in slices
|
||||
for (int i = 0; i < threads; i++) {
|
||||
final int inY = i * inStep;
|
||||
final int outY = i * outStep;
|
||||
final int inHeight = Math.min(inStep, image.getHeight() - inY);
|
||||
final int outHeight = Math.min(outStep, output.getHeight() - outY);
|
||||
executorService.submit(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
BufferedImage in = image.getSubimage(0, inY, image.getWidth(), inHeight);
|
||||
BufferedImage out = output.getSubimage(0, outY, width, outHeight);
|
||||
new ResampleOp(width, outHeight, ResampleOp.FILTER_LANCZOS).filter(in, out);
|
||||
// new ResampleOp(width, outHeight, ResampleOp.FILTER_LANCZOS).resample(in, out, ResampleOp.createFilter(ResampleOp.FILTER_LANCZOS));
|
||||
// BufferedImage out = new ResampleOp(width, outHeight, ResampleOp.FILTER_LANCZOS).filter(in, null);
|
||||
// ImageUtil.drawOnto(output.getSubimage(0, outY, width, outHeight), out);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// System.out.println("Starting image scale on single thread, waiting for execution to complete...");
|
||||
// BufferedImage output = new ResampleOp(width, height, ResampleOp.FILTER_LANCZOS).filter(image, null);
|
||||
System.out.printf("Started image scale on %d threads, waiting for execution to complete...%n", threads);
|
||||
|
||||
Boolean done = null;
|
||||
try {
|
||||
done = latch.await(5L, TimeUnit.MINUTES);
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
|
||||
System.out.printf("%s scaling image in %d ms%n", (done == null ? "Interrupted" : !done ? "Timed out" : "Done"), System.currentTimeMillis() - start);
|
||||
System.out.println("image = " + output);
|
||||
return output;
|
||||
}
|
||||
|
||||
private static void paintDots(int width, int height, final BufferedImage image) {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
int s = 300;
|
||||
int ws = width / s;
|
||||
int hs = height / s;
|
||||
|
||||
Color[] colors = new Color[] {
|
||||
Color.WHITE, Color.ORANGE, Color.BLUE, Color.MAGENTA, Color.BLACK, Color.RED, Color.CYAN,
|
||||
Color.GRAY, Color.GREEN, Color.YELLOW, Color.PINK, Color.LIGHT_GRAY, Color.DARK_GRAY
|
||||
};
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(threads);
|
||||
int step = (int) Math.ceil(hs / (double) threads);
|
||||
Random r = new Random();
|
||||
|
||||
for (int i = 0; i < threads; i++) {
|
||||
executorService.submit(new PaintDotsTask(image, s, ws, colors, r, i * step, i * step + step, latch));
|
||||
}
|
||||
|
||||
System.err.printf("Started painting in %d threads, waiting for execution to complete...%n", threads);
|
||||
|
||||
Boolean done = null;
|
||||
try {
|
||||
done = latch.await(3L, TimeUnit.MINUTES);
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
|
||||
System.out.printf("%s painting %d dots in %d ms%n", (done == null ? "Interrupted" : !done ? "Timed out" : "Done"), Math.max(0, hs - 1) * Math.max(0, ws - 1), System.currentTimeMillis() - start);
|
||||
}
|
||||
|
||||
private static void paintDots0(BufferedImage image, int s, int ws, Color[] colors, Random r, final int first, final int last) {
|
||||
for (int y = first; y < last; y++) {
|
||||
for (int x = 0; x < ws - 1; x++) {
|
||||
BufferedImage tile = image.getSubimage(x * s, y * s, 2 * s, 2 * s);
|
||||
Graphics2D g;
|
||||
try {
|
||||
g = tile.createGraphics();
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
System.gc();
|
||||
System.err.println("Out of memory: " + e.getMessage());
|
||||
g = tile.createGraphics(); // If this fails, give up
|
||||
}
|
||||
|
||||
try {
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setComposite(AlphaComposite.SrcOver.derive(r.nextFloat()));
|
||||
g.setColor(colors[r.nextInt(colors.length)]);
|
||||
int o = r.nextInt(s) + s / 10;
|
||||
int c = (2 * s - o) / 2;
|
||||
g.fillOval(c, c, o, o);
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createBackground(int w, int h, DataBuffer buffer, boolean alpha) {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
int step = (int) Math.ceil(h / (double) threads);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(threads);
|
||||
for (int i = 0; i < threads; i++) {
|
||||
executorService.submit(new PaintBackgroundTask(w, h, buffer, alpha, i * step, i * step + step, latch));
|
||||
}
|
||||
System.err.printf("Started painting in %d threads, waiting for execution to complete...%n", threads);
|
||||
|
||||
Boolean done = null;
|
||||
try {
|
||||
done = latch.await(3L, TimeUnit.MINUTES);
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
|
||||
System.out.printf("%s creating background in %d ms%n", (done == null ? "Interrupted" : !done ? "Timed out" : "Done"), System.currentTimeMillis() - start);
|
||||
}
|
||||
|
||||
private static void paintBackground0(int w, int h, DataBuffer buffer, boolean alpha, final int first, final int last) {
|
||||
for (int y = first; y < last; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int r = (int) ((x * y * 255.0) / (h * w));
|
||||
int g = (int) (((w - x) * y * 255.0) / (h * w));
|
||||
int b = (int) ((x * (h - y) * 255.0) / (h * w));
|
||||
int a = alpha ? (int) (((w - x) * (h - y) * 255.0) / (h * w)) : 0;
|
||||
|
||||
switch (buffer.getDataType()) {
|
||||
case DataBuffer.TYPE_BYTE:
|
||||
int off = (y * w + x) * (alpha ? 4 : 3);
|
||||
if (alpha) {
|
||||
buffer.setElem(off++, 255 - a);
|
||||
buffer.setElem(off++, b);
|
||||
buffer.setElem(off++, g);
|
||||
buffer.setElem(off, r);
|
||||
}
|
||||
else {
|
||||
// TODO: Why the RGB / ABGR byte order inconsistency??
|
||||
buffer.setElem(off++, r);
|
||||
buffer.setElem(off++, g);
|
||||
buffer.setElem(off, b);
|
||||
}
|
||||
break;
|
||||
case DataBuffer.TYPE_INT:
|
||||
buffer.setElem(y * w + x, (255 - a) << 24 | r << 16 | g << 8 | b);
|
||||
break;
|
||||
default:
|
||||
System.err.println("Transfer type not supported: " + buffer.getDataType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String toHumanReadableSize(long size) {
|
||||
return String.format("%,d MB", (long) (size / (double) (1024L << 10)));
|
||||
}
|
||||
|
||||
/**
|
||||
* A fairly optimized component for displaying a BufferedImage
|
||||
*/
|
||||
private static class ImageComponent extends JComponent implements Scrollable {
|
||||
private final BufferedImage image;
|
||||
private Paint texture;
|
||||
double zoom = 1;
|
||||
|
||||
public ImageComponent(final BufferedImage image) {
|
||||
setOpaque(true); // Very important when subclassing JComponent...
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
|
||||
texture = createTexture();
|
||||
}
|
||||
|
||||
private Paint createTexture() {
|
||||
BufferedImage pattern = getGraphicsConfiguration().createCompatibleImage(20, 20);
|
||||
Graphics2D g = pattern.createGraphics();
|
||||
|
||||
try {
|
||||
g.setColor(Color.LIGHT_GRAY);
|
||||
g.fillRect(0, 0, pattern.getWidth(), pattern.getHeight());
|
||||
g.setColor(Color.GRAY);
|
||||
g.fillRect(0, 0, pattern.getWidth() / 2, pattern.getHeight() / 2);
|
||||
g.fillRect(pattern.getWidth() / 2, pattern.getHeight() / 2, pattern.getWidth() / 2, pattern.getHeight() / 2);
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
return new TexturePaint(pattern, new Rectangle(pattern.getWidth(), pattern.getHeight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
// TODO: Figure out why mouse wheel/track pad scroll repaints entire component,
|
||||
// unlike using the scroll bars of the JScrollPane.
|
||||
// Consider creating a custom mouse wheel listener as a workaround.
|
||||
|
||||
// We want to paint only the visible part of the image
|
||||
Rectangle visible = getVisibleRect();
|
||||
Rectangle clip = g.getClipBounds();
|
||||
Rectangle rect = clip == null ? visible : visible.intersection(clip);
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
g2.setPaint(texture);
|
||||
g2.fillRect(rect.x, rect.y, rect.width, rect.height);
|
||||
|
||||
if (zoom != 1) {
|
||||
AffineTransform transform = AffineTransform.getScaleInstance(zoom, zoom);
|
||||
g2.setTransform(transform);
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
repaintImage(rect, g2);
|
||||
System.err.println("repaint: " + (System.currentTimeMillis() - start) + " ms");
|
||||
}
|
||||
|
||||
private void repaintImage(Rectangle rect, Graphics2D g2) {
|
||||
try {
|
||||
// Paint tiles of the image, to preserve memory
|
||||
int sliceSize = 200;
|
||||
|
||||
int slicesW = rect.width / sliceSize;
|
||||
int slicesH = rect.height / sliceSize;
|
||||
|
||||
for (int sliceY = 0; sliceY <= slicesH; sliceY++) {
|
||||
for (int sliceX = 0; sliceX <= slicesW; sliceX++) {
|
||||
int x = rect.x + sliceX * sliceSize;
|
||||
int y = rect.y + sliceY * sliceSize;
|
||||
|
||||
int w = sliceX == slicesW ? Math.min(sliceSize, rect.x + rect.width - x) : sliceSize;
|
||||
int h = sliceY == slicesH ? Math.min(sliceSize, rect.y + rect.height - y) : sliceSize;
|
||||
|
||||
if (w == 0 || h == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// System.err.printf("%04d, %04d, %04d, %04d%n", x, y, w, h);
|
||||
BufferedImage img = image.getSubimage(x, y, w, h);
|
||||
g2.drawImage(img, x, y, null);
|
||||
}
|
||||
}
|
||||
|
||||
// BufferedImage img = image.getSubimage(rect.x, rect.y, rect.width, rect.height);
|
||||
// g2.drawImage(img, rect.x, rect.y, null);
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
// e.printStackTrace();
|
||||
// Happens whenever apple.awt.OSXCachingSufraceManager runs out of memory
|
||||
// TODO: Figure out why repaint(x,y,w,h) doesn't work any more..?
|
||||
repaint(); // NOTE: Might cause a brief flash while the component is redrawn
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension((int) (image.getWidth() * zoom), (int) (image.getHeight() * zoom));
|
||||
}
|
||||
|
||||
public Dimension getPreferredScrollableViewportSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
|
||||
switch (orientation) {
|
||||
case SwingConstants.HORIZONTAL:
|
||||
return visibleRect.width * 3 / 4;
|
||||
case SwingConstants.VERTICAL:
|
||||
default:
|
||||
return visibleRect.height * 3 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getScrollableTracksViewportWidth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean getScrollableTracksViewportHeight() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PaintDotsTask implements Runnable {
|
||||
private final BufferedImage image;
|
||||
private final int s;
|
||||
private final int wstep;
|
||||
private final Color[] colors;
|
||||
private final Random random;
|
||||
private final int last;
|
||||
private final int first;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
public PaintDotsTask(BufferedImage image, int s, int wstep, Color[] colors, Random random, int first, int last, CountDownLatch latch) {
|
||||
this.image = image;
|
||||
this.s = s;
|
||||
this.wstep = wstep;
|
||||
this.colors = colors;
|
||||
this.random = random;
|
||||
this.last = last;
|
||||
this.first = first;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
paintDots0(image, s, wstep, colors, random, first, last);
|
||||
}
|
||||
finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PaintBackgroundTask implements Runnable {
|
||||
private final int w;
|
||||
private final int h;
|
||||
private final DataBuffer buffer;
|
||||
private final boolean alpha;
|
||||
private final int first;
|
||||
private final int last;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
public PaintBackgroundTask(int w, int h, DataBuffer buffer, boolean alpha, int first, int last, CountDownLatch latch) {
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.buffer = buffer;
|
||||
this.alpha = alpha;
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
paintBackground0(w, h, buffer, alpha, first, last);
|
||||
}
|
||||
finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConsoleProgressListener extends ProgressListenerBase {
|
||||
static final int COLUMNS = System.getenv("COLUMNS") != null ? Integer.parseInt(System.getenv("COLUMNS")) - 2 : 78;
|
||||
int left = COLUMNS;
|
||||
|
||||
@Override
|
||||
public void imageComplete(ImageReader source) {
|
||||
for (; left > 0; left--) {
|
||||
System.out.print(".");
|
||||
}
|
||||
System.out.println("]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageProgress(ImageReader source, float percentageDone) {
|
||||
int progress = COLUMNS - Math.round(COLUMNS * percentageDone / 100f);
|
||||
if (progress < left) {
|
||||
for (; left > progress; left--) {
|
||||
System.out.print(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageStarted(ImageReader source, int imageIndex) {
|
||||
System.out.print("[");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
/**
|
||||
* A {@code DataBuffer} implementation that is backed by a memory mapped file.
|
||||
* Memory will be allocated outside the normal JVM heap, allowing more efficient
|
||||
* memory usage for large buffers.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: MappedFileBuffer.java,v 1.0 Jun 12, 2010 4:56:51 PM haraldk Exp$
|
||||
*
|
||||
* @see java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)
|
||||
*/
|
||||
public abstract class MappedFileBuffer extends DataBuffer {
|
||||
private final Buffer buffer;
|
||||
|
||||
private MappedFileBuffer(final int type, final int size, final int numBanks) throws IOException {
|
||||
super(type, Validate.isTrue(size >= 0, size, "Integer overflow for size: %d"), Validate.isTrue(numBanks >= 0, numBanks, "Number of banks must be positive"));
|
||||
|
||||
int componentSize = DataBuffer.getDataTypeSize(type) / 8;
|
||||
|
||||
// Create temp file to get a file handle to use for memory mapping
|
||||
File tempFile = File.createTempFile(String.format("%s-", getClass().getSimpleName().toLowerCase()), ".tmp");
|
||||
|
||||
try {
|
||||
RandomAccessFile raf = new RandomAccessFile(tempFile, "rw");
|
||||
|
||||
long length = ((long) size) * componentSize * numBanks;
|
||||
|
||||
raf.setLength(length);
|
||||
FileChannel channel = raf.getChannel();
|
||||
|
||||
// Map entire file into memory, let OS virtual memory/paging do the heavy lifting
|
||||
MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length);
|
||||
|
||||
switch (type) {
|
||||
case DataBuffer.TYPE_BYTE:
|
||||
buffer = byteBuffer;
|
||||
break;
|
||||
case DataBuffer.TYPE_USHORT:
|
||||
buffer = byteBuffer.asShortBuffer();
|
||||
break;
|
||||
case DataBuffer.TYPE_INT:
|
||||
buffer = byteBuffer.asIntBuffer();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported data type: " + type);
|
||||
}
|
||||
|
||||
// According to the docs, we can safely close the channel and delete the file now
|
||||
channel.close();
|
||||
}
|
||||
finally {
|
||||
// NOTE: File can't be deleted right now on Windows, as the file is open. Let JVM clean up later
|
||||
if (!tempFile.delete()) {
|
||||
tempFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("MappedFileBuffer: %s", buffer);
|
||||
}
|
||||
|
||||
// TODO: Is throws IOException a good idea?
|
||||
|
||||
public static DataBuffer create(final int type, final int size, final int numBanks) throws IOException {
|
||||
switch (type) {
|
||||
case DataBuffer.TYPE_BYTE:
|
||||
return new DataBufferByte(size, numBanks);
|
||||
case DataBuffer.TYPE_USHORT:
|
||||
return new DataBufferUShort(size, numBanks);
|
||||
case DataBuffer.TYPE_INT:
|
||||
return new DataBufferInt(size, numBanks);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported data type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
final static class DataBufferByte extends MappedFileBuffer {
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
public DataBufferByte(int size, int numBanks) throws IOException {
|
||||
super(DataBuffer.TYPE_BYTE, size, numBanks);
|
||||
buffer = (ByteBuffer) super.buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getElem(int bank, int i) {
|
||||
return buffer.get(bank * size + i) & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setElem(int bank, int i, int val) {
|
||||
buffer.put(bank * size + i, (byte) val);
|
||||
}
|
||||
}
|
||||
|
||||
final static class DataBufferUShort extends MappedFileBuffer {
|
||||
private final ShortBuffer buffer;
|
||||
|
||||
public DataBufferUShort(int size, int numBanks) throws IOException {
|
||||
super(DataBuffer.TYPE_USHORT, size, numBanks);
|
||||
buffer = (ShortBuffer) super.buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getElem(int bank, int i) {
|
||||
return buffer.get(bank * size + i) & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setElem(int bank, int i, int val) {
|
||||
buffer.put(bank * size + i, (short) val);
|
||||
}
|
||||
}
|
||||
|
||||
final static class DataBufferInt extends MappedFileBuffer {
|
||||
private final IntBuffer buffer;
|
||||
|
||||
public DataBufferInt(int size, int numBanks) throws IOException {
|
||||
super(DataBuffer.TYPE_INT, size, numBanks);
|
||||
buffer = (IntBuffer) super.buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getElem(int bank, int i) {
|
||||
return buffer.get(bank * size + i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setElem(int bank, int i, int val) {
|
||||
buffer.put(bank * size + i, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A factory for creating {@link BufferedImage}s backed by memory mapped files.
|
||||
* The data buffers will be allocated outside the normal JVM heap, allowing more efficient
|
||||
* memory usage for large images.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: MappedImageFactory.java,v 1.0 May 26, 2010 5:07:01 PM haraldk Exp$
|
||||
*/
|
||||
public final class MappedImageFactory {
|
||||
|
||||
// TODO: Create a way to do ColorConvertOp (or other color space conversion) on these images.
|
||||
// - Current implementation of CCOp delegates to internal sun.awt classes that assumes java.awt.DataBufferByte for type byte buffers :-/
|
||||
|
||||
private MappedImageFactory() {}
|
||||
|
||||
public static BufferedImage createCompatibleMappedImage(int width, int height, int type) throws IOException {
|
||||
BufferedImage temp = new BufferedImage(1, 1, type);
|
||||
return createCompatibleMappedImage(width, height, temp.getSampleModel().createCompatibleSampleModel(width, height), temp.getColorModel());
|
||||
}
|
||||
|
||||
public static BufferedImage createCompatibleMappedImage(int width, int height, GraphicsConfiguration configuration, int transparency) throws IOException {
|
||||
// TODO: Should we also use the sample model?
|
||||
return createCompatibleMappedImage(width, height, configuration.getColorModel(transparency));
|
||||
}
|
||||
|
||||
public static BufferedImage createCompatibleMappedImage(int width, int height, ImageTypeSpecifier type) throws IOException {
|
||||
return createCompatibleMappedImage(width, height, type.getSampleModel(width, height), type.getColorModel());
|
||||
}
|
||||
|
||||
static BufferedImage createCompatibleMappedImage(int width, int height, ColorModel cm) throws IOException {
|
||||
return createCompatibleMappedImage(width, height, cm.createCompatibleSampleModel(width, height), cm);
|
||||
}
|
||||
|
||||
static BufferedImage createCompatibleMappedImage(int width, int height, SampleModel sm, ColorModel cm) throws IOException {
|
||||
DataBuffer buffer = MappedFileBuffer.create(sm.getTransferType(), width * height * sm.getNumDataElements(), 1);
|
||||
|
||||
return new BufferedImage(cm, new GenericWritableRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
|
||||
}
|
||||
}
|
||||
524
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/inv_cmap.c
Executable file
524
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/inv_cmap.c
Executable file
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* This software is copyrighted as noted below. It may be freely copied,
|
||||
* modified, and redistributed, provided that the copyright notice is
|
||||
* preserved on all copies.
|
||||
*
|
||||
* There is no warranty or other guarantee of fitness for this software,
|
||||
* it is provided solely "as is". Bug reports or fixes may be sent
|
||||
* to the author, who may or may not act on them as he desires.
|
||||
*
|
||||
* You may not include this software in a program or other software product
|
||||
* without supplying the source, or without informing the end-user that the
|
||||
* source is available for no extra charge.
|
||||
*
|
||||
* If you modify this software, you should include a notice giving the
|
||||
* name of the person performing the modification, the date of modification,
|
||||
* and the reason for such modification.
|
||||
*/
|
||||
/*
|
||||
* inv_cmap.c - Compute an inverse colormap.
|
||||
*
|
||||
* Author: Spencer W. Thomas
|
||||
* EECS Dept.
|
||||
* University of Michigan
|
||||
* Date: Thu Sep 20 1990
|
||||
* Copyright (c) 1990, University of Michigan
|
||||
*
|
||||
* $Id: inv_cmap.c,v 3.0.1.3 1992/04/30 14:07:28 spencer Exp $
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static int bcenter, gcenter, rcenter;
|
||||
static long gdist, rdist, cdist;
|
||||
static long cbinc, cginc, crinc;
|
||||
static unsigned long *gdp, *rdp, *cdp;
|
||||
static unsigned char *grgbp, *rrgbp, *crgbp;
|
||||
static gstride, rstride;
|
||||
static long x, xsqr, colormax;
|
||||
static int cindex;
|
||||
|
||||
#ifdef USE_PROTOTYPES
|
||||
static void maxfill( unsigned long *, long );
|
||||
static int redloop( void );
|
||||
static int greenloop( int );
|
||||
static int blueloop( int );
|
||||
#else
|
||||
static void maxfill();
|
||||
static int redloop();
|
||||
static int greenloop();
|
||||
static int blueloop();
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* TAG( inv_cmap )
|
||||
*
|
||||
* Compute an inverse colormap efficiently.
|
||||
* Inputs:
|
||||
* colors: Number of colors in the forward colormap.
|
||||
* colormap: The forward colormap.
|
||||
* bits: Number of quantization bits. The inverse
|
||||
* colormap will have (2^bits)^3 entries.
|
||||
* dist_buf: An array of (2^bits)^3 long integers to be
|
||||
* used as scratch space.
|
||||
* Outputs:
|
||||
* rgbmap: The output inverse colormap. The entry
|
||||
* rgbmap[(r<<(2*bits)) + (g<<bits) + b]
|
||||
* is the colormap entry that is closest to the
|
||||
* (quantized) color (r,g,b).
|
||||
* Assumptions:
|
||||
* Quantization is performed by right shift (low order bits are
|
||||
* truncated). Thus, the distance to a quantized color is
|
||||
* actually measured to the color at the center of the cell
|
||||
* (i.e., to r+.5, g+.5, b+.5, if (r,g,b) is a quantized color).
|
||||
* Algorithm:
|
||||
* Uses a "distance buffer" algorithm:
|
||||
* The distance from each representative in the forward color map
|
||||
* to each point in the rgb space is computed. If it is less
|
||||
* than the distance currently stored in dist_buf, then the
|
||||
* corresponding entry in rgbmap is replaced with the current
|
||||
* representative (and the dist_buf entry is replaced with the
|
||||
* new distance).
|
||||
*
|
||||
* The distance computation uses an efficient incremental formulation.
|
||||
*
|
||||
* Distances are computed "outward" from each color. If the
|
||||
* colors are evenly distributed in color space, the expected
|
||||
* number of cells visited for color I is N^3/I.
|
||||
* Thus, the complexity of the algorithm is O(log(K) N^3),
|
||||
* where K = colors, and N = 2^bits.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Here's the idea: scan from the "center" of each cell "out"
|
||||
* until we hit the "edge" of the cell -- that is, the point
|
||||
* at which some other color is closer -- and stop. In 1-D,
|
||||
* this is simple:
|
||||
* for i := here to max do
|
||||
* if closer then buffer[i] = this color
|
||||
* else break
|
||||
* repeat above loop with i := here-1 to min by -1
|
||||
*
|
||||
* In 2-D, it's trickier, because along a "scan-line", the
|
||||
* region might start "after" the "center" point. A picture
|
||||
* might clarify:
|
||||
* | ...
|
||||
* | ... .
|
||||
* ... .
|
||||
* ... | .
|
||||
* . + .
|
||||
* . .
|
||||
* . .
|
||||
* .........
|
||||
*
|
||||
* The + marks the "center" of the above region. On the top 2
|
||||
* lines, the region "begins" to the right of the "center".
|
||||
*
|
||||
* Thus, we need a loop like this:
|
||||
* detect := false
|
||||
* for i := here to max do
|
||||
* if closer then
|
||||
* buffer[..., i] := this color
|
||||
* if !detect then
|
||||
* here = i
|
||||
* detect = true
|
||||
* else
|
||||
* if detect then
|
||||
* break
|
||||
*
|
||||
* Repeat the above loop with i := here-1 to min by -1. Note that
|
||||
* the "detect" value should not be reinitialized. If it was
|
||||
* "true", and center is not inside the cell, then none of the
|
||||
* cell lies to the left and this loop should exit
|
||||
* immediately.
|
||||
*
|
||||
* The outer loops are similar, except that the "closer" test
|
||||
* is replaced by a call to the "next in" loop; its "detect"
|
||||
* value serves as the test. (No assignment to the buffer is
|
||||
* done, either.)
|
||||
*
|
||||
* Each time an outer loop starts, the "here", "min", and
|
||||
* "max" values of the next inner loop should be
|
||||
* re-initialized to the center of the cell, 0, and cube size,
|
||||
* respectively. Otherwise, these values will carry over from
|
||||
* one "call" to the inner loop to the next. This tracks the
|
||||
* edges of the cell and minimizes the number of
|
||||
* "unproductive" comparisons that must be made.
|
||||
*
|
||||
* Finally, the inner-most loop can have the "if !detect"
|
||||
* optimized out of it by splitting it into two loops: one
|
||||
* that finds the first color value on the scan line that is
|
||||
* in this cell, and a second that fills the cell until
|
||||
* another one is closer:
|
||||
* if !detect then {needed for "down" loop}
|
||||
* for i := here to max do
|
||||
* if closer then
|
||||
* buffer[..., i] := this color
|
||||
* detect := true
|
||||
* break
|
||||
* for i := i+1 to max do
|
||||
* if closer then
|
||||
* buffer[..., i] := this color
|
||||
* else
|
||||
* break
|
||||
*
|
||||
* In this implementation, each level will require the
|
||||
* following variables. Variables labelled (l) are local to each
|
||||
* procedure. The ? should be replaced with r, g, or b:
|
||||
* cdist: The distance at the starting point.
|
||||
* ?center: The value of this component of the color
|
||||
* c?inc: The initial increment at the ?center position.
|
||||
* ?stride: The amount to add to the buffer
|
||||
* pointers (dp and rgbp) to get to the
|
||||
* "next row".
|
||||
* min(l): The "low edge" of the cell, init to 0
|
||||
* max(l): The "high edge" of the cell, init to
|
||||
* colormax-1
|
||||
* detect(l): True if this row has changed some
|
||||
* buffer entries.
|
||||
* i(l): The index for this row.
|
||||
* ?xx: The accumulated increment value.
|
||||
*
|
||||
* here(l): The starting index for this color. The
|
||||
* following variables are associated with here,
|
||||
* in the sense that they must be updated if here
|
||||
* is changed.
|
||||
* ?dist: The current distance for this level. The
|
||||
* value of dist from the previous level (g or r,
|
||||
* for level b or g) initializes dist on this
|
||||
* level. Thus gdist is associated with here(b)).
|
||||
* ?inc: The initial increment for the row.
|
||||
* ?dp: Pointer into the distance buffer. The value
|
||||
* from the previous level initializes this level.
|
||||
* ?rgbp: Pointer into the rgb buffer. The value
|
||||
* from the previous level initializes this level.
|
||||
*
|
||||
* The blue and green levels modify 'here-associated' variables (dp,
|
||||
* rgbp, dist) on the green and red levels, respectively, when here is
|
||||
* changed.
|
||||
*/
|
||||
|
||||
void
|
||||
inv_cmap( colors, colormap, bits, dist_buf, rgbmap )
|
||||
int colors, bits;
|
||||
unsigned char *colormap[3], *rgbmap;
|
||||
unsigned long *dist_buf;
|
||||
{
|
||||
int nbits = 8 - bits;
|
||||
|
||||
colormax = 1 << bits;
|
||||
x = 1 << nbits;
|
||||
xsqr = 1 << (2 * nbits);
|
||||
|
||||
/* Compute "strides" for accessing the arrays. */
|
||||
gstride = colormax;
|
||||
rstride = colormax * colormax;
|
||||
|
||||
maxfill( dist_buf, colormax );
|
||||
|
||||
for ( cindex = 0; cindex < colors; cindex++ )
|
||||
{
|
||||
/*
|
||||
* Distance formula is
|
||||
* (red - map[0])^2 + (green - map[1])^2 + (blue - map[2])^2
|
||||
*
|
||||
* Because of quantization, we will measure from the center of
|
||||
* each quantized "cube", so blue distance is
|
||||
* (blue + x/2 - map[2])^2,
|
||||
* where x = 2^(8 - bits).
|
||||
* The step size is x, so the blue increment is
|
||||
* 2*x*blue - 2*x*map[2] + 2*x^2
|
||||
*
|
||||
* Now, b in the code below is actually blue/x, so our
|
||||
* increment will be 2*(b*x^2 + x^2 - x*map[2]). For
|
||||
* efficiency, we will maintain this quantity in a separate variable
|
||||
* that will be updated incrementally by adding 2*x^2 each time.
|
||||
*/
|
||||
/* The initial position is the cell containing the colormap
|
||||
* entry. We get this by quantizing the colormap values.
|
||||
*/
|
||||
rcenter = colormap[0][cindex] >> nbits;
|
||||
gcenter = colormap[1][cindex] >> nbits;
|
||||
bcenter = colormap[2][cindex] >> nbits;
|
||||
|
||||
rdist = colormap[0][cindex] - (rcenter * x + x/2);
|
||||
gdist = colormap[1][cindex] - (gcenter * x + x/2);
|
||||
cdist = colormap[2][cindex] - (bcenter * x + x/2);
|
||||
cdist = rdist*rdist + gdist*gdist + cdist*cdist;
|
||||
|
||||
crinc = 2 * ((rcenter + 1) * xsqr - (colormap[0][cindex] * x));
|
||||
cginc = 2 * ((gcenter + 1) * xsqr - (colormap[1][cindex] * x));
|
||||
cbinc = 2 * ((bcenter + 1) * xsqr - (colormap[2][cindex] * x));
|
||||
|
||||
/* Array starting points. */
|
||||
cdp = dist_buf + rcenter * rstride + gcenter * gstride + bcenter;
|
||||
crgbp = rgbmap + rcenter * rstride + gcenter * gstride + bcenter;
|
||||
|
||||
(void)redloop();
|
||||
}
|
||||
}
|
||||
|
||||
/* redloop -- loop up and down from red center. */
|
||||
static int
|
||||
redloop()
|
||||
{
|
||||
int detect;
|
||||
int r;
|
||||
int first;
|
||||
long txsqr = xsqr + xsqr;
|
||||
static long rxx;
|
||||
|
||||
detect = 0;
|
||||
|
||||
/* Basic loop up. */
|
||||
for ( r = rcenter, rdist = cdist, rxx = crinc,
|
||||
rdp = cdp, rrgbp = crgbp, first = 1;
|
||||
r < colormax;
|
||||
r++, rdp += rstride, rrgbp += rstride,
|
||||
rdist += rxx, rxx += txsqr, first = 0 )
|
||||
{
|
||||
if ( greenloop( first ) )
|
||||
detect = 1;
|
||||
else if ( detect )
|
||||
break;
|
||||
}
|
||||
|
||||
/* Basic loop down. */
|
||||
for ( r = rcenter - 1, rxx = crinc - txsqr, rdist = cdist - rxx,
|
||||
rdp = cdp - rstride, rrgbp = crgbp - rstride, first = 1;
|
||||
r >= 0;
|
||||
r--, rdp -= rstride, rrgbp -= rstride,
|
||||
rxx -= txsqr, rdist -= rxx, first = 0 )
|
||||
{
|
||||
if ( greenloop( first ) )
|
||||
detect = 1;
|
||||
else if ( detect )
|
||||
break;
|
||||
}
|
||||
|
||||
return detect;
|
||||
}
|
||||
|
||||
/* greenloop -- loop up and down from green center. */
|
||||
static int
|
||||
greenloop( restart )
|
||||
int restart;
|
||||
{
|
||||
int detect;
|
||||
int g;
|
||||
int first;
|
||||
long txsqr = xsqr + xsqr;
|
||||
static int here, min, max;
|
||||
static long ginc, gxx, gcdist; /* "gc" variables maintain correct */
|
||||
static unsigned long *gcdp; /* values for bcenter position, */
|
||||
static unsigned char *gcrgbp; /* despite modifications by blueloop */
|
||||
/* to gdist, gdp, grgbp. */
|
||||
|
||||
if ( restart )
|
||||
{
|
||||
here = gcenter;
|
||||
min = 0;
|
||||
max = colormax - 1;
|
||||
ginc = cginc;
|
||||
}
|
||||
|
||||
detect = 0;
|
||||
|
||||
/* Basic loop up. */
|
||||
for ( g = here, gcdist = gdist = rdist, gxx = ginc,
|
||||
gcdp = gdp = rdp, gcrgbp = grgbp = rrgbp, first = 1;
|
||||
g <= max;
|
||||
g++, gdp += gstride, gcdp += gstride, grgbp += gstride, gcrgbp += gstride,
|
||||
gdist += gxx, gcdist += gxx, gxx += txsqr, first = 0 )
|
||||
{
|
||||
if ( blueloop( first ) )
|
||||
{
|
||||
if ( !detect )
|
||||
{
|
||||
/* Remember here and associated data! */
|
||||
if ( g > here )
|
||||
{
|
||||
here = g;
|
||||
rdp = gcdp;
|
||||
rrgbp = gcrgbp;
|
||||
rdist = gcdist;
|
||||
ginc = gxx;
|
||||
}
|
||||
detect = 1;
|
||||
}
|
||||
}
|
||||
else if ( detect )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic loop down. */
|
||||
for ( g = here - 1, gxx = ginc - txsqr, gcdist = gdist = rdist - gxx,
|
||||
gcdp = gdp = rdp - gstride, gcrgbp = grgbp = rrgbp - gstride,
|
||||
first = 1;
|
||||
g >= min;
|
||||
g--, gdp -= gstride, gcdp -= gstride, grgbp -= gstride, gcrgbp -= gstride,
|
||||
gxx -= txsqr, gdist -= gxx, gcdist -= gxx, first = 0 )
|
||||
{
|
||||
if ( blueloop( first ) )
|
||||
{
|
||||
if ( !detect )
|
||||
{
|
||||
/* Remember here! */
|
||||
here = g;
|
||||
rdp = gcdp;
|
||||
rrgbp = gcrgbp;
|
||||
rdist = gcdist;
|
||||
ginc = gxx;
|
||||
detect = 1;
|
||||
}
|
||||
}
|
||||
else if ( detect )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return detect;
|
||||
}
|
||||
|
||||
/* blueloop -- loop up and down from blue center. */
|
||||
static int
|
||||
blueloop( restart )
|
||||
int restart;
|
||||
{
|
||||
int detect;
|
||||
register unsigned long *dp;
|
||||
register unsigned char *rgbp;
|
||||
register long bdist, bxx;
|
||||
register int b, i = cindex;
|
||||
register long txsqr = xsqr + xsqr;
|
||||
register int lim;
|
||||
static int here, min, max;
|
||||
static long binc;
|
||||
|
||||
if ( restart )
|
||||
{
|
||||
here = bcenter;
|
||||
min = 0;
|
||||
max = colormax - 1;
|
||||
binc = cbinc;
|
||||
}
|
||||
|
||||
detect = 0;
|
||||
|
||||
/* Basic loop up. */
|
||||
/* First loop just finds first applicable cell. */
|
||||
for ( b = here, bdist = gdist, bxx = binc, dp = gdp, rgbp = grgbp, lim = max;
|
||||
b <= lim;
|
||||
b++, dp++, rgbp++,
|
||||
bdist += bxx, bxx += txsqr )
|
||||
{
|
||||
if ( *dp > bdist )
|
||||
{
|
||||
/* Remember new 'here' and associated data! */
|
||||
if ( b > here )
|
||||
{
|
||||
here = b;
|
||||
gdp = dp;
|
||||
grgbp = rgbp;
|
||||
gdist = bdist;
|
||||
binc = bxx;
|
||||
}
|
||||
detect = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Second loop fills in a run of closer cells. */
|
||||
for ( ;
|
||||
b <= lim;
|
||||
b++, dp++, rgbp++,
|
||||
bdist += bxx, bxx += txsqr )
|
||||
{
|
||||
if ( *dp > bdist )
|
||||
{
|
||||
*dp = bdist;
|
||||
*rgbp = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic loop down. */
|
||||
/* Do initializations here, since the 'find' loop might not get
|
||||
* executed.
|
||||
*/
|
||||
lim = min;
|
||||
b = here - 1;
|
||||
bxx = binc - txsqr;
|
||||
bdist = gdist - bxx;
|
||||
dp = gdp - 1;
|
||||
rgbp = grgbp - 1;
|
||||
/* The 'find' loop is executed only if we didn't already find
|
||||
* something.
|
||||
*/
|
||||
if ( !detect )
|
||||
for ( ;
|
||||
b >= lim;
|
||||
b--, dp--, rgbp--,
|
||||
bxx -= txsqr, bdist -= bxx )
|
||||
{
|
||||
if ( *dp > bdist )
|
||||
{
|
||||
/* Remember here! */
|
||||
/* No test for b against here necessary because b <
|
||||
* here by definition.
|
||||
*/
|
||||
here = b;
|
||||
gdp = dp;
|
||||
grgbp = rgbp;
|
||||
gdist = bdist;
|
||||
binc = bxx;
|
||||
detect = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* The 'update' loop. */
|
||||
for ( ;
|
||||
b >= lim;
|
||||
b--, dp--, rgbp--,
|
||||
bxx -= txsqr, bdist -= bxx )
|
||||
{
|
||||
if ( *dp > bdist )
|
||||
{
|
||||
*dp = bdist;
|
||||
*rgbp = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If we saw something, update the edge trackers. */
|
||||
|
||||
return detect;
|
||||
}
|
||||
|
||||
static void
|
||||
maxfill( buffer, side )
|
||||
unsigned long *buffer;
|
||||
long side;
|
||||
{
|
||||
register unsigned long maxv = ~0L;
|
||||
register long i;
|
||||
register unsigned long *bp;
|
||||
|
||||
for ( i = side * side * side, bp = buffer;
|
||||
i > 0;
|
||||
i--, bp++ )
|
||||
*bp = maxv;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.io;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
|
||||
/**
|
||||
* FileLockingTest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: FileLockingTest.java,v 1.0 May 12, 2009 7:15:38 PM haraldk Exp$
|
||||
*/
|
||||
public class FileLockingTest {
|
||||
public static void main(final String[] pArgs) throws IOException {
|
||||
FileChannel channel = new RandomAccessFile(pArgs[0], "rw").getChannel();
|
||||
FileLock lock = channel.tryLock(0, Long.MAX_VALUE, pArgs.length <= 1 || !"false".equalsIgnoreCase(pArgs[1])); // Shared lock for entire file
|
||||
|
||||
System.out.println("lock: " + lock);
|
||||
|
||||
if (lock != null) {
|
||||
System.in.read();
|
||||
|
||||
InputStream stream = Channels.newInputStream(channel);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.out.println("Already locked");
|
||||
}
|
||||
}
|
||||
}
|
||||
57
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/io/FileMonitor.java
Executable file
57
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/io/FileMonitor.java
Executable file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.io;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Allows monitoring a file on the file system.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: FileMonitor.java,v 1.0 May 12, 2009 6:58:55 PM haraldk Exp$
|
||||
*/
|
||||
public class FileMonitor {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Listens for changes to a file.
|
||||
*
|
||||
*/
|
||||
public interface FileChangeListener {
|
||||
|
||||
public void fileCreated(File pFile) throws Exception; // TODO: Is this a good thing?
|
||||
|
||||
public void fileUpdated(File pFile) throws Exception;
|
||||
|
||||
public void fileDeleted(File pFile) throws Exception;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,8 +46,8 @@ import java.util.zip.Deflater;
|
||||
*/
|
||||
final class DeflateEncoder implements Encoder {
|
||||
|
||||
private final Deflater mDeflater;
|
||||
private final byte[] mBuffer = new byte[1024];
|
||||
private final Deflater deflater;
|
||||
private final byte[] buffer = new byte[1024];
|
||||
|
||||
public DeflateEncoder() {
|
||||
// this(new Deflater());
|
||||
@@ -59,32 +59,32 @@ final class DeflateEncoder implements Encoder {
|
||||
throw new IllegalArgumentException("deflater == null");
|
||||
}
|
||||
|
||||
mDeflater = pDeflater;
|
||||
deflater = pDeflater;
|
||||
}
|
||||
|
||||
public void encode(final OutputStream pStream, final byte[] pBuffer, final int pOffset, final int pLength)
|
||||
throws IOException
|
||||
{
|
||||
System.out.println("DeflateEncoder.encode");
|
||||
mDeflater.setInput(pBuffer, pOffset, pLength);
|
||||
deflater.setInput(pBuffer, pOffset, pLength);
|
||||
flushInputToStream(pStream);
|
||||
}
|
||||
|
||||
private void flushInputToStream(final OutputStream pStream) throws IOException {
|
||||
System.out.println("DeflateEncoder.flushInputToStream");
|
||||
|
||||
if (mDeflater.needsInput()) {
|
||||
if (deflater.needsInput()) {
|
||||
System.out.println("Foo");
|
||||
}
|
||||
|
||||
while (!mDeflater.needsInput()) {
|
||||
int deflated = mDeflater.deflate(mBuffer, 0, mBuffer.length);
|
||||
pStream.write(mBuffer, 0, deflated);
|
||||
while (!deflater.needsInput()) {
|
||||
int deflated = deflater.deflate(buffer, 0, buffer.length);
|
||||
pStream.write(buffer, 0, deflated);
|
||||
System.out.println("flushed " + deflated);
|
||||
}
|
||||
}
|
||||
|
||||
// public void flush() {
|
||||
// mDeflater.finish();
|
||||
// deflater.finish();
|
||||
// }
|
||||
}
|
||||
@@ -49,9 +49,9 @@ import java.util.zip.Inflater;
|
||||
*/
|
||||
final class InflateDecoder implements Decoder {
|
||||
|
||||
private final Inflater mInflater;
|
||||
private final Inflater inflater;
|
||||
|
||||
private final byte[] mBuffer;
|
||||
private final byte[] buffer;
|
||||
|
||||
/**
|
||||
* Creates an {@code InflateDecoder}
|
||||
@@ -71,20 +71,20 @@ final class InflateDecoder implements Decoder {
|
||||
throw new IllegalArgumentException("inflater == null");
|
||||
}
|
||||
|
||||
mInflater = pInflater;
|
||||
mBuffer = new byte[1024];
|
||||
inflater = pInflater;
|
||||
buffer = new byte[1024];
|
||||
}
|
||||
|
||||
public int decode(final InputStream pStream, final byte[] pBuffer) throws IOException {
|
||||
try {
|
||||
int decoded;
|
||||
|
||||
while ((decoded = mInflater.inflate(pBuffer, 0, pBuffer.length)) == 0) {
|
||||
if (mInflater.finished() || mInflater.needsDictionary()) {
|
||||
while ((decoded = inflater.inflate(pBuffer, 0, pBuffer.length)) == 0) {
|
||||
if (inflater.finished() || inflater.needsDictionary()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mInflater.needsInput()) {
|
||||
if (inflater.needsInput()) {
|
||||
fill(pStream);
|
||||
}
|
||||
}
|
||||
@@ -98,12 +98,12 @@ final class InflateDecoder implements Decoder {
|
||||
}
|
||||
|
||||
private void fill(final InputStream pStream) throws IOException {
|
||||
int available = pStream.read(mBuffer, 0, mBuffer.length);
|
||||
int available = pStream.read(buffer, 0, buffer.length);
|
||||
|
||||
if (available == -1) {
|
||||
throw new EOFException("Unexpected end of ZLIB stream");
|
||||
}
|
||||
|
||||
mInflater.setInput(mBuffer, 0, available);
|
||||
inflater.setInput(buffer, 0, available);
|
||||
}
|
||||
}
|
||||
468
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/lang/DuckType.java
Executable file
468
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/lang/DuckType.java
Executable file
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <20>If it walks like a duck, looks like a duck, quacks like a duck, it must be<62><65>.
|
||||
* <p/>
|
||||
* Based on an idea found at
|
||||
* <a href="http://www.coconut-palm-software.com/the_visual_editor/?p=25">The Visual Editor</a>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/lang/DuckType.java#1 $
|
||||
*
|
||||
* @see java.lang.reflect.Proxy
|
||||
*/
|
||||
public final class DuckType {
|
||||
/*
|
||||
EXAMPLE:
|
||||
public ImageMgr(Object receiver, Image image) {
|
||||
if (!DuckType.instanceOf(IImageHolder.class, receiver)) {
|
||||
throw new ClassCastException("Cannot implement IImageHolder");
|
||||
}
|
||||
|
||||
this.image = image;
|
||||
|
||||
IImageHolder imageHolder = (IImageHolder) DuckType.implement(IImageHolder.class, receiver);
|
||||
imageHolder.setImage(image);
|
||||
imageHolder.addDisposeListener(this);
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: Implement some weak caching of proxy classes and instances
|
||||
// TODO: Make the proxy classes serializable...
|
||||
|
||||
private DuckType() {}
|
||||
|
||||
public static boolean instanceOf(Class pInterface, Object pObject) {
|
||||
return instanceOf(new Class[] {pInterface}, new Object[] {pObject});
|
||||
}
|
||||
|
||||
public static boolean instanceOf(Class[] pInterfaces, Object pObject) {
|
||||
return instanceOf(pInterfaces, new Object[] {pObject});
|
||||
}
|
||||
|
||||
public static boolean instanceOf(final Class[] pInterfaces, final Object[] pObjects) {
|
||||
// Get all methods of all Class in pInterfaces, and see if pObjects has
|
||||
// matching implementations
|
||||
|
||||
// TODO: Possible optimization: If any of the interfaces are implemented
|
||||
// by one of the objects' classes, we don't need to find every method...
|
||||
|
||||
for (int i = 0; i < pInterfaces.length; i++) {
|
||||
Class interfce = pInterfaces[i];
|
||||
|
||||
Method[] methods = interfce.getMethods();
|
||||
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
Method method = methods[j];
|
||||
|
||||
//if (findMethodImplementation(method, getClasses(pObjects)) < 0) {
|
||||
//if (findMethodImplementation(method, getClasses(pObjects)) == null) {
|
||||
if (findMethodImplementation(method, pObjects) == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Might be moved to ReflectUtil
|
||||
private static Class[] getClasses(final Object[] pObjects) {
|
||||
Class[] classes = new Class[pObjects.length];
|
||||
|
||||
for (int i = 0; i < pObjects.length; i++) {
|
||||
classes[i] = pObjects[i].getClass();
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a class that has a method maching the given signature.
|
||||
* Returns the index of the class in the {@code pClasses} array that has a
|
||||
* matching method.
|
||||
* If there is more than one class that has a matching method the first
|
||||
* index will be returned.
|
||||
* If there is no match in any of the classes, {@code -1} is returned.
|
||||
*
|
||||
* @param pMethod
|
||||
* @param pObjects
|
||||
*
|
||||
* @return the first index of the object in the {@code pObjects} array that
|
||||
* has a matching method, or {@code -1} if none was found.
|
||||
*/
|
||||
// TODO: Might be moved to ReflectUtil
|
||||
//static int findMethodImplementation(final Method pMethod, final Class[] pClasses) {
|
||||
static MethodProxy findMethodImplementation(final Method pMethod, final Object[] pObjects) {
|
||||
// TODO: Optimization: Each getParameterTypes() invokation creates a
|
||||
// new clone of the array. If we do it once and store the refs, that
|
||||
// would be a good idea
|
||||
|
||||
// Optimization, don't test class more than once
|
||||
Set tested = new HashSet(pObjects.length);
|
||||
|
||||
for (int i = 0; i < pObjects.length; i++) {
|
||||
Class cls = pObjects[i].getClass();
|
||||
|
||||
if (tested.contains(cls)) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
tested.add(cls);
|
||||
}
|
||||
|
||||
try {
|
||||
// NOTE: This test might be too restrictive
|
||||
// We could actually go ahead with
|
||||
// supertype parameters or subtype return types...
|
||||
// However, we should only do that after we have tried all
|
||||
// classes for direct mathces.
|
||||
Method method = cls.getMethod(pMethod.getName(),
|
||||
pMethod.getParameterTypes());
|
||||
|
||||
if (matches(pMethod, method)) {
|
||||
//return i;
|
||||
// TODO: This is a waste of time if we are only testing if there's a method here...
|
||||
return new MethodProxy(method, pObjects[i]);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
// Ingore
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSuperTypes(pMethod.getParameterTypes())) {
|
||||
SortedSet uniqueMethods = new TreeSet();
|
||||
for (int i = 0; i < pObjects.length; i++) {
|
||||
Class cls = pObjects[i].getClass();
|
||||
|
||||
Method[] methods = cls.getMethods();
|
||||
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
Method method = methods[j];
|
||||
|
||||
// Now, for each method
|
||||
// 1 test if the name matches
|
||||
// 2 test if the parameter types match for superclass
|
||||
// 3 Test return types for assignability?
|
||||
if (pMethod.getName().equals(method.getName())
|
||||
&& isAssignableFrom(method.getParameterTypes(), pMethod.getParameterTypes())
|
||||
&& pMethod.getReturnType().isAssignableFrom(method.getReturnType())) {
|
||||
// 4 TODO: How to find the most specific match?!
|
||||
//return new MethodProxy(method, pObjects[i]);
|
||||
uniqueMethods.add(new MethodProxy(method, pObjects[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uniqueMethods.size() == 1) {
|
||||
return (MethodProxy) uniqueMethods.first();
|
||||
}
|
||||
else {
|
||||
// TODO: We need to figure out what method is the best match..
|
||||
}
|
||||
}
|
||||
|
||||
//return -1;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isAssignableFrom(Class[] pTypes, Class[] pSubTypes) {
|
||||
if (pTypes.length != pSubTypes.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pTypes.length; i++) {
|
||||
if (!pTypes[i].isAssignableFrom(pSubTypes[i])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean hasSuperTypes(Class[] pParameterTypes) {
|
||||
for (int i = 0; i < pParameterTypes.length; i++) {
|
||||
Class type = pParameterTypes[i];
|
||||
|
||||
if (type != Object.class
|
||||
&& (type.isInterface() || type.getSuperclass() != null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests two {@code Method}s for match.
|
||||
* That is, they have same name and equal parameters.
|
||||
*
|
||||
* @param pLeft
|
||||
* @param pRight
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @see Method#equals(Object)
|
||||
*/
|
||||
private static boolean matches(Method pLeft, Method pRight) {
|
||||
if (pLeft == pRight) {
|
||||
return true;
|
||||
}
|
||||
else if (pLeft.getName().equals(pRight.getName())
|
||||
&& pLeft.getReturnType().isAssignableFrom(pRight.getReturnType())) {
|
||||
|
||||
// Avoid unnecessary cloning
|
||||
Class[] params1 = pLeft.getParameterTypes();
|
||||
Class[] params2 = pRight.getParameterTypes();
|
||||
if (params1.length == params2.length) {
|
||||
for (int i = 0; i < params1.length; i++) {
|
||||
if (params1[i] != params2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Object implement(Class pInterface, Object pObject) throws NoMatchingMethodException {
|
||||
return implement(new Class[] {pInterface}, new Object[] {pObject}, false);
|
||||
}
|
||||
|
||||
public static Object implement(Class[] pInterfaces, Object pObject) throws NoMatchingMethodException {
|
||||
return implement(pInterfaces, new Object[] {pObject}, false);
|
||||
}
|
||||
|
||||
// TODO: What about the interfaces pObjects allready implements?
|
||||
// TODO: Use first object as "identity"? Allow user to supply "indentity"
|
||||
// that is not exposed as part of the implemented interfaces?
|
||||
public static Object implement(final Class[] pInterfaces, final Object[] pObjects) throws NoMatchingMethodException {
|
||||
return implement(pInterfaces, pObjects, false);
|
||||
}
|
||||
|
||||
public static Object implement(final Class[] pInterfaces, final Object[] pObjects, boolean pStubAbstract) throws NoMatchingMethodException {
|
||||
Map delegates = new HashMap(pObjects.length * 10);
|
||||
|
||||
for (int i = 0; i < pInterfaces.length; i++) {
|
||||
Class interfce = pInterfaces[i];
|
||||
|
||||
Method[] methods = interfce.getMethods();
|
||||
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
Method method = methods[j];
|
||||
|
||||
//int idx = findMethodImplementation(method, getClasses(pObjects));
|
||||
//Method impl = findMethodImplementation(method, getClasses(pObjects));
|
||||
MethodProxy impl = findMethodImplementation(method, pObjects);
|
||||
//if (idx < 0) {
|
||||
if (impl == null) {
|
||||
// TODO: Maybe optionally create stubs that fails when invoked?!
|
||||
if (pStubAbstract) {
|
||||
impl = MethodProxy.createAbstract(method);
|
||||
}
|
||||
else {
|
||||
throw new NoMatchingMethodException(interfce.getName() + "."
|
||||
+ method.getName()
|
||||
+ parameterTypesToString(method.getParameterTypes()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!delegates.containsKey(method)) {
|
||||
// TODO: Must find the correct object...
|
||||
//delegates.put(method, new MethodProxy(method, pObjects[idx]));
|
||||
delegates.put(method, impl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: It's probably not good enough to use the current context class loader
|
||||
// TODO: Either let user specify classloader directly
|
||||
// TODO: ...or use one of the classloaders from pInterfaces or pObjects
|
||||
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
|
||||
pInterfaces, new DelegationHandler(delegates));
|
||||
}
|
||||
|
||||
private static String parameterTypesToString(Class[] pTypes) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("(");
|
||||
if (pTypes != null) {
|
||||
for (int i = 0; i < pTypes.length; i++) {
|
||||
if (i > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
Class c = pTypes[i];
|
||||
buf.append((c == null) ? "null" : c.getName());
|
||||
}
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
static class MethodProxy {
|
||||
private final Method mMethod;
|
||||
private final Object mDelegate;
|
||||
|
||||
private final static Object ABSTRACT_METHOD_DELEGATE = new Object() {
|
||||
};
|
||||
|
||||
public static MethodProxy createAbstract(Method pMethod) {
|
||||
return new MethodProxy(pMethod, ABSTRACT_METHOD_DELEGATE) {
|
||||
public Object invoke(Object[] pArguments) throws Throwable {
|
||||
throw abstractMehthodError();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public MethodProxy(Method pMethod, Object pDelegate) {
|
||||
if (pMethod == null) {
|
||||
throw new IllegalArgumentException("method == null");
|
||||
}
|
||||
if (pDelegate == null) {
|
||||
throw new IllegalArgumentException("delegate == null");
|
||||
}
|
||||
|
||||
mMethod = pMethod;
|
||||
mDelegate = pDelegate;
|
||||
}
|
||||
|
||||
public Object invoke(Object[] pArguments) throws Throwable {
|
||||
try {
|
||||
return mMethod.invoke(mDelegate, pArguments);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new Error(e); // This is an error in the impl
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
Error abstractMehthodError() {
|
||||
return new AbstractMethodError(mMethod.toString());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return mMethod.hashCode() ^ mDelegate.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object pOther) {
|
||||
if (pOther == this) {
|
||||
return true;
|
||||
}
|
||||
if (pOther instanceof MethodProxy) {
|
||||
MethodProxy other = (MethodProxy) pOther;
|
||||
return mMethod.equals(other.mMethod) && mDelegate.equals(other.mDelegate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return mMethod.toString() + mDelegate.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class NoMatchingMethodException extends IllegalArgumentException {
|
||||
public NoMatchingMethodException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NoMatchingMethodException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public NoMatchingMethodException(Exception e) {
|
||||
super(e.getMessage());
|
||||
initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Must handle identity...
|
||||
// TODO: equals/hashCode
|
||||
// TODO: Allow clients to pass in Identity subclasses?
|
||||
private static class DelegationHandler implements InvocationHandler {
|
||||
private final Map mDelegates;
|
||||
|
||||
public DelegationHandler(Map pDelegates) {
|
||||
mDelegates = pDelegates;
|
||||
}
|
||||
|
||||
public final Object invoke(Object pProxy, Method pMethod, Object[] pArguments)
|
||||
throws Throwable
|
||||
{
|
||||
if (pMethod.getDeclaringClass() == Object.class) {
|
||||
// Intercept equals/hashCode/toString
|
||||
String name = pMethod.getName();
|
||||
if (name.equals("equals")) {
|
||||
return proxyEquals(pProxy, pArguments[0]);
|
||||
}
|
||||
else if (name.equals("hashCode")) {
|
||||
return proxyHashCode(pProxy);
|
||||
}
|
||||
else if (name.equals("toString")) {
|
||||
return proxyToString(pProxy);
|
||||
}
|
||||
|
||||
// Other methods are handled by their default Object
|
||||
// implementations
|
||||
return pMethod.invoke(this, pArguments);
|
||||
}
|
||||
|
||||
MethodProxy mp = (MethodProxy) mDelegates.get(pMethod);
|
||||
|
||||
return mp.invoke(pArguments);
|
||||
}
|
||||
|
||||
protected Integer proxyHashCode(Object pProxy) {
|
||||
//return new Integer(System.identityHashCode(pProxy));
|
||||
return new Integer(mDelegates.hashCode());
|
||||
}
|
||||
|
||||
protected Boolean proxyEquals(Object pProxy, Object pOther) {
|
||||
return pProxy == pOther ||
|
||||
(Proxy.isProxyClass(pOther.getClass())
|
||||
&& Proxy.getInvocationHandler(pOther) instanceof DelegationHandler
|
||||
&& ((DelegationHandler) Proxy.getInvocationHandler(pOther)).mDelegates.equals(mDelegates))
|
||||
? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
protected String proxyToString(Object pProxy) {
|
||||
return pProxy.getClass().getName() + '@' +
|
||||
Integer.toHexString(pProxy.hashCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
/**
|
||||
* ExceptionUtil
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/lang/ExceptionUtil.java#2 $
|
||||
*/
|
||||
public final class ExceptionUtil {
|
||||
|
||||
/**
|
||||
* Re-throws an exception, either as-is if the exception was already unchecked, otherwise wrapped in
|
||||
* a {@link RuntimeException} subtype.
|
||||
* "Expected" exception types are wrapped in {@link RuntimeException}s directly, while
|
||||
* "unexpected" exception types are wrapped in {@link java.lang.reflect.UndeclaredThrowableException}s.
|
||||
*
|
||||
* @param pThrowable the exception to launder
|
||||
* @param pExpectedTypes the types of exception the code is expected to throw
|
||||
*/
|
||||
/*public*/ static void launder(final Throwable pThrowable, Class<? extends Throwable>... pExpectedTypes) {
|
||||
if (pThrowable instanceof Error) {
|
||||
throw (Error) pThrowable;
|
||||
}
|
||||
if (pThrowable instanceof RuntimeException) {
|
||||
throw (RuntimeException) pThrowable;
|
||||
}
|
||||
|
||||
for (Class<? extends Throwable> expectedType : pExpectedTypes) {
|
||||
if (expectedType.isInstance(pThrowable)) {
|
||||
throw new RuntimeException(pThrowable);
|
||||
}
|
||||
}
|
||||
|
||||
throw new UndeclaredThrowableException(pThrowable);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "UnusedDeclaration"})
|
||||
static <T extends Throwable> void throwAs(final Class<T> pType, final Throwable pThrowable) throws T {
|
||||
throw (T) pThrowable;
|
||||
}
|
||||
|
||||
public static void throwUnchecked(final Throwable pThrowable) {
|
||||
throwAs(RuntimeException.class, pThrowable);
|
||||
}
|
||||
|
||||
/*@SafeVarargs*/
|
||||
@SuppressWarnings({"unchecked", "varargs"})
|
||||
/*public*/ static void handle(final Throwable pThrowable, final ThrowableHandler<? extends Throwable>... pHandlers) {
|
||||
handleImpl(pThrowable, (ThrowableHandler<Throwable>[]) pHandlers);
|
||||
}
|
||||
|
||||
private static void handleImpl(final Throwable pThrowable, final ThrowableHandler<Throwable>... pHandlers) {
|
||||
// TODO: Sort more specific throwable handlers before less specific?
|
||||
for (ThrowableHandler<Throwable> handler : pHandlers) {
|
||||
if (handler.handles(pThrowable)) {
|
||||
handler.handle(pThrowable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Not handled, re-throw
|
||||
throwUnchecked(pThrowable);
|
||||
}
|
||||
|
||||
public static abstract class ThrowableHandler<T extends Throwable> {
|
||||
private final Class<? extends T>[] throwables;
|
||||
|
||||
protected ThrowableHandler(final Class<? extends T>... pThrowables) {
|
||||
throwables = notNull(pThrowables).clone();
|
||||
}
|
||||
|
||||
final public boolean handles(final Throwable pThrowable) {
|
||||
for (Class<? extends T> throwable : throwables) {
|
||||
if (throwable.isAssignableFrom(pThrowable.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void handle(T pThrowable);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
/**
|
||||
* MostUnfortunateException
|
||||
* <p/>
|
||||
*
|
||||
* @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/MostUnfortunateException.java#1 $
|
||||
*/
|
||||
class MostUnfortunateException extends RuntimeException {
|
||||
public MostUnfortunateException() {
|
||||
this("Most unfortunate.");
|
||||
}
|
||||
|
||||
public MostUnfortunateException(Throwable pCause) {
|
||||
this(pCause.getMessage(), pCause);
|
||||
}
|
||||
|
||||
public MostUnfortunateException(String pMessage, Throwable pCause) {
|
||||
this(pMessage);
|
||||
initCause(pCause);
|
||||
}
|
||||
|
||||
public MostUnfortunateException(String pMessage) {
|
||||
super("A most unfortunate exception has occured: " + pMessage);
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
/**
|
||||
* MostUnfortunateException
|
||||
* <p/>
|
||||
*
|
||||
* @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/MostUnfortunateException.java#1 $
|
||||
*/
|
||||
class MostUnfortunateException extends RuntimeException {
|
||||
public MostUnfortunateException() {
|
||||
this("Most unfortunate.");
|
||||
}
|
||||
|
||||
public MostUnfortunateException(Throwable pCause) {
|
||||
this(pCause.getMessage(), pCause);
|
||||
}
|
||||
|
||||
public MostUnfortunateException(String pMessage, Throwable pCause) {
|
||||
this(pMessage);
|
||||
initCause(pCause);
|
||||
}
|
||||
|
||||
public MostUnfortunateException(String pMessage) {
|
||||
super("A most unfortunate exception has occured: " + pMessage);
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,8 @@ import com.twelvemonkeys.util.FilterIterator;
|
||||
import com.twelvemonkeys.util.service.ServiceRegistry;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* NativeLoader
|
||||
@@ -182,6 +182,7 @@ final class NativeLoader {
|
||||
Iterator<NativeResourceSPI> providers = sRegistry.providers(pLibrary);
|
||||
while (providers.hasNext()) {
|
||||
NativeResourceSPI resourceSPI = providers.next();
|
||||
|
||||
try {
|
||||
return resourceSPI.getClassPathResource(Platform.get());
|
||||
}
|
||||
@@ -372,27 +373,29 @@ final class NativeLoader {
|
||||
|
||||
private static class NativeResourceRegistry extends ServiceRegistry {
|
||||
public NativeResourceRegistry() {
|
||||
super(Arrays.asList(NativeResourceSPI.class).iterator());
|
||||
super(Collections.singletonList(NativeResourceSPI.class).iterator());
|
||||
registerApplicationClasspathSPIs();
|
||||
}
|
||||
|
||||
Iterator<NativeResourceSPI> providers(String pNativeResource) {
|
||||
return new FilterIterator<NativeResourceSPI>(providers(NativeResourceSPI.class),
|
||||
new NameFilter(pNativeResource));
|
||||
Iterator<NativeResourceSPI> providers(final String nativeResource) {
|
||||
return new FilterIterator<NativeResourceSPI>(
|
||||
providers(NativeResourceSPI.class),
|
||||
new NameFilter(nativeResource)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NameFilter implements FilterIterator.Filter<NativeResourceSPI> {
|
||||
private final String mName;
|
||||
private final String name;
|
||||
|
||||
NameFilter(String pName) {
|
||||
if (pName == null) {
|
||||
throw new IllegalArgumentException("name == null");
|
||||
}
|
||||
mName = pName;
|
||||
name = pName;
|
||||
}
|
||||
public boolean accept(NativeResourceSPI pElement) {
|
||||
return mName.equals(pElement.getResourceName());
|
||||
return name.equals(pElement.getResourceName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
/**
|
||||
* Abstract base class for native reource providers to iplement.
|
||||
* <p/>
|
||||
*
|
||||
* @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/NativeResourceSPI.java#1 $
|
||||
*/
|
||||
public abstract class NativeResourceSPI {
|
||||
|
||||
private final String mResourceName;
|
||||
|
||||
/**
|
||||
* Creates a {@code NativeResourceSPI} with the given name.
|
||||
*
|
||||
* The name will typically be a short string, with the common name of the
|
||||
* library that is provided, like "JMagick", "JOGL" or similar.
|
||||
*
|
||||
* @param pResourceName name of the resource (native library) provided by
|
||||
* this SPI.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code pResourceName == null}
|
||||
*/
|
||||
protected NativeResourceSPI(String pResourceName) {
|
||||
if (pResourceName == null) {
|
||||
throw new IllegalArgumentException("resourceName == null");
|
||||
}
|
||||
|
||||
mResourceName = pResourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the resource (native library) provided by this SPI.
|
||||
*
|
||||
* The name will typically be a short string, with the common name of the
|
||||
* library that is provided, like "JMagick", "JOGL" or similar.
|
||||
* <p/>
|
||||
* NOTE: This method is intended for the SPI framework, and should not be
|
||||
* invoked by client code.
|
||||
*
|
||||
* @return the name of the resource provided by this SPI
|
||||
*/
|
||||
public final String getResourceName() {
|
||||
return mResourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the classpath resource that is suited for the given
|
||||
* runtime configuration.
|
||||
* <p/>
|
||||
* In the common case, the {@code pPlatform} parameter is
|
||||
* normalized from the values found in
|
||||
* {@code System.getProperty("os.name")} and
|
||||
* {@code System.getProperty("os.arch")}.
|
||||
* For unknown operating systems and architectures, {@code toString()} on
|
||||
* the platforms's properties will return the the same value as these properties.
|
||||
* <p/>
|
||||
* NOTE: This method is intended for the SPI framework, and should not be
|
||||
* invoked by client code.
|
||||
*
|
||||
* @param pPlatform the current platform
|
||||
* @return a {@code String} containing the path to a classpath resource or
|
||||
* {@code null} if no resource is available.
|
||||
*
|
||||
* @see com.twelvemonkeys.lang.Platform.OperatingSystem
|
||||
* @see com.twelvemonkeys.lang.Platform.Architecture
|
||||
* @see System#getProperties()
|
||||
*/
|
||||
public abstract String getClassPathResource(final Platform pPlatform);
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
/**
|
||||
* Abstract base class for native reource providers to iplement.
|
||||
* <p/>
|
||||
*
|
||||
* @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/NativeResourceSPI.java#1 $
|
||||
*/
|
||||
public abstract class NativeResourceSPI {
|
||||
|
||||
private final String mResourceName;
|
||||
|
||||
/**
|
||||
* Creates a {@code NativeResourceSPI} with the given name.
|
||||
*
|
||||
* The name will typically be a short string, with the common name of the
|
||||
* library that is provided, like "JMagick", "JOGL" or similar.
|
||||
*
|
||||
* @param pResourceName name of the resource (native library) provided by
|
||||
* this SPI.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code pResourceName == null}
|
||||
*/
|
||||
protected NativeResourceSPI(String pResourceName) {
|
||||
if (pResourceName == null) {
|
||||
throw new IllegalArgumentException("resourceName == null");
|
||||
}
|
||||
|
||||
mResourceName = pResourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the resource (native library) provided by this SPI.
|
||||
*
|
||||
* The name will typically be a short string, with the common name of the
|
||||
* library that is provided, like "JMagick", "JOGL" or similar.
|
||||
* <p/>
|
||||
* NOTE: This method is intended for the SPI framework, and should not be
|
||||
* invoked by client code.
|
||||
*
|
||||
* @return the name of the resource provided by this SPI
|
||||
*/
|
||||
public final String getResourceName() {
|
||||
return mResourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the classpath resource that is suited for the given
|
||||
* runtime configuration.
|
||||
* <p/>
|
||||
* In the common case, the {@code pPlatform} parameter is
|
||||
* normalized from the values found in
|
||||
* {@code System.getProperty("os.name")} and
|
||||
* {@code System.getProperty("os.arch")}.
|
||||
* For unknown operating systems and architectures, {@code toString()} on
|
||||
* the platforms's properties will return the the same value as these properties.
|
||||
* <p/>
|
||||
* NOTE: This method is intended for the SPI framework, and should not be
|
||||
* invoked by client code.
|
||||
*
|
||||
* @param pPlatform the current platform
|
||||
* @return a {@code String} containing the path to a classpath resource or
|
||||
* {@code null} if no resource is available.
|
||||
*
|
||||
* @see com.twelvemonkeys.lang.Platform.OperatingSystem
|
||||
* @see com.twelvemonkeys.lang.Platform.Architecture
|
||||
* @see System#getProperties()
|
||||
*/
|
||||
public abstract String getClassPathResource(final Platform pPlatform);
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
import com.twelvemonkeys.lang.SystemUtil;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A class that holds a JDBC Connection. The class can be configured by a
|
||||
* properties file. However, the approach is rather lame, and only lets you
|
||||
* configure one connection...
|
||||
* <P/>
|
||||
* Tested with jConnect (Sybase), I-net Sprinta2000 (MS SQL) and Oracle.
|
||||
* <P/>
|
||||
* @todo be able to register more drivers, trough properties and runtime
|
||||
* @todo be able to register more connections, trough properties and runtime
|
||||
* <P/>
|
||||
* <STRONG>Example properties file</STRONG></BR>
|
||||
* # filename: com.twelvemonkeys.sql.DatabaseConnection.properties
|
||||
* driver=com.inet.tds.TdsDriver
|
||||
* url=jdbc:inetdae7:127.0.0.1:1433?database\=mydb
|
||||
* user=scott
|
||||
* password=tiger
|
||||
* # What do you expect, really?
|
||||
* logDebug=true
|
||||
*
|
||||
* @author Philippe B<>al (phbe@iconmedialab.no)
|
||||
* @author Harald Kuhr (haraldk@iconmedialab.no)
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sql/DatabaseConnection.java#1 $
|
||||
*
|
||||
* @todo Use org.apache.commons.logging instead of proprietary logging.
|
||||
*
|
||||
*/
|
||||
|
||||
public class DatabaseConnection {
|
||||
|
||||
// Default driver
|
||||
public final static String DEFAULT_DRIVER = "NO_DRIVER";
|
||||
// Default URL
|
||||
public final static String DEFAULT_URL = "NO_URL";
|
||||
|
||||
protected static String mDriver = null;
|
||||
protected static String mUrl = null;
|
||||
|
||||
// Default debug is true
|
||||
// private static boolean debug = true;
|
||||
|
||||
protected static Properties mConfig = null;
|
||||
//protected static Log mLog = null;
|
||||
protected static Log mLog = null;
|
||||
|
||||
protected static boolean mInitialized = false;
|
||||
|
||||
// Must be like this...
|
||||
// http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html :-)
|
||||
private static DatabaseConnection sInstance = new DatabaseConnection();
|
||||
|
||||
/**
|
||||
* Creates the DatabaseConnection.
|
||||
*/
|
||||
|
||||
private DatabaseConnection() {
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single DatabaseConnection instance.
|
||||
*/
|
||||
|
||||
protected static DatabaseConnection getInstance() {
|
||||
/*
|
||||
if (sInstance == null) {
|
||||
sInstance = new DatabaseConnection();
|
||||
sInstance.init();
|
||||
}
|
||||
*/
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the DatabaseConnection, called from the constructor.
|
||||
*
|
||||
* @exception IllegalStateException if an attempt to call init() is made
|
||||
* after the instance is allready initialized.
|
||||
*/
|
||||
|
||||
protected synchronized void init() {
|
||||
// Make sure init is executed only once!
|
||||
if (mInitialized) {
|
||||
throw new IllegalStateException("init() may only be called once!");
|
||||
}
|
||||
|
||||
mInitialized = true;
|
||||
|
||||
try {
|
||||
mConfig = SystemUtil.loadProperties(DatabaseConnection.class);
|
||||
}
|
||||
catch (FileNotFoundException fnf) {
|
||||
// Ignore
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
//LogFactory.getLog(getClass()).error("Caught IOException: ", ioe);
|
||||
new Log(this).logError(ioe);
|
||||
//ioe.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
if (mConfig == null) {
|
||||
mConfig = new Properties();
|
||||
}
|
||||
}
|
||||
|
||||
mLog = new Log(this, mConfig);
|
||||
//mLog = LogFactory.getLog(getClass());
|
||||
// debug = new Boolean(config.getProperty("debug", "true")).booleanValue();
|
||||
// config.list(System.out);
|
||||
|
||||
mDriver = mConfig.getProperty("driver", DEFAULT_DRIVER);
|
||||
mUrl = mConfig.getProperty("url", DEFAULT_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default JDBC Connection. The connection is configured through
|
||||
* the properties file.
|
||||
*
|
||||
* @return the default jdbc Connection
|
||||
*/
|
||||
|
||||
public static Connection getConnection() {
|
||||
return getConnection(null, null, getInstance().mUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a JDBC Connection with the given parameters. The connection is
|
||||
* configured through the properties file.
|
||||
*
|
||||
* @param pUser the database user name
|
||||
* @param pPassword the password of the database user
|
||||
* @param pURL the url to connect to
|
||||
*
|
||||
* @return a jdbc Connection
|
||||
*/
|
||||
|
||||
public static Connection getConnection(String pUser,
|
||||
String pPassword,
|
||||
String pURL) {
|
||||
return getInstance().getConnectionInstance(pUser, pPassword, pURL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a JDBC Connection with the given parameters. The connection is
|
||||
* configured through the properties file.
|
||||
*
|
||||
* @param pUser the database user name
|
||||
* @param pPassword the password of the database user
|
||||
* @param pURL the url to connect to
|
||||
*
|
||||
* @return a jdbc Connection
|
||||
*/
|
||||
|
||||
protected Connection getConnectionInstance(String pUser,
|
||||
String pPassword,
|
||||
String pURL) {
|
||||
Properties props = (Properties) mConfig.clone();
|
||||
|
||||
if (pUser != null) {
|
||||
props.put("user", pUser);
|
||||
}
|
||||
if (pPassword != null) {
|
||||
props.put("password", pPassword);
|
||||
}
|
||||
|
||||
// props.list(System.out);
|
||||
|
||||
try {
|
||||
// Load & register the JDBC Driver
|
||||
if (!DEFAULT_DRIVER.equals(mDriver)) {
|
||||
Class.forName(mDriver).newInstance();
|
||||
}
|
||||
|
||||
Connection conn = DriverManager.getConnection(pURL, props);
|
||||
|
||||
if (mLog.getLogDebug()) {
|
||||
//if (mLog.isDebugEnabled()) {
|
||||
DatabaseMetaData dma = conn.getMetaData();
|
||||
mLog.logDebug("Connected to " + dma.getURL());
|
||||
mLog.logDebug("Driver " + dma.getDriverName());
|
||||
mLog.logDebug("Version " + dma.getDriverVersion());
|
||||
|
||||
//mLog.debug("Connected to " + dma.getURL());
|
||||
//mLog.debug("Driver " + dma.getDriverName());
|
||||
//mLog.debug("Version " + dma.getDriverVersion());
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
catch (Exception e) {
|
||||
mLog.logError(e.getMessage());
|
||||
|
||||
// Get chained excpetions
|
||||
if (e instanceof SQLException) {
|
||||
SQLException sqle = (SQLException) e;
|
||||
while ((sqle = sqle.getNextException()) != null) {
|
||||
mLog.logWarning(sqle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
126
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/DatabaseProduct.java
Executable file
126
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/DatabaseProduct.java
Executable file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* DatabaseProduct
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sql/DatabaseProduct.java#1 $
|
||||
*/
|
||||
public final class DatabaseProduct implements Serializable {
|
||||
private static final String UNKNOWN_NAME = "Unknown";
|
||||
private static final String GENERIC_NAME = "Generic";
|
||||
private static final String CACHE_NAME = "Cach<EFBFBD>";
|
||||
private static final String DB2_NAME = "DB2";
|
||||
private static final String MSSQL_NAME = "MSSQL";
|
||||
private static final String ORACLE_NAME = "Oracle";
|
||||
private static final String POSTGRESS_NAME = "PostgreSQL";
|
||||
private static final String SYBASE_NAME = "Sybase";
|
||||
|
||||
/*public*/ static final DatabaseProduct UNKNOWN = new DatabaseProduct(UNKNOWN_NAME);
|
||||
public static final DatabaseProduct GENERIC = new DatabaseProduct(GENERIC_NAME);
|
||||
public static final DatabaseProduct CACHE = new DatabaseProduct(CACHE_NAME);
|
||||
public static final DatabaseProduct DB2 = new DatabaseProduct(DB2_NAME);
|
||||
public static final DatabaseProduct MSSQL = new DatabaseProduct(MSSQL_NAME);
|
||||
public static final DatabaseProduct ORACLE = new DatabaseProduct(ORACLE_NAME);
|
||||
public static final DatabaseProduct POSTGRES = new DatabaseProduct(POSTGRESS_NAME);
|
||||
public static final DatabaseProduct SYBASE = new DatabaseProduct(SYBASE_NAME);
|
||||
|
||||
private static final DatabaseProduct[] VALUES = {
|
||||
GENERIC, CACHE, DB2, MSSQL, ORACLE, POSTGRES, SYBASE,
|
||||
};
|
||||
|
||||
private static int sNextOrdinal = -1;
|
||||
private final int mOrdinal = sNextOrdinal++;
|
||||
|
||||
private final String mKey;
|
||||
|
||||
private DatabaseProduct(String pName) {
|
||||
mKey = pName;
|
||||
}
|
||||
|
||||
static int enumSize() {
|
||||
return sNextOrdinal;
|
||||
}
|
||||
|
||||
final int id() {
|
||||
return mOrdinal;
|
||||
}
|
||||
|
||||
final String key() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return mKey + " [id=" + mOrdinal+ "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@code DatabaseProduct} known by the given name.
|
||||
*
|
||||
* @param pName
|
||||
* @return the {@code DatabaseProduct} known by the given name
|
||||
* @throws IllegalArgumentException if there's no such name
|
||||
*/
|
||||
public static DatabaseProduct resolve(String pName) {
|
||||
if ("ANSI".equalsIgnoreCase(pName) || GENERIC_NAME.equalsIgnoreCase(pName)) {
|
||||
return GENERIC;
|
||||
}
|
||||
else if ("Cache".equalsIgnoreCase(pName) || CACHE_NAME.equalsIgnoreCase(pName)) {
|
||||
return CACHE;
|
||||
}
|
||||
else if (DB2_NAME.equalsIgnoreCase(pName)) {
|
||||
return DB2;
|
||||
}
|
||||
else if (MSSQL_NAME.equalsIgnoreCase(pName)) {
|
||||
return MSSQL;
|
||||
}
|
||||
else if (ORACLE_NAME.equalsIgnoreCase(pName)) {
|
||||
return ORACLE;
|
||||
}
|
||||
else if ("Postgres".equalsIgnoreCase(pName) || POSTGRESS_NAME.equalsIgnoreCase(pName)) {
|
||||
return POSTGRES;
|
||||
}
|
||||
else if (SYBASE_NAME.equalsIgnoreCase(pName)) {
|
||||
return SYBASE;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown database product \"" + pName
|
||||
+ "\", try any of the known products, or \"Generic\"");
|
||||
}
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return VALUES[mOrdinal]; // Canonicalize
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Interface for classes that is to be read from a database, using the
|
||||
* ObjectReader class.
|
||||
*
|
||||
* @author Harald Kuhr (haraldk@iconmedialab.no)
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sql/DatabaseReadable.java#1 $
|
||||
*
|
||||
* @todo Use JDK logging instead of proprietary logging.
|
||||
*
|
||||
*/
|
||||
public interface DatabaseReadable {
|
||||
|
||||
/**
|
||||
* Gets the unique identifier of this DatabaseReadable object.
|
||||
*
|
||||
* @return An object that uniqely identifies this DatabaseReadable.
|
||||
*/
|
||||
|
||||
public Object getId();
|
||||
|
||||
/**
|
||||
* Sets the unique identifier of this DatabaseReadable object.
|
||||
*
|
||||
* @param id An object that uniqely identifies this DatabaseReadable.
|
||||
*/
|
||||
|
||||
public void setId(Object id);
|
||||
|
||||
/**
|
||||
* Gets the object to database mapping of this DatabaseReadable.
|
||||
*
|
||||
* @return A Hashtable cotaining the database mapping for this
|
||||
* DatabaseReadable.
|
||||
*/
|
||||
|
||||
public Hashtable getMapping();
|
||||
}
|
||||
173
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/JDBCHelper.java
Executable file
173
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/JDBCHelper.java
Executable file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
/**
|
||||
* AbstractHelper
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sql/JDBCHelper.java#1 $
|
||||
*/
|
||||
public abstract class JDBCHelper {
|
||||
|
||||
private static JDBCHelper[] sHelpers = new JDBCHelper[DatabaseProduct.enumSize()];
|
||||
|
||||
static {
|
||||
DatabaseProduct product = DatabaseProduct.resolve(System.getProperty("com.twelvemonkeys.sql.databaseProduct", "Generic"));
|
||||
sHelpers[0] = createInstance(product);
|
||||
}
|
||||
|
||||
private JDBCHelper() {
|
||||
}
|
||||
|
||||
private static JDBCHelper createInstance(DatabaseProduct pProduct) {
|
||||
// Get database name
|
||||
// Instantiate helper
|
||||
if (pProduct == DatabaseProduct.GENERIC) {
|
||||
return new GenericHelper();
|
||||
}
|
||||
else if (pProduct == DatabaseProduct.CACHE) {
|
||||
return new CacheHelper();
|
||||
}
|
||||
else if (pProduct == DatabaseProduct.DB2) {
|
||||
return new DB2Helper();
|
||||
}
|
||||
else if (pProduct == DatabaseProduct.MSSQL) {
|
||||
return new MSSQLHelper();
|
||||
}
|
||||
else if (pProduct == DatabaseProduct.ORACLE) {
|
||||
return new OracleHelper();
|
||||
}
|
||||
else if (pProduct == DatabaseProduct.POSTGRES) {
|
||||
return new PostgreSQLHelper();
|
||||
}
|
||||
else if (pProduct == DatabaseProduct.SYBASE) {
|
||||
return new SybaseHelper();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown database product, try any of the known products, or \"generic\"");
|
||||
}
|
||||
}
|
||||
|
||||
public final static JDBCHelper getInstance() {
|
||||
return sHelpers[0];
|
||||
}
|
||||
|
||||
public final static JDBCHelper getInstance(DatabaseProduct pProuct) {
|
||||
JDBCHelper helper = sHelpers[pProuct.id()];
|
||||
if (helper == null) {
|
||||
// This is ok, iff sHelpers[pProuct] = helper is an atomic op...
|
||||
synchronized (sHelpers) {
|
||||
helper = sHelpers[pProuct.id()];
|
||||
if (helper == null) {
|
||||
helper = createInstance(pProuct);
|
||||
sHelpers[pProuct.id()] = helper;
|
||||
}
|
||||
}
|
||||
}
|
||||
return helper;
|
||||
}
|
||||
|
||||
// Abstract or ANSI SQL implementations of different stuff
|
||||
|
||||
public String getDefaultDriverName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getDefaultURL() {
|
||||
return "jdbc:{$DRIVER}://localhost:{$PORT}/{$DATABASE}";
|
||||
}
|
||||
|
||||
// Vendor specific concrete implementations
|
||||
|
||||
static class GenericHelper extends JDBCHelper {
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
static class CacheHelper extends JDBCHelper {
|
||||
public String getDefaultDriverName() {
|
||||
return "com.intersys.jdbc.CacheDriver";
|
||||
}
|
||||
|
||||
public String getDefaultURL() {
|
||||
return "jdbc:Cache://localhost:1972/{$DATABASE}";
|
||||
}
|
||||
}
|
||||
|
||||
static class DB2Helper extends JDBCHelper {
|
||||
public String getDefaultDriverName() {
|
||||
return "COM.ibm.db2.jdbc.net.DB2Driver";
|
||||
}
|
||||
|
||||
public String getDefaultURL() {
|
||||
return "jdbc:db2:{$DATABASE}";
|
||||
}
|
||||
}
|
||||
|
||||
static class MSSQLHelper extends JDBCHelper {
|
||||
public String getDefaultDriverName() {
|
||||
return "com.microsoft.jdbc.sqlserver.SQLServerDriver";
|
||||
}
|
||||
|
||||
public String getDefaultURL() {
|
||||
return "jdbc:microsoft:sqlserver://localhost:1433;databasename={$DATABASE};SelectMethod=cursor";
|
||||
}
|
||||
}
|
||||
|
||||
static class OracleHelper extends JDBCHelper {
|
||||
public String getDefaultDriverName() {
|
||||
return "oracle.jdbc.driver.OracleDriver";
|
||||
}
|
||||
|
||||
public String getDefaultURL() {
|
||||
return "jdbc:oracle:thin:@localhost:1521:{$DATABASE}";
|
||||
}
|
||||
}
|
||||
|
||||
static class PostgreSQLHelper extends JDBCHelper {
|
||||
public String getDefaultDriverName() {
|
||||
return "org.postgresql.Driver";
|
||||
}
|
||||
|
||||
public String getDefaultURL() {
|
||||
return "jdbc:postgresql://localhost/{$DATABASE}";
|
||||
}
|
||||
}
|
||||
|
||||
static class SybaseHelper extends JDBCHelper {
|
||||
public String getDefaultDriverName() {
|
||||
return "com.sybase.jdbc2.jdbc.SybDriver";
|
||||
}
|
||||
|
||||
public String getDefaultURL() {
|
||||
return "jdbc:sybase:Tds:localhost:4100/";
|
||||
}
|
||||
}
|
||||
}
|
||||
673
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/Log.java
Executable file
673
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/Log.java
Executable file
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
|
||||
import com.twelvemonkeys.lang.SystemUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Date;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Class used for logging.
|
||||
* The class currently supports four levels of logging (debug, warning, error
|
||||
* and info).
|
||||
* <P>
|
||||
* The class maintains a cahce of OutputStreams, to avoid more than one stream
|
||||
* logging to a specific file. The class should also be thread safe, in that no
|
||||
* more than one instance of the class can log to the same OuputStream.
|
||||
* <P>
|
||||
* <STRONG>
|
||||
* WARNING: The uniqueness of logfiles is based on filenames alone, meaning
|
||||
* "info.log" and "./info.log" will probably be treated as different files,
|
||||
* and have different streams attatched to them.
|
||||
* </STRONG>
|
||||
* <P>
|
||||
* <STRONG>
|
||||
* WARNING: The cached OutputStreams can possibly be in error state or be
|
||||
* closed without warning. Should be fixed in later versions!
|
||||
* </STRONG>
|
||||
*
|
||||
* @author Harald Kuhr (haraldk@iconmedialab.no)
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sql/Log.java#1 $
|
||||
*
|
||||
* @deprecated Use the JDK java.util.logging for logging.
|
||||
* This class is old and outdated, and is here only for compatibility. It will
|
||||
* be removed from the library in later releases.
|
||||
* <P>
|
||||
* All new code are strongly encouraged to use the org.apache.commons.logging
|
||||
* package for logging.
|
||||
*
|
||||
* @see java.util.logging.Logger
|
||||
*
|
||||
*/
|
||||
|
||||
class Log {
|
||||
private static Hashtable streamCache = new Hashtable();
|
||||
|
||||
static {
|
||||
streamCache.put("System.out", System.out);
|
||||
streamCache.put("System.err", System.err);
|
||||
}
|
||||
|
||||
private static Log globalLog = null;
|
||||
|
||||
private String owner = null;
|
||||
|
||||
private boolean logDebug = false;
|
||||
private boolean logWarning = false;
|
||||
private boolean logError = true; // Log errors!
|
||||
private boolean logInfo = false;
|
||||
|
||||
private PrintStream debugLog = null;
|
||||
private PrintStream warningLog = null;
|
||||
private PrintStream errorLog = null;
|
||||
private PrintStream infoLog = null;
|
||||
|
||||
/**
|
||||
* Init global log
|
||||
*/
|
||||
|
||||
static {
|
||||
Properties config = null;
|
||||
try {
|
||||
config = SystemUtil.loadProperties(Log.class);
|
||||
}
|
||||
catch (FileNotFoundException fnf) {
|
||||
// That's okay.
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
// Not so good
|
||||
log(System.err, "ERROR", Log.class.getName(), null, ioe);
|
||||
}
|
||||
|
||||
globalLog = new Log(new Log(), config);
|
||||
|
||||
// Defaults
|
||||
if (globalLog.debugLog == null)
|
||||
globalLog.setDebugLog(System.out);
|
||||
if (globalLog.warningLog == null)
|
||||
globalLog.setWarningLog(System.err);
|
||||
if (globalLog.errorLog == null)
|
||||
globalLog.setErrorLog(System.err);
|
||||
if (globalLog.infoLog == null)
|
||||
globalLog.setInfoLog(System.out);
|
||||
|
||||
// Info
|
||||
globalLog.logDebug("Logging system started.");
|
||||
log(globalLog.infoLog, "INFO", Log.class.getName(),
|
||||
"Logging system started.", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal use only
|
||||
*/
|
||||
|
||||
private Log() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a log
|
||||
*/
|
||||
|
||||
public Log(Object owner) {
|
||||
this.owner = owner.getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a log
|
||||
*/
|
||||
|
||||
public Log(Object owner, Properties config) {
|
||||
this(owner);
|
||||
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
// Set logging levels
|
||||
logDebug = new Boolean(config.getProperty("logDebug",
|
||||
"false")).booleanValue();
|
||||
logWarning = new Boolean(config.getProperty("logWarning",
|
||||
"false")).booleanValue();
|
||||
logError = new Boolean(config.getProperty("logError",
|
||||
"true")).booleanValue();
|
||||
logInfo = new Boolean(config.getProperty("logInfo",
|
||||
"true")).booleanValue();
|
||||
|
||||
// Set logging streams
|
||||
String fileName;
|
||||
try {
|
||||
if ((fileName = config.getProperty("debugLog")) != null)
|
||||
setDebugLog(fileName);
|
||||
|
||||
if ((fileName = config.getProperty("warningLog")) != null)
|
||||
setWarningLog(fileName);
|
||||
|
||||
if ((fileName = config.getProperty("errorLog")) != null)
|
||||
setErrorLog(fileName);
|
||||
|
||||
if ((fileName = config.getProperty("infoLog")) != null)
|
||||
setInfoLog(fileName);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
if (errorLog == null)
|
||||
setErrorLog(System.err);
|
||||
logError("Could not create one or more logging streams! ", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we log debug info
|
||||
*
|
||||
* @return True if logging
|
||||
*/
|
||||
|
||||
public boolean getLogDebug() {
|
||||
return logDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets wheter we are to log debug info
|
||||
*
|
||||
* @param logDebug Boolean, true if we want to log debug info
|
||||
*/
|
||||
|
||||
public void setLogDebug(boolean logDebug) {
|
||||
this.logDebug = logDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we globally log debug info
|
||||
*
|
||||
* @return True if global logging
|
||||
*/
|
||||
/*
|
||||
public static boolean getGlobalDebug() {
|
||||
return globalDebug;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Sets wheter we are to globally log debug info
|
||||
*
|
||||
* @param logDebug Boolean, true if we want to globally log debug info
|
||||
*/
|
||||
/*
|
||||
public static void setGlobalDebug(boolean globalDebug) {
|
||||
Log.globalDebug = globalDebug;
|
||||
}
|
||||
/*
|
||||
/**
|
||||
* Sets the OutputStream we want to print to
|
||||
*
|
||||
* @param os The OutputStream we will use for logging
|
||||
*/
|
||||
|
||||
public void setDebugLog(OutputStream os) {
|
||||
debugLog = new PrintStream(os, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filename of the File we want to print to. Equivalent to
|
||||
* setDebugLog(new FileOutputStream(fileName, true))
|
||||
*
|
||||
* @param file The File we will use for logging
|
||||
* @see #setDebugLog(OutputStream)
|
||||
*/
|
||||
|
||||
public void setDebugLog(String fileName) throws IOException {
|
||||
setDebugLog(getStream(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints debug info to the current debugLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @see #logDebug(String, Exception)
|
||||
*/
|
||||
|
||||
public void logDebug(String message) {
|
||||
logDebug(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints debug info to the current debugLog
|
||||
*
|
||||
* @param exception An Exception
|
||||
* @see #logDebug(String, Exception)
|
||||
*/
|
||||
|
||||
public void logDebug(Exception exception) {
|
||||
logDebug(null, exception);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints debug info to the current debugLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @param exception An Exception
|
||||
*/
|
||||
|
||||
public void logDebug(String message, Exception exception) {
|
||||
if (!(logDebug || globalLog.logDebug))
|
||||
return;
|
||||
|
||||
if (debugLog != null)
|
||||
log(debugLog, "DEBUG", owner, message, exception);
|
||||
else
|
||||
log(globalLog.debugLog, "DEBUG", owner, message, exception);
|
||||
}
|
||||
|
||||
// WARNING
|
||||
|
||||
/**
|
||||
* Checks if we log warning info
|
||||
*
|
||||
* @return True if logging
|
||||
*/
|
||||
|
||||
public boolean getLogWarning() {
|
||||
return logWarning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets wheter we are to log warning info
|
||||
*
|
||||
* @param logWarning Boolean, true if we want to log warning info
|
||||
*/
|
||||
|
||||
public void setLogWarning(boolean logWarning) {
|
||||
this.logWarning = logWarning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we globally log warning info
|
||||
*
|
||||
* @return True if global logging
|
||||
*/
|
||||
/*
|
||||
public static boolean getGlobalWarning() {
|
||||
return globalWarning;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Sets wheter we are to globally log warning info
|
||||
*
|
||||
* @param logWarning Boolean, true if we want to globally log warning info
|
||||
*/
|
||||
/*
|
||||
public static void setGlobalWarning(boolean globalWarning) {
|
||||
Log.globalWarning = globalWarning;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Sets the OutputStream we want to print to
|
||||
*
|
||||
* @param os The OutputStream we will use for logging
|
||||
*/
|
||||
|
||||
public void setWarningLog(OutputStream os) {
|
||||
warningLog = new PrintStream(os, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filename of the File we want to print to. Equivalent to
|
||||
* setWarningLog(new FileOutputStream(fileName, true))
|
||||
*
|
||||
* @param file The File we will use for logging
|
||||
* @see #setWarningLog(OutputStream)
|
||||
*/
|
||||
|
||||
public void setWarningLog(String fileName) throws IOException {
|
||||
setWarningLog(getStream(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints warning info to the current warningLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @see #logWarning(String, Exception)
|
||||
*/
|
||||
|
||||
public void logWarning(String message) {
|
||||
logWarning(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints warning info to the current warningLog
|
||||
*
|
||||
* @param exception An Exception
|
||||
* @see #logWarning(String, Exception)
|
||||
*/
|
||||
|
||||
public void logWarning(Exception exception) {
|
||||
logWarning(null, exception);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints warning info to the current warningLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @param exception An Exception
|
||||
*/
|
||||
|
||||
public void logWarning(String message, Exception exception) {
|
||||
if (!(logWarning || globalLog.logWarning))
|
||||
return;
|
||||
|
||||
if (warningLog != null)
|
||||
log(warningLog, "WARNING", owner, message, exception);
|
||||
else
|
||||
log(globalLog.warningLog, "WARNING", owner, message, exception);
|
||||
}
|
||||
|
||||
// ERROR
|
||||
|
||||
/**
|
||||
* Checks if we log error info
|
||||
*
|
||||
* @return True if logging
|
||||
*/
|
||||
|
||||
public boolean getLogError() {
|
||||
return logError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets wheter we are to log error info
|
||||
*
|
||||
* @param logError Boolean, true if we want to log error info
|
||||
*/
|
||||
|
||||
public void setLogError(boolean logError) {
|
||||
this.logError = logError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we globally log error info
|
||||
*
|
||||
* @return True if global logging
|
||||
*/
|
||||
/*
|
||||
public static boolean getGlobalError() {
|
||||
return globalError;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Sets wheter we are to globally log error info
|
||||
*
|
||||
* @param logError Boolean, true if we want to globally log error info
|
||||
*/
|
||||
/*
|
||||
public static void setGlobalError(boolean globalError) {
|
||||
Log.globalError = globalError;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Sets the OutputStream we want to print to
|
||||
*
|
||||
* @param os The OutputStream we will use for logging
|
||||
*/
|
||||
|
||||
public void setErrorLog(OutputStream os) {
|
||||
errorLog = new PrintStream(os, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filename of the File we want to print to. Equivalent to
|
||||
* setErrorLog(new FileOutputStream(fileName, true))
|
||||
*
|
||||
* @param file The File we will use for logging
|
||||
* @see #setErrorLog(OutputStream)
|
||||
*/
|
||||
|
||||
public void setErrorLog(String fileName) throws IOException {
|
||||
setErrorLog(getStream(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints error info to the current errorLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @see #logError(String, Exception)
|
||||
*/
|
||||
|
||||
public void logError(String message) {
|
||||
logError(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints error info to the current errorLog
|
||||
*
|
||||
* @param exception An Exception
|
||||
* @see #logError(String, Exception)
|
||||
*/
|
||||
|
||||
public void logError(Exception exception) {
|
||||
logError(null, exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints error info to the current errorLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @param exception An Exception
|
||||
*/
|
||||
|
||||
public void logError(String message, Exception exception) {
|
||||
if (!(logError || globalLog.logError))
|
||||
return;
|
||||
|
||||
if (errorLog != null)
|
||||
log(errorLog, "ERROR", owner, message, exception);
|
||||
else
|
||||
log(globalLog.errorLog, "ERROR", owner, message, exception);
|
||||
}
|
||||
|
||||
// INFO
|
||||
|
||||
/**
|
||||
* Checks if we log info info
|
||||
*
|
||||
* @return True if logging
|
||||
*/
|
||||
|
||||
public boolean getLogInfo() {
|
||||
return logInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets wheter we are to log info info
|
||||
*
|
||||
* @param logInfo Boolean, true if we want to log info info
|
||||
*/
|
||||
|
||||
public void setLogInfo(boolean logInfo) {
|
||||
this.logInfo = logInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we globally log info info
|
||||
*
|
||||
* @return True if global logging
|
||||
*/
|
||||
/*
|
||||
public static boolean getGlobalInfo() {
|
||||
return globalInfo;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Sets wheter we are to globally log info info
|
||||
*
|
||||
* @param logInfo Boolean, true if we want to globally log info info
|
||||
*/
|
||||
/*
|
||||
public static void setGlobalInfo(boolean globalInfo) {
|
||||
Log.globalInfo = globalInfo;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Sets the OutputStream we want to print to
|
||||
*
|
||||
* @param os The OutputStream we will use for logging
|
||||
*/
|
||||
|
||||
public void setInfoLog(OutputStream os) {
|
||||
infoLog = new PrintStream(os, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filename of the File we want to print to. Equivalent to
|
||||
* setInfoLog(new FileOutputStream(fileName, true))
|
||||
*
|
||||
* @param file The File we will use for logging
|
||||
* @see #setInfoLog(OutputStream)
|
||||
*/
|
||||
|
||||
public void setInfoLog(String fileName) throws IOException {
|
||||
setInfoLog(getStream(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints info info to the current infoLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @see #logInfo(String, Exception)
|
||||
*/
|
||||
|
||||
public void logInfo(String message) {
|
||||
logInfo(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints info info to the current infoLog
|
||||
*
|
||||
* @param exception An Exception
|
||||
* @see #logInfo(String, Exception)
|
||||
*/
|
||||
|
||||
public void logInfo(Exception exception) {
|
||||
logInfo(null, exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints info info to the current infoLog
|
||||
*
|
||||
* @param message The message to log
|
||||
* @param exception An Exception
|
||||
*/
|
||||
|
||||
public void logInfo(String message, Exception exception) {
|
||||
if (!(logInfo || globalLog.logInfo))
|
||||
return;
|
||||
|
||||
if (infoLog != null)
|
||||
log(infoLog, "INFO", owner, message, exception);
|
||||
else
|
||||
log(globalLog.infoLog, "INFO", owner, message, exception);
|
||||
}
|
||||
|
||||
// LOG
|
||||
|
||||
/**
|
||||
* Internal method to get a named stream
|
||||
*/
|
||||
|
||||
private static OutputStream getStream(String name) throws IOException {
|
||||
OutputStream os = null;
|
||||
|
||||
synchronized (streamCache) {
|
||||
if ((os = (OutputStream) streamCache.get(name)) != null)
|
||||
return os;
|
||||
|
||||
os = new FileOutputStream(name, true);
|
||||
streamCache.put(name, os);
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal log method
|
||||
*/
|
||||
|
||||
private static void log(PrintStream ps, String header,
|
||||
String owner, String message, Exception ex) {
|
||||
// Only allow one instance to print to the given stream.
|
||||
synchronized (ps) {
|
||||
// Create output stream for logging
|
||||
LogStream logStream = new LogStream(ps);
|
||||
|
||||
logStream.time = new Date(System.currentTimeMillis());
|
||||
logStream.header = header;
|
||||
logStream.owner = owner;
|
||||
|
||||
if (message != null)
|
||||
logStream.println(message);
|
||||
|
||||
if (ex != null) {
|
||||
logStream.println(ex.getMessage());
|
||||
ex.printStackTrace(logStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for logging.
|
||||
*
|
||||
* Minimal overloading of PrintStream
|
||||
*/
|
||||
|
||||
class LogStream extends PrintStream {
|
||||
Date time = null;
|
||||
String header = null;
|
||||
String owner = null;
|
||||
|
||||
public LogStream(OutputStream ps) {
|
||||
super(ps);
|
||||
}
|
||||
|
||||
public void println(Object o) {
|
||||
if (o == null)
|
||||
println("null");
|
||||
else
|
||||
println(o.toString());
|
||||
}
|
||||
|
||||
public void println(String str) {
|
||||
super.println("*** " + header + " (" + time + ", " + time.getTime()
|
||||
+ ") " + owner + ": " + str);
|
||||
}
|
||||
}
|
||||
276
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/ObjectManager.java
Executable file
276
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/ObjectManager.java
Executable file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Connection;
|
||||
|
||||
/*
|
||||
Det vi trenger er en mapping mellom
|
||||
- abstrakt navn/klasse/type/identifikator (tilsv. repository)
|
||||
- java klasse
|
||||
- selve mappingen av db kolonne/java property
|
||||
|
||||
I tillegg en mapping mellom alle objektene som brukes i VM'en, og deres id'er
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Under construction.
|
||||
*
|
||||
* @author Harald Kuhr (haraldk@iconmedialab.no),
|
||||
* @version 0.5
|
||||
*/
|
||||
public abstract class ObjectManager {
|
||||
private ObjectReader mObjectReader = null;
|
||||
|
||||
private WeakHashMap mLiveObjects = new WeakHashMap(); // object/id
|
||||
|
||||
private Hashtable mTypes = new Hashtable(); // type name/java class
|
||||
private Hashtable mMappings = new Hashtable(); // type name/mapping
|
||||
|
||||
/**
|
||||
* Creates an Object Manager with the default JDBC connection
|
||||
*/
|
||||
|
||||
public ObjectManager() {
|
||||
this(DatabaseConnection.getConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Object Manager with the given JDBC connection
|
||||
*/
|
||||
|
||||
public ObjectManager(Connection pConnection) {
|
||||
mObjectReader = new ObjectReader(pConnection);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the property/column mapping for a given type
|
||||
*/
|
||||
|
||||
protected Hashtable getMapping(String pType) {
|
||||
return (Hashtable) mMappings.get(pType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class for a type
|
||||
*
|
||||
* @return The class for a type. If the type is not found, this method will
|
||||
* throw an excpetion, and will never return null.
|
||||
*/
|
||||
|
||||
protected Class getType(String pType) {
|
||||
Class cl = (Class) mTypes.get(pType);
|
||||
|
||||
if (cl == null) {
|
||||
// throw new NoSuchTypeException();
|
||||
}
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a java object of the class for a given type.
|
||||
*/
|
||||
|
||||
protected Object getObject(String pType)
|
||||
/*throws XxxException*/ {
|
||||
// Get class
|
||||
Class cl = getType(pType);
|
||||
|
||||
// Return the new instance (requires empty public constructor)
|
||||
try {
|
||||
return cl.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// throw new XxxException(e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
|
||||
// Can't happen
|
||||
//return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a DatabaseReadable object that can be used for looking up the
|
||||
* object properties from the database.
|
||||
*/
|
||||
|
||||
protected DatabaseReadable getDatabaseReadable(String pType) {
|
||||
|
||||
return new DatabaseObject(getObject(pType), getMapping(pType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the object of the given type and with the given id from the
|
||||
* database
|
||||
*/
|
||||
|
||||
// interface
|
||||
public Object getObject(String pType, Object pId)
|
||||
throws SQLException {
|
||||
|
||||
// Create DatabaseReadable and set id
|
||||
DatabaseObject dbObject = (DatabaseObject) getDatabaseReadable(pType);
|
||||
dbObject.setId(pId);
|
||||
|
||||
// Read it
|
||||
dbObject = (DatabaseObject) mObjectReader.readObject(dbObject);
|
||||
|
||||
// Return it
|
||||
return dbObject.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the objects of the given type and with the given ids from the
|
||||
* database
|
||||
*/
|
||||
|
||||
// interface
|
||||
public Object[] getObjects(String pType, Object[] pIds)
|
||||
throws SQLException {
|
||||
|
||||
// Create Vector to hold the result
|
||||
Vector result = new Vector(pIds.length);
|
||||
|
||||
// Loop through Id's and fetch one at a time (no good performance...)
|
||||
for (int i = 0; i < pIds.length; i++) {
|
||||
// Create DBObject, set id and read it
|
||||
DatabaseObject dbObject =
|
||||
(DatabaseObject) getDatabaseReadable(pType);
|
||||
|
||||
dbObject.setId(pIds[i]);
|
||||
dbObject = (DatabaseObject) mObjectReader.readObject(dbObject);
|
||||
|
||||
// Add to result if not null
|
||||
if (dbObject != null) {
|
||||
result.add(dbObject.getObject());
|
||||
}
|
||||
}
|
||||
|
||||
// Create array of correct type, length equal to Vector
|
||||
Class cl = getType(pType);
|
||||
Object[] arr = (Object[]) Array.newInstance(cl, result.size());
|
||||
|
||||
// Return the vector as an array
|
||||
return result.toArray(arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the objects of the given type and with the given properties from
|
||||
* the database
|
||||
*/
|
||||
|
||||
// interface
|
||||
public Object[] getObjects(String pType, Hashtable pWhere)
|
||||
throws SQLException {
|
||||
return mObjectReader.readObjects(getDatabaseReadable(pType), pWhere);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all objects of the given type from the database
|
||||
*/
|
||||
|
||||
// interface
|
||||
public Object[] getObjects(String pType)
|
||||
throws SQLException {
|
||||
return mObjectReader.readObjects(getDatabaseReadable(pType));
|
||||
}
|
||||
|
||||
// interface
|
||||
public Object addObject(Object pObject) {
|
||||
// get id...
|
||||
|
||||
return pObject;
|
||||
}
|
||||
|
||||
// interface
|
||||
public Object updateObject(Object pObject) {
|
||||
// get id...
|
||||
|
||||
return pObject;
|
||||
}
|
||||
|
||||
// interface
|
||||
public abstract Object deleteObject(String pType, Object pId);
|
||||
|
||||
// interface
|
||||
public abstract Object deleteObject(Object pObject);
|
||||
|
||||
// interface
|
||||
public abstract Object createObject(String pType, Object pId);
|
||||
|
||||
// interface
|
||||
public abstract Object createObject(String pType);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for reading Objects from the database
|
||||
*/
|
||||
|
||||
class DatabaseObject implements DatabaseReadable {
|
||||
Hashtable mMapping = null;
|
||||
|
||||
Object mId = null;
|
||||
Object mObject = null;
|
||||
|
||||
public DatabaseObject(Object pObject, Hashtable pMapping) {
|
||||
setObject(pObject);
|
||||
setMapping(pMapping);
|
||||
}
|
||||
|
||||
public Object getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public void setId(Object pId) {
|
||||
mId = pId;
|
||||
}
|
||||
|
||||
public void setObject(Object pObject) {
|
||||
mObject = pObject;
|
||||
}
|
||||
public Object getObject() {
|
||||
return mObject;
|
||||
}
|
||||
|
||||
public void setMapping(Hashtable pMapping) {
|
||||
mMapping = pMapping;
|
||||
}
|
||||
|
||||
public Hashtable getMapping() {
|
||||
return mMapping;
|
||||
}
|
||||
}
|
||||
663
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/ObjectMapper.java
Executable file
663
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/ObjectMapper.java
Executable file
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
import com.twelvemonkeys.lang.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
// Single-type import, to avoid util.Date/sql.Date confusion
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* A class for mapping JDBC ResultSet rows to Java objects.
|
||||
*
|
||||
* @see ObjectReader
|
||||
*
|
||||
* @author Harald Kuhr (haraldk@iconmedialab.no)
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sql/ObjectMapper.java#1 $
|
||||
*
|
||||
* @todo Use JDK logging instead of proprietary logging.
|
||||
*/
|
||||
public class ObjectMapper {
|
||||
final static String DIRECTMAP = "direct";
|
||||
final static String OBJECTMAP = "object";
|
||||
final static String COLLECTIONMAP = "collection";
|
||||
final static String OBJCOLLMAP = "objectcollection";
|
||||
|
||||
Class mInstanceClass = null;
|
||||
|
||||
Hashtable mMethods = null;
|
||||
|
||||
Hashtable mColumnMap = null;
|
||||
Hashtable mPropertiesMap = null;
|
||||
|
||||
Hashtable mJoins = null;
|
||||
|
||||
private Hashtable mTables = null;
|
||||
private Vector mColumns = null;
|
||||
|
||||
Hashtable mForeignKeys = null;
|
||||
Hashtable mPrimaryKeys = null;
|
||||
Hashtable mMapTypes = null;
|
||||
Hashtable mClasses = null;
|
||||
|
||||
String mPrimaryKey = null;
|
||||
String mForeignKey = null;
|
||||
String mIdentityJoin = null;
|
||||
|
||||
Log mLog = null;
|
||||
|
||||
/**
|
||||
* Creates a new ObjectMapper for a DatabaseReadable
|
||||
*
|
||||
* @param obj An object of type DatabaseReadable
|
||||
*/
|
||||
|
||||
/*
|
||||
public ObjectMapper(DatabaseReadable obj) {
|
||||
this(obj.getClass(), obj.getMapping());
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Creates a new ObjectMapper for any object, given a mapping
|
||||
*
|
||||
* @param objClass The class of the object(s) created by this OM
|
||||
* @param mapping an Hashtable containing the mapping information
|
||||
* for this OM
|
||||
*/
|
||||
|
||||
public ObjectMapper(Class pObjClass, Hashtable pMapping) {
|
||||
mLog = new Log(this);
|
||||
|
||||
mInstanceClass = pObjClass;
|
||||
|
||||
mJoins = new Hashtable();
|
||||
mPropertiesMap = new Hashtable();
|
||||
mColumnMap = new Hashtable();
|
||||
|
||||
mClasses = new Hashtable();
|
||||
mMapTypes = new Hashtable();
|
||||
mForeignKeys = new Hashtable();
|
||||
mPrimaryKeys = new Hashtable();
|
||||
|
||||
// Unpack and store mapping information
|
||||
for (Enumeration keys = pMapping.keys(); keys.hasMoreElements();) {
|
||||
String key = (String) keys.nextElement();
|
||||
String value = (String) pMapping.get(key);
|
||||
|
||||
int dotIdx = key.indexOf(".");
|
||||
|
||||
if (dotIdx >= 0) {
|
||||
if (key.equals(".primaryKey")) {
|
||||
// Primary key
|
||||
mPrimaryKey = (String) pMapping.get(value);
|
||||
}
|
||||
else if (key.equals(".foreignKey")) {
|
||||
// Foreign key
|
||||
mForeignKey = (String) pMapping.get(value);
|
||||
}
|
||||
else if (key.equals(".join")) {
|
||||
// Identity join
|
||||
mIdentityJoin = (String) pMapping.get(key);
|
||||
}
|
||||
else if (key.endsWith(".primaryKey")) {
|
||||
// Primary key in joining table
|
||||
mPrimaryKeys.put(key.substring(0, dotIdx), value);
|
||||
}
|
||||
else if (key.endsWith(".foreignKey")) {
|
||||
// Foreign key
|
||||
mForeignKeys.put(key.substring(0, dotIdx), value);
|
||||
}
|
||||
else if (key.endsWith(".join")) {
|
||||
// Joins
|
||||
mJoins.put(key.substring(0, dotIdx), value);
|
||||
}
|
||||
else if (key.endsWith(".mapType")) {
|
||||
// Maptypes
|
||||
value = value.toLowerCase();
|
||||
|
||||
if (value.equals(DIRECTMAP) || value.equals(OBJECTMAP) ||
|
||||
value.equals(COLLECTIONMAP) ||
|
||||
value.equals(OBJCOLLMAP)) {
|
||||
mMapTypes.put(key.substring(0, dotIdx), value);
|
||||
}
|
||||
else {
|
||||
mLog.logError("Illegal mapType: \"" + value + "\"! "
|
||||
+ "Legal types are: direct, object, "
|
||||
+ "collection and objectCollection.");
|
||||
}
|
||||
}
|
||||
else if (key.endsWith(".class")) {
|
||||
// Classes
|
||||
try {
|
||||
mClasses.put(key.substring(0, dotIdx),
|
||||
Class.forName(value));
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
mLog.logError(e);
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else if (key.endsWith(".collection")) {
|
||||
// TODO!!
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Property to column mappings
|
||||
mPropertiesMap.put(key, value);
|
||||
mColumnMap.put(value.substring(value.lastIndexOf(".") + 1),
|
||||
key);
|
||||
}
|
||||
}
|
||||
|
||||
mMethods = new Hashtable();
|
||||
Method[] methods = mInstanceClass.getMethods();
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
// Two methods CAN have same name...
|
||||
mMethods.put(methods[i].getName(), methods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPrimaryKey(String pPrimaryKey) {
|
||||
mPrimaryKey = pPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the property, that acts as the unique identifier for
|
||||
* this ObjectMappers type.
|
||||
*
|
||||
* @return The name of the primary key property
|
||||
*/
|
||||
|
||||
public String getPrimaryKey() {
|
||||
return mPrimaryKey;
|
||||
}
|
||||
|
||||
public String getForeignKey() {
|
||||
return mForeignKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the join, that is needed to find this ObjectMappers type.
|
||||
*
|
||||
* @return The name of the primary key property
|
||||
*/
|
||||
|
||||
public String getIdentityJoin() {
|
||||
return mIdentityJoin;
|
||||
}
|
||||
|
||||
Hashtable getPropertyMapping(String pProperty) {
|
||||
Hashtable mapping = new Hashtable();
|
||||
|
||||
if (pProperty != null) {
|
||||
// Property
|
||||
if (mPropertiesMap.containsKey(pProperty))
|
||||
mapping.put("object", mPropertiesMap.get(pProperty));
|
||||
|
||||
// Primary key
|
||||
if (mPrimaryKeys.containsKey(pProperty)) {
|
||||
mapping.put(".primaryKey", "id");
|
||||
mapping.put("id", mPrimaryKeys.get(pProperty));
|
||||
}
|
||||
|
||||
//Foreign key
|
||||
if (mForeignKeys.containsKey(pProperty))
|
||||
mapping.put(".foreignKey", mPropertiesMap.get(mForeignKeys.get(pProperty)));
|
||||
|
||||
// Join
|
||||
if (mJoins.containsKey(pProperty))
|
||||
mapping.put(".join", mJoins.get(pProperty));
|
||||
|
||||
// mapType
|
||||
mapping.put(".mapType", "object");
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the column for a given property.
|
||||
*
|
||||
* @param property The property
|
||||
* @return The name of the matching database column, on the form
|
||||
* table.column
|
||||
*/
|
||||
|
||||
public String getColumn(String pProperty) {
|
||||
if (mPropertiesMap == null || pProperty == null)
|
||||
return null;
|
||||
return (String) mPropertiesMap.get(pProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table name for a given property.
|
||||
*
|
||||
* @param property The property
|
||||
* @return The name of the matching database table.
|
||||
*/
|
||||
|
||||
public String getTable(String pProperty) {
|
||||
String table = getColumn(pProperty);
|
||||
|
||||
if (table != null) {
|
||||
int dotIdx = 0;
|
||||
if ((dotIdx = table.lastIndexOf(".")) >= 0)
|
||||
table = table.substring(0, dotIdx);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the property for a given database column. If the column incudes
|
||||
* table qualifier, the table qualifier is removed.
|
||||
*
|
||||
* @param column The name of the column
|
||||
* @return The name of the mathcing property
|
||||
*/
|
||||
|
||||
public String getProperty(String pColumn) {
|
||||
if (mColumnMap == null || pColumn == null)
|
||||
return null;
|
||||
|
||||
String property = (String) mColumnMap.get(pColumn);
|
||||
|
||||
int dotIdx = 0;
|
||||
if (property == null && (dotIdx = pColumn.lastIndexOf(".")) >= 0)
|
||||
property = (String) mColumnMap.get(pColumn.substring(dotIdx + 1));
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps each row of the given result set to an object ot this OM's type.
|
||||
*
|
||||
* @param rs The ResultSet to process (map to objects)
|
||||
* @return An array of objects (of this OM's class). If there are no rows
|
||||
* in the ResultSet, an empty (zero-length) array will be returned.
|
||||
*/
|
||||
|
||||
public synchronized Object[] mapObjects(ResultSet pRSet) throws SQLException {
|
||||
Vector result = new Vector();
|
||||
|
||||
ResultSetMetaData meta = pRSet.getMetaData();
|
||||
int cols = meta.getColumnCount();
|
||||
|
||||
// Get colum names
|
||||
String[] colNames = new String[cols];
|
||||
for (int i = 0; i < cols; i++) {
|
||||
colNames[i] = meta.getColumnName(i + 1); // JDBC cols start at 1...
|
||||
|
||||
/*
|
||||
System.out.println(meta.getColumnLabel(i + 1));
|
||||
System.out.println(meta.getColumnName(i + 1));
|
||||
System.out.println(meta.getColumnType(i + 1));
|
||||
System.out.println(meta.getColumnTypeName(i + 1));
|
||||
// System.out.println(meta.getTableName(i + 1));
|
||||
// System.out.println(meta.getCatalogName(i + 1));
|
||||
// System.out.println(meta.getSchemaName(i + 1));
|
||||
// Last three NOT IMPLEMENTED!!
|
||||
*/
|
||||
}
|
||||
|
||||
// Loop through rows in resultset
|
||||
while (pRSet.next()) {
|
||||
Object obj = null;
|
||||
|
||||
try {
|
||||
obj = mInstanceClass.newInstance(); // Asserts empty constructor!
|
||||
}
|
||||
catch (IllegalAccessException iae) {
|
||||
mLog.logError(iae);
|
||||
// iae.printStackTrace();
|
||||
}
|
||||
catch (InstantiationException ie) {
|
||||
mLog.logError(ie);
|
||||
// ie.printStackTrace();
|
||||
}
|
||||
|
||||
// Read each colum from this row into object
|
||||
for (int i = 0; i < cols; i++) {
|
||||
|
||||
String property = (String) mColumnMap.get(colNames[i]);
|
||||
|
||||
if (property != null) {
|
||||
// This column is mapped to a property
|
||||
mapColumnProperty(pRSet, i + 1, property, obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Add object to the result Vector
|
||||
result.addElement(obj);
|
||||
}
|
||||
|
||||
return result.toArray((Object[]) Array.newInstance(mInstanceClass,
|
||||
result.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a ResultSet column (from the current ResultSet row) to a named
|
||||
* property of an object, using reflection.
|
||||
*
|
||||
* @param rs The JDBC ResultSet
|
||||
* @param index The column index to get the value from
|
||||
* @param property The name of the property to set the value of
|
||||
* @param obj The object to set the property to
|
||||
*/
|
||||
|
||||
void mapColumnProperty(ResultSet pRSet, int pIndex, String pProperty,
|
||||
Object pObj) {
|
||||
if (pRSet == null || pProperty == null || pObj == null)
|
||||
throw new IllegalArgumentException("ResultSet, Property or Object"
|
||||
+ " arguments cannot be null!");
|
||||
if (pIndex <= 0)
|
||||
throw new IllegalArgumentException("Index parameter must be > 0!");
|
||||
|
||||
String methodName = "set" + StringUtil.capitalize(pProperty);
|
||||
Method setMethod = (Method) mMethods.get(methodName);
|
||||
|
||||
if (setMethod == null) {
|
||||
// No setMethod for this property
|
||||
mLog.logError("No set method for property \""
|
||||
+ pProperty + "\" in " + pObj.getClass() + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
// System.err.println("DEBUG: setMethod=" + setMethod);
|
||||
|
||||
Method getMethod = null;
|
||||
|
||||
String type = "";
|
||||
try {
|
||||
Class[] cl = {Integer.TYPE};
|
||||
type = setMethod.getParameterTypes()[0].getName();
|
||||
|
||||
type = type.substring(type.lastIndexOf(".") + 1);
|
||||
|
||||
// There is no getInteger, use getInt instead
|
||||
if (type.equals("Integer")) {
|
||||
type = "int";
|
||||
}
|
||||
|
||||
// System.err.println("DEBUG: type=" + type);
|
||||
getMethod = pRSet.getClass().
|
||||
getMethod("get" + StringUtil.capitalize(type), cl);
|
||||
}
|
||||
catch (Exception e) {
|
||||
mLog.logError("Can't find method \"get"
|
||||
+ StringUtil.capitalize(type) + "(int)\" "
|
||||
+ "(for class " + StringUtil.capitalize(type)
|
||||
+ ") in ResultSet", e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the data from the DB
|
||||
// System.err.println("DEBUG: " + getMethod.getName() + "(" + (i + 1) + ")");
|
||||
|
||||
Object[] colIdx = {new Integer(pIndex)};
|
||||
Object[] arg = {getMethod.invoke(pRSet, colIdx)};
|
||||
|
||||
// Set it to the object
|
||||
// System.err.println("DEBUG: " + setMethod.getName() + "(" + arg[0] + ")");
|
||||
setMethod.invoke(pObj, arg);
|
||||
}
|
||||
catch (InvocationTargetException ite) {
|
||||
mLog.logError(ite);
|
||||
// ite.printStackTrace();
|
||||
}
|
||||
catch (IllegalAccessException iae) {
|
||||
mLog.logError(iae);
|
||||
// iae.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SQL query string to get the primary keys for this
|
||||
* ObjectMapper.
|
||||
*/
|
||||
|
||||
String buildIdentitySQL(String[] pKeys) {
|
||||
mTables = new Hashtable();
|
||||
mColumns = new Vector();
|
||||
|
||||
// Get columns to select
|
||||
mColumns.addElement(getPrimaryKey());
|
||||
|
||||
// Get tables to select (and join) from and their joins
|
||||
tableJoins(null, false);
|
||||
|
||||
for (int i = 0; i < pKeys.length; i++) {
|
||||
tableJoins(getColumn(pKeys[i]), true);
|
||||
}
|
||||
|
||||
// All data read, build SQL query string
|
||||
return "SELECT " + getPrimaryKey() + " " + buildFromClause()
|
||||
+ buildWhereClause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SQL query string to get objects for this ObjectMapper.
|
||||
*/
|
||||
|
||||
public String buildSQL() {
|
||||
mTables = new Hashtable();
|
||||
mColumns = new Vector();
|
||||
|
||||
String key = null;
|
||||
for (Enumeration keys = mPropertiesMap.keys(); keys.hasMoreElements();) {
|
||||
key = (String) keys.nextElement();
|
||||
|
||||
// Get columns to select
|
||||
String column = (String) mPropertiesMap.get(key);
|
||||
mColumns.addElement(column);
|
||||
|
||||
tableJoins(column, false);
|
||||
}
|
||||
|
||||
// All data read, build SQL query string
|
||||
return buildSelectClause() + buildFromClause()
|
||||
+ buildWhereClause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a SQL SELECT clause from the columns Vector
|
||||
*/
|
||||
|
||||
private String buildSelectClause() {
|
||||
StringBuilder sqlBuf = new StringBuilder();
|
||||
|
||||
sqlBuf.append("SELECT ");
|
||||
|
||||
String column = null;
|
||||
for (Enumeration select = mColumns.elements(); select.hasMoreElements();) {
|
||||
column = (String) select.nextElement();
|
||||
|
||||
/*
|
||||
String subColumn = column.substring(column.indexOf(".") + 1);
|
||||
// System.err.println("DEBUG: col=" + subColumn);
|
||||
String mapType = (String) mMapTypes.get(mColumnMap.get(subColumn));
|
||||
*/
|
||||
String mapType = (String) mMapTypes.get(getProperty(column));
|
||||
|
||||
if (mapType == null || mapType.equals(DIRECTMAP)) {
|
||||
sqlBuf.append(column);
|
||||
|
||||
sqlBuf.append(select.hasMoreElements() ? ", " : " ");
|
||||
}
|
||||
}
|
||||
|
||||
return sqlBuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a SQL FROM clause from the tables/joins Hashtable
|
||||
*/
|
||||
|
||||
private String buildFromClause() {
|
||||
StringBuilder sqlBuf = new StringBuilder();
|
||||
|
||||
sqlBuf.append("FROM ");
|
||||
|
||||
String table = null;
|
||||
String schema = null;
|
||||
for (Enumeration from = mTables.keys(); from.hasMoreElements();) {
|
||||
table = (String) from.nextElement();
|
||||
/*
|
||||
schema = (String) schemas.get(table);
|
||||
|
||||
if (schema != null)
|
||||
sqlBuf.append(schema + ".");
|
||||
*/
|
||||
|
||||
sqlBuf.append(table);
|
||||
sqlBuf.append(from.hasMoreElements() ? ", " : " ");
|
||||
}
|
||||
|
||||
return sqlBuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a SQL WHERE clause from the tables/joins Hashtable
|
||||
*
|
||||
* @return Currently, this metod will return "WHERE 1 = 1", if no other
|
||||
* WHERE conditions are specified. This can be considered a hack.
|
||||
*/
|
||||
|
||||
private String buildWhereClause() {
|
||||
|
||||
StringBuilder sqlBuf = new StringBuilder();
|
||||
|
||||
String join = null;
|
||||
boolean first = true;
|
||||
|
||||
for (Enumeration where = mTables.elements(); where.hasMoreElements();) {
|
||||
join = (String) where.nextElement();
|
||||
|
||||
if (join.length() > 0) {
|
||||
if (first) {
|
||||
// Skip " AND " in first iteration
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
sqlBuf.append(" AND ");
|
||||
}
|
||||
}
|
||||
|
||||
sqlBuf.append(join);
|
||||
}
|
||||
|
||||
if (sqlBuf.length() > 0)
|
||||
return "WHERE " + sqlBuf.toString();
|
||||
|
||||
return "WHERE 1 = 1"; // Hacky...
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds tables used in mappings and joins and adds them to the tables
|
||||
* Hashtable, with the table name as key, and the join as value.
|
||||
*/
|
||||
|
||||
private void tableJoins(String pColumn, boolean pWhereJoin) {
|
||||
String join = null;
|
||||
String table = null;
|
||||
|
||||
if (pColumn == null) {
|
||||
// Identity
|
||||
join = getIdentityJoin();
|
||||
table = getTable(getProperty(getPrimaryKey()));
|
||||
}
|
||||
else {
|
||||
// Normal
|
||||
int dotIndex = -1;
|
||||
if ((dotIndex = pColumn.lastIndexOf(".")) <= 0) {
|
||||
// No table qualifier
|
||||
return;
|
||||
}
|
||||
|
||||
// Get table qualifier.
|
||||
table = pColumn.substring(0, dotIndex);
|
||||
|
||||
// Don't care about the tables that are not supposed to be selected from
|
||||
String property = (String) getProperty(pColumn);
|
||||
|
||||
if (property != null) {
|
||||
String mapType = (String) mMapTypes.get(property);
|
||||
if (!pWhereJoin && mapType != null && !mapType.equals(DIRECTMAP)) {
|
||||
return;
|
||||
}
|
||||
|
||||
join = (String) mJoins.get(property);
|
||||
}
|
||||
}
|
||||
|
||||
// If table is not in the tables Hash, add it, and check for joins.
|
||||
if (mTables.get(table) == null) {
|
||||
if (join != null) {
|
||||
mTables.put(table, join);
|
||||
|
||||
StringTokenizer tok = new StringTokenizer(join, "= ");
|
||||
String next = null;
|
||||
|
||||
while(tok.hasMoreElements()) {
|
||||
next = tok.nextToken();
|
||||
// Don't care about SQL keywords
|
||||
if (next.equals("AND") || next.equals("OR")
|
||||
|| next.equals("NOT") || next.equals("IN")) {
|
||||
continue;
|
||||
}
|
||||
// Check for new tables and joins in this join clause.
|
||||
tableJoins(next, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No joins for this table.
|
||||
join = "";
|
||||
mTables.put(table, join);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
879
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/ObjectReader.java
Executable file
879
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/ObjectReader.java
Executable file
@@ -0,0 +1,879 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.lang.SystemUtil;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Properties;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Class used for reading table data from a database through JDBC, and map
|
||||
* the data to Java classes.
|
||||
*
|
||||
* @see ObjectMapper
|
||||
*
|
||||
* @author Harald Kuhr (haraldk@iconmedialab.no)
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sql/ObjectReader.java#1 $
|
||||
*
|
||||
* @todo Use JDK logging instead of proprietary logging.
|
||||
*
|
||||
*/
|
||||
public class ObjectReader {
|
||||
|
||||
/**
|
||||
* Main method, for testing purposes only.
|
||||
*/
|
||||
|
||||
public final static void main(String[] pArgs) throws SQLException {
|
||||
/*
|
||||
System.err.println("Testing only!");
|
||||
|
||||
// Get default connection
|
||||
ObjectReader obr = new ObjectReader(DatabaseConnection.getConnection());
|
||||
|
||||
com.twelvemonkeys.usedcars.DBCar car = new com.twelvemonkeys.usedcars.DBCar(new Integer(1));
|
||||
com.twelvemonkeys.usedcars.DBDealer dealer = new com.twelvemonkeys.usedcars.DBDealer("NO4537");
|
||||
|
||||
System.out.println(obr.readObject(dealer));
|
||||
com.twelvemonkeys.usedcars.Dealer[] dealers = (com.twelvemonkeys.usedcars.Dealer[]) obr.readObjects(dealer);
|
||||
|
||||
for (int i = 0; i < dealers.length; i++) {
|
||||
System.out.println(dealers[i]);
|
||||
}
|
||||
|
||||
System.out.println("------------------------------------------------------------------------------\n"
|
||||
+ "Total: " + dealers.length + " dealers in database\n");
|
||||
|
||||
Hashtable where = new Hashtable();
|
||||
|
||||
where.put("zipCode", "0655");
|
||||
dealers = (com.twelvemonkeys.usedcars.Dealer[]) obr.readObjects(dealer, where);
|
||||
|
||||
for (int i = 0; i < dealers.length; i++) {
|
||||
System.out.println(dealers[i]);
|
||||
}
|
||||
|
||||
System.out.println("------------------------------------------------------------------------------\n"
|
||||
+ "Total: " + dealers.length + " dealers matching query: "
|
||||
+ where + "\n");
|
||||
|
||||
|
||||
com.twelvemonkeys.usedcars.Car[] cars = null;
|
||||
cars = (com.twelvemonkeys.usedcars.Car[]) obr.readObjects(car);
|
||||
|
||||
for (int i = 0; i < cars.length; i++) {
|
||||
System.out.println(cars[i]);
|
||||
}
|
||||
|
||||
System.out.println("------------------------------------------------------------------------------\n"
|
||||
+ "Total: " + cars.length + " cars in database\n");
|
||||
|
||||
where = new Hashtable();
|
||||
where.put("year", new Integer(1995));
|
||||
cars = (com.twelvemonkeys.usedcars.Car[]) obr.readObjects(car, where);
|
||||
|
||||
for (int i = 0; i < cars.length; i++) {
|
||||
System.out.println(cars[i]);
|
||||
}
|
||||
|
||||
System.out.println("------------------------------------------------------------------------------\n"
|
||||
+ "Total: " + cars.length + " cars matching query: "
|
||||
+ where + " \n");
|
||||
|
||||
|
||||
where = new Hashtable();
|
||||
where.put("publishers", "Bilguiden");
|
||||
cars = (com.twelvemonkeys.usedcars.Car[]) obr.readObjects(car, where);
|
||||
|
||||
for (int i = 0; i < cars.length; i++) {
|
||||
System.out.println(cars[i]);
|
||||
}
|
||||
|
||||
System.out.println("------------------------------------------------------------------------------\n"
|
||||
+ "Total: " + cars.length + " cars matching query: "
|
||||
+ where + "\n");
|
||||
|
||||
System.out.println("==============================================================================\n"
|
||||
+ getStats());
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
protected Log mLog = null;
|
||||
protected Properties mConfig = null;
|
||||
|
||||
/**
|
||||
* The connection used for all database operations executed by this
|
||||
* ObjectReader.
|
||||
*/
|
||||
|
||||
Connection mConnection = null;
|
||||
|
||||
/**
|
||||
* The cache for this ObjectReader.
|
||||
* Probably a source for memory leaks, as it has no size limitations.
|
||||
*/
|
||||
|
||||
private Hashtable mCache = new Hashtable();
|
||||
|
||||
/**
|
||||
* Creates a new ObjectReader, using the given JDBC Connection. The
|
||||
* Connection will be used for all database reads by this ObjectReader.
|
||||
*
|
||||
* @param connection A JDBC Connection
|
||||
*/
|
||||
|
||||
public ObjectReader(Connection pConnection) {
|
||||
mConnection = pConnection;
|
||||
|
||||
try {
|
||||
mConfig = SystemUtil.loadProperties(getClass());
|
||||
}
|
||||
catch (FileNotFoundException fnf) {
|
||||
// Just go with defaults
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
new Log(this).logError(ioe);
|
||||
}
|
||||
|
||||
mLog = new Log(this, mConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string containing the stats for this ObjectReader.
|
||||
*
|
||||
* @return A string to display the stats.
|
||||
*/
|
||||
|
||||
public static String getStats() {
|
||||
long total = sCacheHit + sCacheMiss + sCacheUn;
|
||||
double hit = ((double) sCacheHit / (double) total) * 100.0;
|
||||
double miss = ((double) sCacheMiss / (double) total) * 100.0;
|
||||
double un = ((double) sCacheUn / (double) total) * 100.0;
|
||||
|
||||
// Default locale
|
||||
java.text.NumberFormat nf = java.text.NumberFormat.getInstance();
|
||||
|
||||
return "Total: " + total + " reads. "
|
||||
+ "Cache hits: " + sCacheHit + " (" + nf.format(hit) + "%), "
|
||||
+ "Cache misses: " + sCacheMiss + " (" + nf.format(miss) + "%), "
|
||||
+ "Unattempted: " + sCacheUn + " (" + nf.format(un) + "%) ";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing Objects of type objClass, with the
|
||||
* identity values for the given class set.
|
||||
*/
|
||||
|
||||
private Object[] readIdentities(Class pObjClass, Hashtable pMapping,
|
||||
Hashtable pWhere, ObjectMapper pOM)
|
||||
throws SQLException {
|
||||
sCacheUn++;
|
||||
// Build SQL query string
|
||||
if (pWhere == null)
|
||||
pWhere = new Hashtable();
|
||||
|
||||
String[] keys = new String[pWhere.size()];
|
||||
int i = 0;
|
||||
for (Enumeration en = pWhere.keys(); en.hasMoreElements(); i++) {
|
||||
keys[i] = (String) en.nextElement();
|
||||
}
|
||||
|
||||
// Get SQL for reading identity column
|
||||
String sql = pOM.buildIdentitySQL(keys)
|
||||
+ buildWhereClause(keys, pMapping);
|
||||
|
||||
// Log?
|
||||
mLog.logDebug(sql + " (" + pWhere + ")");
|
||||
|
||||
// Prepare statement and set values
|
||||
PreparedStatement statement = mConnection.prepareStatement(sql);
|
||||
for (int j = 0; j < keys.length; j++) {
|
||||
Object key = pWhere.get(keys[j]);
|
||||
|
||||
if (key instanceof Integer)
|
||||
statement.setInt(j + 1, ((Integer) key).intValue());
|
||||
else if (key instanceof BigDecimal)
|
||||
statement.setBigDecimal(j + 1, (BigDecimal) key);
|
||||
else
|
||||
statement.setString(j + 1, key.toString());
|
||||
}
|
||||
|
||||
// Execute query
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
rs = statement.executeQuery();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
mLog.logError(sql + " (" + pWhere + ")", e);
|
||||
throw e;
|
||||
}
|
||||
Vector result = new Vector();
|
||||
|
||||
// Map query to objects
|
||||
while (rs.next()) {
|
||||
Object obj = null;
|
||||
|
||||
try {
|
||||
obj = pObjClass.newInstance();
|
||||
}
|
||||
catch (IllegalAccessException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
catch (InstantiationException ie) {
|
||||
ie.printStackTrace();
|
||||
}
|
||||
|
||||
// Map it
|
||||
pOM.mapColumnProperty(rs, 1,
|
||||
pOM.getProperty(pOM.getPrimaryKey()), obj);
|
||||
result.addElement(obj);
|
||||
}
|
||||
|
||||
// Return array of identifiers
|
||||
return result.toArray((Object[]) Array.newInstance(pObjClass,
|
||||
result.size()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads one object implementing the DatabaseReadable interface from the
|
||||
* database.
|
||||
*
|
||||
* @param readable A DatabaseReadable object
|
||||
* @return The Object read, or null in no object is found
|
||||
*/
|
||||
|
||||
public Object readObject(DatabaseReadable pReadable) throws SQLException {
|
||||
return readObject(pReadable.getId(), pReadable.getClass(),
|
||||
pReadable.getMapping());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the object with the given id from the database, using the given
|
||||
* mapping.
|
||||
*
|
||||
* @param id An object uniquely identifying the object to read
|
||||
* @param objClass The clas
|
||||
* @return The Object read, or null in no object is found
|
||||
*/
|
||||
|
||||
public Object readObject(Object pId, Class pObjClass, Hashtable pMapping)
|
||||
throws SQLException {
|
||||
return readObject(pId, pObjClass, pMapping, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all the objects of the given type from the
|
||||
* database. The object must implement the DatabaseReadable interface.
|
||||
*
|
||||
* @return An array of Objects, or an zero-length array if none was found
|
||||
*/
|
||||
|
||||
public Object[] readObjects(DatabaseReadable pReadable)
|
||||
throws SQLException {
|
||||
return readObjects(pReadable.getClass(),
|
||||
pReadable.getMapping(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property value to an object using reflection
|
||||
*
|
||||
* @param obj The object to get a property from
|
||||
* @param property The name of the property
|
||||
* @param value The property value
|
||||
*
|
||||
*/
|
||||
|
||||
private void setPropertyValue(Object pObj, String pProperty,
|
||||
Object pValue) {
|
||||
|
||||
Method m = null;
|
||||
Class[] cl = {pValue.getClass()};
|
||||
|
||||
try {
|
||||
//Util.setPropertyValue(pObj, pProperty, pValue);
|
||||
|
||||
// Find method
|
||||
m = pObj.getClass().
|
||||
getMethod("set" + StringUtil.capitalize(pProperty), cl);
|
||||
// Invoke it
|
||||
Object[] args = {pValue};
|
||||
m.invoke(pObj, args);
|
||||
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (IllegalAccessException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
catch (InvocationTargetException ite) {
|
||||
ite.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the property value from an object using reflection
|
||||
*
|
||||
* @param obj The object to get a property from
|
||||
* @param property The name of the property
|
||||
*
|
||||
* @return The property value as an Object
|
||||
*/
|
||||
|
||||
private Object getPropertyValue(Object pObj, String pProperty) {
|
||||
|
||||
Method m = null;
|
||||
Class[] cl = new Class[0];
|
||||
|
||||
try {
|
||||
//return Util.getPropertyValue(pObj, pProperty);
|
||||
|
||||
// Find method
|
||||
m = pObj.getClass().
|
||||
getMethod("get" + StringUtil.capitalize(pProperty),
|
||||
new Class[0]);
|
||||
// Invoke it
|
||||
Object result = m.invoke(pObj, new Object[0]);
|
||||
return result;
|
||||
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (IllegalAccessException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
catch (InvocationTargetException ite) {
|
||||
ite.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and sets the child properties of the given parent object.
|
||||
*
|
||||
* @param parent The object to set the child obects to.
|
||||
* @param om The ObjectMapper of the parent object.
|
||||
*/
|
||||
|
||||
private void setChildObjects(Object pParent, ObjectMapper pOM)
|
||||
throws SQLException {
|
||||
if (pOM == null) {
|
||||
throw new NullPointerException("ObjectMapper in readChildObjects "
|
||||
+ "cannot be null!!");
|
||||
}
|
||||
|
||||
for (Enumeration keys = pOM.mMapTypes.keys(); keys.hasMoreElements();) {
|
||||
String property = (String) keys.nextElement();
|
||||
String mapType = (String) pOM.mMapTypes.get(property);
|
||||
|
||||
if (property.length() <= 0 || mapType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the id of the parent
|
||||
Object id = getPropertyValue(pParent,
|
||||
pOM.getProperty(pOM.getPrimaryKey()));
|
||||
|
||||
if (mapType.equals(ObjectMapper.OBJECTMAP)) {
|
||||
// OBJECT Mapping
|
||||
|
||||
// Get the class for this property
|
||||
Class objectClass = (Class) pOM.mClasses.get(property);
|
||||
|
||||
DatabaseReadable dbr = null;
|
||||
try {
|
||||
dbr = (DatabaseReadable) objectClass.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
mLog.logError(e);
|
||||
}
|
||||
|
||||
/*
|
||||
Properties mapping = readMapping(objectClass);
|
||||
*/
|
||||
|
||||
// Get property mapping for child object
|
||||
if (pOM.mJoins.containsKey(property))
|
||||
// mapping.setProperty(".join", (String) pOM.joins.get(property));
|
||||
dbr.getMapping().put(".join", pOM.mJoins.get(property));
|
||||
|
||||
// Find id and put in where hash
|
||||
Hashtable where = new Hashtable();
|
||||
|
||||
// String foreignKey = mapping.getProperty(".foreignKey");
|
||||
String foreignKey = (String)
|
||||
dbr.getMapping().get(".foreignKey");
|
||||
|
||||
if (foreignKey != null) {
|
||||
where.put(".foreignKey", id);
|
||||
}
|
||||
|
||||
Object[] child = readObjects(dbr, where);
|
||||
// Object[] child = readObjects(objectClass, mapping, where);
|
||||
|
||||
if (child.length < 1)
|
||||
throw new SQLException("No child object with foreign key "
|
||||
+ foreignKey + "=" + id);
|
||||
else if (child.length != 1)
|
||||
throw new SQLException("More than one object with foreign "
|
||||
+ "key " + foreignKey + "=" + id);
|
||||
|
||||
// Set child object to the parent
|
||||
setPropertyValue(pParent, property, child[0]);
|
||||
}
|
||||
else if (mapType.equals(ObjectMapper.COLLECTIONMAP)) {
|
||||
// COLLECTION Mapping
|
||||
|
||||
// Get property mapping for child object
|
||||
Hashtable mapping = pOM.getPropertyMapping(property);
|
||||
|
||||
// Find id and put in where hash
|
||||
Hashtable where = new Hashtable();
|
||||
String foreignKey = (String) mapping.get(".foreignKey");
|
||||
if (foreignKey != null) {
|
||||
where.put(".foreignKey", id);
|
||||
}
|
||||
|
||||
DBObject dbr = new DBObject();
|
||||
dbr.mapping = mapping; // ugh...
|
||||
// Read the objects
|
||||
Object[] objs = readObjects(dbr, where);
|
||||
|
||||
// Put the objects in a hash
|
||||
Hashtable children = new Hashtable();
|
||||
for (int i = 0; i < objs.length; i++) {
|
||||
children.put(((DBObject) objs[i]).getId(),
|
||||
((DBObject) objs[i]).getObject());
|
||||
}
|
||||
|
||||
// Set child properties to parent object
|
||||
setPropertyValue(pParent, property, children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all objects from the database, using the given mapping.
|
||||
*
|
||||
* @param objClass The class of the objects to read
|
||||
* @param mapping The hashtable containing the object mapping
|
||||
*
|
||||
* @return An array of Objects, or an zero-length array if none was found
|
||||
*/
|
||||
|
||||
public Object[] readObjects(Class pObjClass, Hashtable pMapping)
|
||||
throws SQLException {
|
||||
return readObjects(pObjClass, pMapping, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds extra SQL WHERE clause
|
||||
*
|
||||
* @param keys An array of ID names
|
||||
* @param mapping The hashtable containing the object mapping
|
||||
*
|
||||
* @return A string containing valid SQL
|
||||
*/
|
||||
|
||||
private String buildWhereClause(String[] pKeys, Hashtable pMapping) {
|
||||
StringBuilder sqlBuf = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < pKeys.length; i++) {
|
||||
String column = (String) pMapping.get(pKeys[i]);
|
||||
sqlBuf.append(" AND ");
|
||||
sqlBuf.append(column);
|
||||
sqlBuf.append(" = ?");
|
||||
}
|
||||
|
||||
return sqlBuf.toString();
|
||||
|
||||
}
|
||||
|
||||
private String buildIdInClause(Object[] pIds, Hashtable pMapping) {
|
||||
StringBuilder sqlBuf = new StringBuilder();
|
||||
|
||||
if (pIds != null && pIds.length > 0) {
|
||||
sqlBuf.append(" AND ");
|
||||
sqlBuf.append(pMapping.get(".primaryKey"));
|
||||
sqlBuf.append(" IN (");
|
||||
|
||||
for (int i = 0; i < pIds.length; i++) {
|
||||
sqlBuf.append(pIds[i]); // SETTE INN '?' ???
|
||||
sqlBuf.append(", ");
|
||||
}
|
||||
sqlBuf.append(")");
|
||||
}
|
||||
|
||||
return sqlBuf.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all objects from the database, using the given mapping.
|
||||
*
|
||||
* @param readable A DatabaseReadable object
|
||||
* @param mapping The hashtable containing the object mapping
|
||||
*
|
||||
* @return An array of Objects, or an zero-length array if none was found
|
||||
*/
|
||||
|
||||
public Object[] readObjects(DatabaseReadable pReadable, Hashtable pWhere)
|
||||
throws SQLException {
|
||||
return readObjects(pReadable.getClass(),
|
||||
pReadable.getMapping(), pWhere);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the object with the given id from the database, using the given
|
||||
* mapping.
|
||||
* This is the most general form of readObject().
|
||||
*
|
||||
* @param id An object uniquely identifying the object to read
|
||||
* @param objClass The class of the object to read
|
||||
* @param mapping The hashtable containing the object mapping
|
||||
* @param where An hashtable containing extra criteria for the read
|
||||
*
|
||||
* @return An array of Objects, or an zero-length array if none was found
|
||||
*/
|
||||
|
||||
public Object readObject(Object pId, Class pObjClass,
|
||||
Hashtable pMapping, Hashtable pWhere)
|
||||
throws SQLException {
|
||||
ObjectMapper om = new ObjectMapper(pObjClass, pMapping);
|
||||
return readObject0(pId, pObjClass, om, pWhere);
|
||||
}
|
||||
|
||||
public Object readObjects(Object[] pIds, Class pObjClass,
|
||||
Hashtable pMapping, Hashtable pWhere)
|
||||
throws SQLException {
|
||||
ObjectMapper om = new ObjectMapper(pObjClass, pMapping);
|
||||
return readObjects0(pIds, pObjClass, om, pWhere);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all objects from the database, using the given mapping.
|
||||
* This is the most general form of readObjects().
|
||||
*
|
||||
* @param objClass The class of the objects to read
|
||||
* @param mapping The hashtable containing the object mapping
|
||||
* @param where An hashtable containing extra criteria for the read
|
||||
*
|
||||
* @return An array of Objects, or an zero-length array if none was found
|
||||
*/
|
||||
|
||||
public Object[] readObjects(Class pObjClass, Hashtable pMapping,
|
||||
Hashtable pWhere) throws SQLException {
|
||||
return readObjects0(pObjClass, pMapping, pWhere);
|
||||
}
|
||||
|
||||
// readObjects implementation
|
||||
|
||||
private Object[] readObjects0(Class pObjClass, Hashtable pMapping,
|
||||
Hashtable pWhere) throws SQLException {
|
||||
ObjectMapper om = new ObjectMapper(pObjClass, pMapping);
|
||||
|
||||
Object[] ids = readIdentities(pObjClass, pMapping, pWhere, om);
|
||||
|
||||
Object[] result = readObjects0(ids, pObjClass, om, pWhere);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object[] readObjects0(Object[] pIds, Class pObjClass,
|
||||
ObjectMapper pOM, Hashtable pWhere)
|
||||
throws SQLException {
|
||||
Object[] result = new Object[pIds.length];
|
||||
|
||||
// Read each object from ID
|
||||
for (int i = 0; i < pIds.length; i++) {
|
||||
|
||||
// TODO: For better cahce efficiency/performance:
|
||||
// - Read as many objects from cache as possible
|
||||
// - Read all others in ONE query, and add to cache
|
||||
/*
|
||||
sCacheUn++;
|
||||
// Build SQL query string
|
||||
if (pWhere == null)
|
||||
pWhere = new Hashtable();
|
||||
|
||||
String[] keys = new String[pWhere.size()];
|
||||
int i = 0;
|
||||
for (Enumeration en = pWhere.keys(); en.hasMoreElements(); i++) {
|
||||
keys[i] = (String) en.nextElement();
|
||||
}
|
||||
|
||||
// Get SQL for reading identity column
|
||||
String sql = pOM.buildSelectClause() + pOM.buildFromClause() +
|
||||
+ buildWhereClause(keys, pMapping) + buildIdInClause(pIds, pMapping);
|
||||
|
||||
// Log?
|
||||
mLog.logDebug(sql + " (" + pWhere + ")");
|
||||
|
||||
|
||||
// Log?
|
||||
mLog.logDebug(sql + " (" + pWhere + ")");
|
||||
|
||||
PreparedStatement statement = null;
|
||||
|
||||
// Execute query, and map columns/properties
|
||||
try {
|
||||
statement = mConnection.prepareStatement(sql);
|
||||
|
||||
// Set keys
|
||||
for (int j = 0; j < keys.length; j++) {
|
||||
Object value = pWhere.get(keys[j]);
|
||||
|
||||
if (value instanceof Integer)
|
||||
statement.setInt(j + 1, ((Integer) value).intValue());
|
||||
else if (value instanceof BigDecimal)
|
||||
statement.setBigDecimal(j + 1, (BigDecimal) value);
|
||||
else
|
||||
statement.setString(j + 1, value.toString());
|
||||
}
|
||||
// Set ids
|
||||
for (int j = 0; j < pIds.length; j++) {
|
||||
Object id = pIds[i];
|
||||
|
||||
if (id instanceof Integer)
|
||||
statement.setInt(j + 1, ((Integer) id).intValue());
|
||||
else if (id instanceof BigDecimal)
|
||||
statement.setBigDecimal(j + 1, (BigDecimal) id);
|
||||
else
|
||||
statement.setString(j + 1, id.toString());
|
||||
}
|
||||
|
||||
ResultSet rs = statement.executeQuery();
|
||||
|
||||
Object[] result = pOM.mapObjects(rs);
|
||||
|
||||
// Set child objects and return
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
// FOR THIS TO REALLY GET EFFECTIVE, WE NEED TO SET ALL
|
||||
// CHILDREN IN ONE GO!
|
||||
setChildObjects(result[i], pOM);
|
||||
mContent.put(pOM.getPrimaryKey() + "=" + pId, result[0]);
|
||||
|
||||
}
|
||||
// Return result
|
||||
return result[0];
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
Object id = getPropertyValue(result[i],
|
||||
pOM.getProperty(pOM.getPrimaryKey()));
|
||||
|
||||
result[i] = readObject0(id, pObjClass, pOM, null);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// readObject implementation, used for ALL database reads
|
||||
|
||||
static long sCacheHit;
|
||||
static long sCacheMiss;
|
||||
static long sCacheUn;
|
||||
|
||||
private Object readObject0(Object pId, Class pObjClass, ObjectMapper pOM,
|
||||
Hashtable pWhere) throws SQLException {
|
||||
if (pId == null && pWhere == null)
|
||||
throw new IllegalArgumentException("Either id or where argument"
|
||||
+ "must be non-null!");
|
||||
|
||||
// First check if object exists in cache
|
||||
if (pId != null) {
|
||||
Object o = mCache.get(pOM.getPrimaryKey() + "=" + pId);
|
||||
if (o != null) {
|
||||
sCacheHit++;
|
||||
return o;
|
||||
}
|
||||
sCacheMiss++;
|
||||
}
|
||||
else {
|
||||
sCacheUn++;
|
||||
}
|
||||
|
||||
// Create where hash
|
||||
if (pWhere == null)
|
||||
pWhere = new Hashtable();
|
||||
|
||||
// Make sure the ID is in the where hash
|
||||
if (pId != null)
|
||||
pWhere.put(pOM.getProperty(pOM.getPrimaryKey()), pId);
|
||||
|
||||
String[] keys = new String[pWhere.size()];
|
||||
Enumeration en = pWhere.keys();
|
||||
for (int i = 0; en.hasMoreElements(); i++) {
|
||||
keys[i] = (String) en.nextElement();
|
||||
}
|
||||
|
||||
// Get SQL query string
|
||||
String sql = pOM.buildSQL() + buildWhereClause(keys, pOM.mPropertiesMap);
|
||||
|
||||
// Log?
|
||||
mLog.logDebug(sql + " (" + pWhere + ")");
|
||||
|
||||
PreparedStatement statement = null;
|
||||
|
||||
// Execute query, and map columns/properties
|
||||
try {
|
||||
statement = mConnection.prepareStatement(sql);
|
||||
|
||||
for (int j = 0; j < keys.length; j++) {
|
||||
Object value = pWhere.get(keys[j]);
|
||||
|
||||
if (value instanceof Integer)
|
||||
statement.setInt(j + 1, ((Integer) value).intValue());
|
||||
else if (value instanceof BigDecimal)
|
||||
statement.setBigDecimal(j + 1, (BigDecimal) value);
|
||||
else
|
||||
statement.setString(j + 1, value.toString());
|
||||
}
|
||||
|
||||
ResultSet rs = statement.executeQuery();
|
||||
|
||||
Object[] result = pOM.mapObjects(rs);
|
||||
|
||||
// Set child objects and return
|
||||
if (result.length == 1) {
|
||||
setChildObjects(result[0], pOM);
|
||||
mCache.put(pOM.getPrimaryKey() + "=" + pId, result[0]);
|
||||
|
||||
// Return result
|
||||
return result[0];
|
||||
}
|
||||
// More than 1 is an error...
|
||||
else if (result.length > 1) {
|
||||
throw new SQLException("More than one object with primary key "
|
||||
+ pOM.getPrimaryKey() + "="
|
||||
+ pWhere.get(pOM.getProperty(pOM.getPrimaryKey())) + "!");
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
mLog.logError(sql + " (" + pWhere + ")", e);
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
mLog.logError(e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for reading a property mapping from a properties-file
|
||||
*
|
||||
*/
|
||||
|
||||
public static Properties loadMapping(Class pClass) {
|
||||
try {
|
||||
return SystemUtil.loadProperties(pClass);
|
||||
}
|
||||
catch (FileNotFoundException fnf) {
|
||||
// System.err... err...
|
||||
System.err.println("ERROR: " + fnf.getMessage());
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use loadMapping(Class) instead
|
||||
* @see #loadMapping(Class)
|
||||
*/
|
||||
|
||||
public static Properties readMapping(Class pClass) {
|
||||
return loadMapping(pClass);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class
|
||||
*/
|
||||
|
||||
class DBObject implements DatabaseReadable {
|
||||
Object id;
|
||||
Object o;
|
||||
static Hashtable mapping; // WHOA, STATIC!?!?
|
||||
|
||||
public DBObject() {
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setObject(Object o) {
|
||||
this.o = o;
|
||||
}
|
||||
public Object getObject() {
|
||||
return o;
|
||||
}
|
||||
|
||||
public Hashtable getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
396
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/SQLUtil.java
Executable file
396
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/SQLUtil.java
Executable file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.sql;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import java.sql.*;
|
||||
import java.io.*;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* A class used to test a JDBC database connection. It can also be used as a
|
||||
* really simple form of command line SQL interface, that passes all command
|
||||
* line parameters to the database as plain SQL, and returns all rows to
|
||||
* Sytem.out. <EM>Be aware that the wildcard character (*) is intercepted by
|
||||
* the console, so you have to quote your string, or escape the wildcard
|
||||
* character, otherwise you may get unpredictable results.</EM>
|
||||
* <P/>
|
||||
* <STRONG>Exmaple use</STRONG>
|
||||
* <BR/>
|
||||
* <PRE>
|
||||
* $ java -cp lib\jconn2.jar;build com.twelvemonkeys.sql.SQLUtil
|
||||
* -d com.sybase.jdbc2.jdbc.SybDriver -u "jdbc:sybase:Tds:10.248.136.42:6100"
|
||||
* -l scott -p tiger "SELECT * FROM emp"</PRE>
|
||||
* <EM>Make sure sure to include the path to your JDBC driver in the java class
|
||||
* path!</EM>
|
||||
*
|
||||
* @author Philippe B<>al (phbe@iconmedialab.no)
|
||||
* @author Harald Kuhr (haraldk@iconmedialab.no)
|
||||
* @author last modified by $author: WMHAKUR $
|
||||
* @version $id: $
|
||||
* @see DatabaseConnection
|
||||
*/
|
||||
public class SQLUtil {
|
||||
/**
|
||||
* Method main
|
||||
*
|
||||
* @param pArgs
|
||||
* @throws SQLException
|
||||
*
|
||||
* @todo Refactor the long and ugly main method...
|
||||
* Consider: - extract method parserArgs(String[])::Properties (how do we
|
||||
* get the rest of the arguments? getProperty("_ARGV")?
|
||||
* Make the Properties/Map an argument and return int with last
|
||||
* option index?
|
||||
* - extract method getStatementReader(Properties)
|
||||
*/
|
||||
public static void main(String[] pArgs) throws SQLException, IOException {
|
||||
String user = null;
|
||||
String password = null;
|
||||
String url = null;
|
||||
String driver = null;
|
||||
String configFileName = null;
|
||||
String scriptFileName = null;
|
||||
String scriptSQLDelim = "go";
|
||||
int argIdx = 0;
|
||||
boolean errArgs = false;
|
||||
|
||||
while ((argIdx < pArgs.length) && (pArgs[argIdx].charAt(0) == '-') && (pArgs[argIdx].length() >= 2)) {
|
||||
if ((pArgs[argIdx].charAt(1) == 'l') || pArgs[argIdx].equals("--login")) {
|
||||
argIdx++;
|
||||
user = pArgs[argIdx++];
|
||||
}
|
||||
else if ((pArgs[argIdx].charAt(1) == 'p') || pArgs[argIdx].equals("--password")) {
|
||||
argIdx++;
|
||||
password = pArgs[argIdx++];
|
||||
}
|
||||
else if ((pArgs[argIdx].charAt(1) == 'u') || pArgs[argIdx].equals("--url")) {
|
||||
argIdx++;
|
||||
url = pArgs[argIdx++];
|
||||
}
|
||||
else if ((pArgs[argIdx].charAt(1) == 'd') || pArgs[argIdx].equals("--driver")) {
|
||||
argIdx++;
|
||||
driver = pArgs[argIdx++];
|
||||
}
|
||||
else if ((pArgs[argIdx].charAt(1) == 'c') || pArgs[argIdx].equals("--config")) {
|
||||
argIdx++;
|
||||
configFileName = pArgs[argIdx++];
|
||||
}
|
||||
else if ((pArgs[argIdx].charAt(1) == 's') || pArgs[argIdx].equals("--script")) {
|
||||
argIdx++;
|
||||
scriptFileName = pArgs[argIdx++];
|
||||
}
|
||||
else if ((pArgs[argIdx].charAt(1) == 'h') || pArgs[argIdx].equals("--help")) {
|
||||
argIdx++;
|
||||
errArgs = true;
|
||||
}
|
||||
else {
|
||||
System.err.println("Unknown option \"" + pArgs[argIdx++] + "\"");
|
||||
}
|
||||
}
|
||||
if (errArgs || (scriptFileName == null && (pArgs.length < (argIdx + 1)))) {
|
||||
System.err.println("Usage: SQLUtil [--help|-h] [--login|-l <login-name>] [--password|-p <password>] [--driver|-d <jdbc-driver-class>] [--url|-u <connect url>] [--config|-c <config-file>] [--script|-s <script-file>] <sql statement> ");
|
||||
System.exit(5);
|
||||
}
|
||||
|
||||
// If config file, read config and use as defaults
|
||||
// NOTE: Command line options override!
|
||||
if (!StringUtil.isEmpty(configFileName)) {
|
||||
Properties config = new Properties();
|
||||
File configFile = new File(configFileName);
|
||||
if (!configFile.exists()) {
|
||||
System.err.println("Config file " + configFile.getAbsolutePath() + " does not exist.");
|
||||
System.exit(10);
|
||||
}
|
||||
|
||||
InputStream in = new FileInputStream(configFile);
|
||||
try {
|
||||
config.load(in);
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
if (driver == null) {
|
||||
driver = config.getProperty("driver");
|
||||
}
|
||||
if (url == null) {
|
||||
url = config.getProperty("url");
|
||||
}
|
||||
if (user == null) {
|
||||
user = config.getProperty("login");
|
||||
}
|
||||
if (password == null) {
|
||||
password = config.getProperty("password");
|
||||
}
|
||||
}
|
||||
|
||||
// Register JDBC driver
|
||||
if (driver != null) {
|
||||
registerDriver(driver);
|
||||
}
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
// Use default connection from DatabaseConnection.properties
|
||||
conn = DatabaseConnection.getConnection(user, password, url);
|
||||
if (conn == null) {
|
||||
System.err.println("No connection.");
|
||||
System.exit(10);
|
||||
}
|
||||
|
||||
BufferedReader reader;
|
||||
if (scriptFileName != null) {
|
||||
// Read SQL from file
|
||||
File file = new File(scriptFileName);
|
||||
if (!file.exists()) {
|
||||
System.err.println("Script file " + file.getAbsolutePath() + " does not exist.");
|
||||
System.exit(10);
|
||||
}
|
||||
|
||||
reader = new BufferedReader(new FileReader(file));
|
||||
}
|
||||
else {
|
||||
// Create SQL statement from command line params
|
||||
StringBuilder sql = new StringBuilder();
|
||||
for (int i = argIdx; i < pArgs.length; i++) {
|
||||
sql.append(pArgs[i]).append(" ");
|
||||
}
|
||||
|
||||
reader = new BufferedReader(new StringReader(sql.toString()));
|
||||
}
|
||||
|
||||
//reader.mark(10000000);
|
||||
//for (int i = 0; i < 5; i++) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
while (true) {
|
||||
// Read next line
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
// End of file, execute and quit
|
||||
String str = sql.toString();
|
||||
if (!StringUtil.isEmpty(str)) {
|
||||
executeSQL(str, conn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (line.trim().endsWith(scriptSQLDelim)) {
|
||||
// End of statement, execute and continue
|
||||
sql.append(line.substring(0, line.lastIndexOf(scriptSQLDelim)));
|
||||
executeSQL(sql.toString(), conn);
|
||||
sql.setLength(0);
|
||||
}
|
||||
else {
|
||||
sql.append(line).append(" ");
|
||||
}
|
||||
}
|
||||
//reader.reset();
|
||||
//}
|
||||
}
|
||||
finally {
|
||||
// Close the connection
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void executeSQL(String pSQL, Connection pConn) throws SQLException {
|
||||
System.out.println("Executing: " + pSQL);
|
||||
|
||||
Statement stmt = null;
|
||||
try {
|
||||
// NOTE: Experimental
|
||||
//stmt = pConn.prepareCall(pSQL);
|
||||
//boolean results = ((CallableStatement) stmt).execute();
|
||||
|
||||
// Create statement and execute
|
||||
stmt = pConn.createStatement();
|
||||
boolean results = stmt.execute(pSQL);
|
||||
|
||||
int updateCount = -1;
|
||||
|
||||
SQLWarning warning = stmt.getWarnings();
|
||||
while (warning != null) {
|
||||
System.out.println("Warning: " + warning.getMessage());
|
||||
warning = warning.getNextWarning();
|
||||
}
|
||||
|
||||
// More result sets to process?
|
||||
while (results || (updateCount = stmt.getUpdateCount()) != -1) {
|
||||
// INSERT, UPDATE or DELETE statement (no result set).
|
||||
if (!results && (updateCount >= 0)) {
|
||||
System.out.println("Operation successfull. " + updateCount + " row" + ((updateCount != 1) ? "s" : "") + " affected.");
|
||||
System.out.println();
|
||||
}
|
||||
// SELECT statement or stored procedure
|
||||
else {
|
||||
processResultSet(stmt.getResultSet());
|
||||
}
|
||||
|
||||
// More results?
|
||||
results = stmt.getMoreResults();
|
||||
}
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
System.err.println("Error: " + sqle.getMessage());
|
||||
while ((sqle = sqle.getNextException()) != null) {
|
||||
System.err.println(" " + sqle);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Close the statement
|
||||
if (stmt != null) {
|
||||
stmt.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Create interface ResultSetProcessor
|
||||
// -- processWarnings(SQLWarning pWarnings);
|
||||
// -- processMetaData(ResultSetMetaData pMetas); ??
|
||||
// -- processResultSet(ResultSet pResult);
|
||||
// TODO: Add parameter pResultSetProcessor to method
|
||||
// TODO: Extract contents of this method to class Default/CLIRSP
|
||||
// TODO: Create new class JTableRSP that creates (?) and populates a JTable
|
||||
// or a TableModel (?)
|
||||
private static void processResultSet(ResultSet pResultSet) throws SQLException {
|
||||
try {
|
||||
// Get meta data
|
||||
ResultSetMetaData meta = pResultSet.getMetaData();
|
||||
|
||||
// Print any warnings that might have occured
|
||||
SQLWarning warning = pResultSet.getWarnings();
|
||||
while (warning != null) {
|
||||
System.out.println("Warning: " + warning.getMessage());
|
||||
warning = warning.getNextWarning();
|
||||
}
|
||||
|
||||
// Get the number of columns in the result set
|
||||
int numCols = meta.getColumnCount();
|
||||
|
||||
for (int i = 1; i <= numCols; i++) {
|
||||
boolean prepend = isNumeric(meta.getColumnType(i));
|
||||
|
||||
String label = maybePad(meta.getColumnLabel(i), meta.getColumnDisplaySize(i), " ", prepend);
|
||||
|
||||
System.out.print(label + "\t");
|
||||
}
|
||||
System.out.println();
|
||||
for (int i = 1; i <= numCols; i++) {
|
||||
boolean prepend = isNumeric(meta.getColumnType(i));
|
||||
String label = maybePad("(" + meta.getColumnTypeName(i) + "/" + meta.getColumnClassName(i) + ")", meta.getColumnDisplaySize(i), " ", prepend);
|
||||
System.out.print(label + "\t");
|
||||
}
|
||||
System.out.println();
|
||||
for (int i = 1; i <= numCols; i++) {
|
||||
String label = maybePad("", meta.getColumnDisplaySize(i), "-", false);
|
||||
System.out.print(label + "\t");
|
||||
}
|
||||
System.out.println();
|
||||
while (pResultSet.next()) {
|
||||
for (int i = 1; i <= numCols; i++) {
|
||||
boolean prepend = isNumeric(meta.getColumnType(i));
|
||||
String value = maybePad(String.valueOf(pResultSet.getString(i)), meta.getColumnDisplaySize(i), " ", prepend);
|
||||
System.out.print(value + "\t");
|
||||
//System.out.print(pResultSet.getString(i) + "\t");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
System.err.println("Error: " + sqle.getMessage());
|
||||
while ((sqle = sqle.getNextException()) != null) {
|
||||
System.err.println(" " + sqle);
|
||||
}
|
||||
throw sqle;
|
||||
}
|
||||
finally {
|
||||
if (pResultSet != null) {
|
||||
pResultSet.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String maybePad(String pString, int pColumnDisplaySize, String pPad, boolean pPrepend) {
|
||||
String padded;
|
||||
if (pColumnDisplaySize < 100) {
|
||||
padded = StringUtil.pad(pString, pColumnDisplaySize, pPad, pPrepend);
|
||||
}
|
||||
else {
|
||||
padded = StringUtil.pad(pString, 100, pPad, pPrepend);
|
||||
}
|
||||
return padded;
|
||||
}
|
||||
|
||||
private static boolean isNumeric(int pColumnType) {
|
||||
return (pColumnType == Types.INTEGER || pColumnType == Types.DECIMAL
|
||||
|| pColumnType == Types.TINYINT || pColumnType == Types.BIGINT
|
||||
|| pColumnType == Types.DOUBLE || pColumnType == Types.FLOAT
|
||||
|| pColumnType == Types.NUMERIC || pColumnType == Types.REAL
|
||||
|| pColumnType == Types.SMALLINT);
|
||||
}
|
||||
|
||||
public static boolean isDriverAvailable(String pDriver) {
|
||||
//ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
Class.forName(pDriver, false, null); // null means the caller's ClassLoader
|
||||
return true;
|
||||
}
|
||||
catch (ClassNotFoundException ignore) {
|
||||
// Ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void registerDriver(String pDriver) {
|
||||
// Register JDBC driver
|
||||
try {
|
||||
Class.forName(pDriver).newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Driver class not found: " + e.getMessage(), e);
|
||||
//System.err.println("Driver class not found: " + e.getMessage());
|
||||
//System.exit(5);
|
||||
}
|
||||
catch (InstantiationException e) {
|
||||
throw new RuntimeException("Driver class could not be instantiated: " + e.getMessage(), e);
|
||||
//System.err.println("Driver class could not be instantiated: " + e.getMessage());
|
||||
//System.exit(5);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Driver class could not be instantiated: " + e.getMessage(), e);
|
||||
//System.err.println("Driver class could not be instantiated: " + e.getMessage());
|
||||
//System.exit(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/package.html
Executable file
12
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/sql/package.html
Executable file
@@ -0,0 +1,12 @@
|
||||
<HTML>
|
||||
|
||||
<BODY>
|
||||
Provides classes for database access through JDBC.
|
||||
The package contains warious mechanisms to et connections, read (currently) and write (future) objects from a database, etc.
|
||||
|
||||
@see java.sql
|
||||
@see com.twelvemonkeys.sql.ObjectReader
|
||||
@see com.twelvemonkeys.sql.DatabaseConnection
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
/**
|
||||
* AbstractResource class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/AbstractResource.java#1 $
|
||||
*/
|
||||
abstract class AbstractResource implements Resource {
|
||||
protected final Object resourceId;
|
||||
protected final Object wrappedResource;
|
||||
|
||||
/**
|
||||
* Creates a {@code Resource}.
|
||||
*
|
||||
* @param pResourceId
|
||||
* @param pWrappedResource
|
||||
*/
|
||||
protected AbstractResource(Object pResourceId, Object pWrappedResource) {
|
||||
if (pResourceId == null) {
|
||||
throw new IllegalArgumentException("id == null");
|
||||
}
|
||||
if (pWrappedResource == null) {
|
||||
throw new IllegalArgumentException("resource == null");
|
||||
}
|
||||
|
||||
resourceId = pResourceId;
|
||||
wrappedResource = pWrappedResource;
|
||||
}
|
||||
|
||||
public final Object getId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation simply returns {@code asURL().toExternalForm()}.
|
||||
*
|
||||
* @return a string representation of this resource
|
||||
*/
|
||||
public String toString() {
|
||||
return asURL().toExternalForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defautl implementation returns {@code mWrapped.hashCode()}.
|
||||
*
|
||||
* @return {@code mWrapped.hashCode()}
|
||||
*/
|
||||
public int hashCode() {
|
||||
return wrappedResource.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation
|
||||
*
|
||||
* @param pObject
|
||||
* @return
|
||||
*/
|
||||
public boolean equals(Object pObject) {
|
||||
return pObject instanceof AbstractResource
|
||||
&& wrappedResource.equals(((AbstractResource) pObject).wrappedResource);
|
||||
}
|
||||
}
|
||||
52
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/BooleanKey.java
Executable file
52
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/BooleanKey.java
Executable file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* BooleanKey class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/BooleanKey.java#1 $
|
||||
*/
|
||||
public class BooleanKey extends TypedMap.AbstractKey implements Serializable {
|
||||
public BooleanKey() {
|
||||
super();
|
||||
}
|
||||
|
||||
public BooleanKey(String pName) {
|
||||
super(pName);
|
||||
}
|
||||
|
||||
public boolean isCompatibleValue(Object pValue) {
|
||||
return pValue instanceof Boolean;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* FileResource class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/FileResource.java#1 $
|
||||
*/
|
||||
final class FileResource extends AbstractResource {
|
||||
|
||||
/**
|
||||
* Creates a {@code FileResource}.
|
||||
*
|
||||
* @param pResourceId the resource id
|
||||
* @param pFile the file resource
|
||||
*/
|
||||
public FileResource(Object pResourceId, File pFile) {
|
||||
super(pResourceId, pFile);
|
||||
}
|
||||
|
||||
private File getFile() {
|
||||
return (File) wrappedResource;
|
||||
}
|
||||
|
||||
public URL asURL() {
|
||||
try {
|
||||
return getFile().toURL();
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new IllegalStateException("The file \"" + getFile().getAbsolutePath()
|
||||
+ "\" is not parseable as an URL: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream asStream() throws IOException {
|
||||
return new FileInputStream(getFile());
|
||||
}
|
||||
|
||||
public long lastModified() {
|
||||
return getFile().lastModified();
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LZWEncoder.
|
||||
* <p/>
|
||||
*
|
||||
* @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/LZWEncoder.java#2 $
|
||||
*/
|
||||
final class LZWEncoder implements Encoder {
|
||||
public void encode(OutputStream pStream, byte[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
// TODO: Implement
|
||||
// TODO: We probably need a GIF specific subclass
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* FloatKey class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/FloatKey.java#1 $
|
||||
*/
|
||||
public class FloatKey extends TypedMap.AbstractKey implements Serializable {
|
||||
public FloatKey() {
|
||||
super();
|
||||
}
|
||||
|
||||
public FloatKey(String pName) {
|
||||
super(pName);
|
||||
}
|
||||
|
||||
public boolean isCompatibleValue(Object pValue) {
|
||||
return pValue instanceof Float;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LZWDecoder.
|
||||
* <p/>
|
||||
*
|
||||
* @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/LZWDecoder.java#2 $
|
||||
*/
|
||||
final class LZWDecoder implements Decoder {
|
||||
public int decode(InputStream pStream, byte[] pBuffer) throws IOException {
|
||||
return 0; // TODO: Implement
|
||||
// TODO: We probably need a GIF specific subclass
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* IntegerKey class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/IntegerKey.java#1 $
|
||||
*/
|
||||
public class IntegerKey extends TypedMap.AbstractKey implements Serializable {
|
||||
public IntegerKey(String pName) {
|
||||
super(pName);
|
||||
}
|
||||
|
||||
public IntegerKey() {
|
||||
}
|
||||
|
||||
public boolean isCompatibleValue(Object pValue) {
|
||||
return pValue instanceof Integer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MappedBeanFactory
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/main/java/com/twelvemonkeys/sandbox/MappedBeanFactory.java#1 $
|
||||
*/
|
||||
public final class MappedBeanFactory {
|
||||
|
||||
// TODO: Map<String, ?> getMap(Object pProxy)
|
||||
|
||||
// TODO: Consider a @NotNull annotation that will allow for throwing IllegalArgumentExceptions
|
||||
// - Or a more general validator approach for custom fields...
|
||||
|
||||
// NOTE: Specifying default values does not make much sense, as it would be possible to just add values to the map
|
||||
// in the first place
|
||||
|
||||
// TODO: Replace Converter varargs with new class a PropertyConverterConfiguration
|
||||
// - setPropertyConverter(String propertyName, Converter from, Converter to)
|
||||
// - setDefaultConverter(Class from, Class to, Converter)
|
||||
// TODO: Validators? Allows for more than just NotNull checking
|
||||
// TODO: Mixin support for other methods, and we are on the way to full-blown AOP.. ;-)
|
||||
// TODO: Delegate for behaviour?
|
||||
|
||||
// TODO: Consider being fail-fast for primitives without default values?
|
||||
// Or have default values be the same as they would have been if class members (false/0/null)
|
||||
// NOTE: There's a difference between a map with a null value for a key, and no presence of that key at all
|
||||
|
||||
// TODO: ProperyChange support!
|
||||
|
||||
private MappedBeanFactory() {
|
||||
}
|
||||
|
||||
static <T> T as(final Class<T> pClass, final Converter... pConverters) {
|
||||
// TODO: Add neccessary default initializer stuff here.
|
||||
return as(pClass, new LinkedHashMap<String, Object>(), pConverters);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
static <T> T as(final Class<T> pClass, final Map<String, ?> pMap, final Converter... pConverters) {
|
||||
return asImpl(pClass, (Map<String, Object>) pMap, pConverters);
|
||||
}
|
||||
|
||||
static <T> T asImpl(final Class<T> pClass, final Map<String, Object> pMap, final Converter[] pConverters) {
|
||||
// TODO: Report clashing? Named converters?
|
||||
final Map<ConverterKey, Converter> converters = new HashMap<ConverterKey, Converter>() {
|
||||
@Override
|
||||
public Converter get(Object key) {
|
||||
Converter converter = super.get(key);
|
||||
return converter != null ? converter : Converter.NULL;
|
||||
}
|
||||
};
|
||||
|
||||
for (Converter converter : pConverters) {
|
||||
converters.put(new ConverterKey(converter.getFromType(), converter.getToType()), converter);
|
||||
}
|
||||
|
||||
return pClass.cast(
|
||||
Proxy.newProxyInstance(
|
||||
pClass.getClassLoader(),
|
||||
new Class<?>[]{pClass, Serializable.class}, // TODO: Maybe Serializable should be specified by pClass?
|
||||
new MappedBeanInvocationHandler(pClass, pMap, converters)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static class ConverterKey {
|
||||
private Class<?> to;
|
||||
private Class<?> from;
|
||||
|
||||
ConverterKey(Class<?> pFrom, Class<?> pTo) {
|
||||
to = pTo;
|
||||
from = pFrom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object pOther) {
|
||||
if (this == pOther) {
|
||||
return true;
|
||||
}
|
||||
if (pOther == null || getClass() != pOther.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConverterKey that = (ConverterKey) pOther;
|
||||
|
||||
return from == that.from && to == that.to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = to != null ? to.hashCode() : 0;
|
||||
result = 31 * result + (from != null ? from.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s->%s", from, to);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Converter<F, T> {
|
||||
|
||||
Converter NULL = new Converter() {
|
||||
public Class<?> getFromType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Class<?> getToType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object convert(Object value, Object old) {
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
throw new ClassCastException(value.getClass().getName());
|
||||
}
|
||||
};
|
||||
|
||||
Class<F> getFromType();
|
||||
|
||||
Class<T> getToType();
|
||||
|
||||
T convert(F value, T old);
|
||||
}
|
||||
|
||||
// Add guards for null values by throwing IllegalArgumentExceptions for parameters
|
||||
// TODO: Throw IllegalArgumentException at CREATION time, if value in map is null for a method with @NotNull return type
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
|
||||
static @interface NotNull {
|
||||
}
|
||||
|
||||
// For setter methods to have automatic property change support
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
// TODO: Consider field as well?
|
||||
static @interface Observable {
|
||||
}
|
||||
|
||||
// TODO: Decide on default value annotation
|
||||
// Alternate default value annotation
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultValue {
|
||||
boolean booleanValue() default false;
|
||||
byte byteValue() default 0;
|
||||
char charValue() default 0;
|
||||
short shortValue() default 0;
|
||||
int intValue() default 0;
|
||||
float floatValue() default 0f;
|
||||
long longValue() default 0l;
|
||||
double doubleValue() default 0d;
|
||||
}
|
||||
|
||||
|
||||
// Default values for primitive types
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultBooleanValue {
|
||||
boolean value() default false;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultByteValue {
|
||||
byte value() default 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultCharValue {
|
||||
char value() default 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultShortValue {
|
||||
short value() default 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultIntValue {
|
||||
int value() default 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultFloatValue {
|
||||
float value() default 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultLongValue {
|
||||
long value() default 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface DefaultDouleValue {
|
||||
double value() default 0;
|
||||
}
|
||||
|
||||
// TODO: Does it make sense to NOT just put the value in the map?
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
private static @interface DefaultStringValue {
|
||||
String value(); // TODO: Do we want a default empty string?
|
||||
}
|
||||
|
||||
private static class MappedBeanInvocationHandler implements InvocationHandler, Serializable {
|
||||
|
||||
private static final Method OBJECT_TO_STRING = getObjectMethod("toString");
|
||||
private static final Method OBJECT_HASH_CODE = getObjectMethod("hashCode");
|
||||
private static final Method OBJECT_EQUALS = getObjectMethod("equals", Object.class);
|
||||
private static final Method OBJECT_CLONE = getObjectMethod("clone");
|
||||
|
||||
private final Class<?> mClass;
|
||||
private final Map<String, Object> mMap;
|
||||
private final Map<ConverterKey, Converter> mConverters;
|
||||
|
||||
private transient Map<Method, String> mReadMethods = new HashMap<Method, String>();
|
||||
private transient Map<Method, String> mWriteMethods = new HashMap<Method, String>();
|
||||
|
||||
private static Method getObjectMethod(final String pMethodName, final Class<?>... pParams) {
|
||||
try {
|
||||
return Object.class.getDeclaredMethod(pMethodName, pParams);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new Error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
mReadMethods = new HashMap<Method, String>();
|
||||
mWriteMethods = new HashMap<Method, String>();
|
||||
|
||||
introspectBean(mClass, mReadMethods, mWriteMethods);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappedBeanInvocationHandler(Class<?> pClass, Map<String, Object> pMap, Map<ConverterKey, Converter> pConverters) {
|
||||
mClass = pClass;
|
||||
mMap = pMap;
|
||||
mConverters = pConverters;
|
||||
|
||||
introspectBean(mClass, mReadMethods, mWriteMethods);
|
||||
}
|
||||
|
||||
private void introspectBean(Class<?> pClass, Map<Method, String> pReadMethods, Map<Method, String> pWriteMethods) {
|
||||
try {
|
||||
BeanInfo info = Introspector.getBeanInfo(pClass);
|
||||
PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
|
||||
for (PropertyDescriptor descriptor : descriptors) {
|
||||
String name = descriptor.getName();
|
||||
|
||||
Method read = descriptor.getReadMethod();
|
||||
if (read != null) {
|
||||
pReadMethods.put(read, name);
|
||||
}
|
||||
|
||||
Method write = descriptor.getWriteMethod();
|
||||
if (write != null) {
|
||||
pWriteMethods.put(write, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IntrospectionException e) {
|
||||
throw new IllegalArgumentException(String.format("Class %s not introspectable: %s", pClass, e.getMessage()) , e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object invoke(final Object pProxy, final Method pMethod, final Object[] pArguments) throws Throwable {
|
||||
String property = mReadMethods.get(pMethod);
|
||||
if (property != null) {
|
||||
if (pArguments == null || pArguments.length == 0) {
|
||||
Object value = mMap.get(property);
|
||||
Class<?> type = pMethod.getReturnType();
|
||||
|
||||
if (!isCompatible(value, type)) {
|
||||
return mConverters.get(new ConverterKey(value != null ? value.getClass() : Void.class, unBoxType(type))).convert(value, null);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown parameters for " + pMethod + ": " + Arrays.toString(pArguments));
|
||||
}
|
||||
}
|
||||
|
||||
property = mWriteMethods.get(pMethod);
|
||||
if (property != null) {
|
||||
if (pArguments.length == 1) {
|
||||
Object value = pArguments[0];
|
||||
|
||||
// Make sure we don't accidentally overwrite a value that looks like ours...
|
||||
Object oldValue = mMap.get(property);
|
||||
Class<?> type = pMethod.getParameterTypes()[0];
|
||||
if (oldValue != null && !isCompatible(oldValue, type)) {
|
||||
value = mConverters.get(new ConverterKey(type, oldValue.getClass())).convert(value, oldValue);
|
||||
}
|
||||
return mMap.put(property, value);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown parameters for " + pMethod + ": " + Arrays.toString(pArguments));
|
||||
}
|
||||
}
|
||||
|
||||
if (pMethod.equals(OBJECT_TO_STRING)) {
|
||||
return proxyToString();
|
||||
}
|
||||
if (pMethod.equals(OBJECT_EQUALS)) {
|
||||
return proxyEquals(pProxy, pArguments[0]);
|
||||
}
|
||||
if (pMethod.equals(OBJECT_HASH_CODE)) {
|
||||
return proxyHashCode();
|
||||
}
|
||||
if (pMethod.getName().equals(OBJECT_CLONE.getName())
|
||||
&& Arrays.equals(pMethod.getParameterTypes(), OBJECT_CLONE.getParameterTypes())
|
||||
&& OBJECT_CLONE.getReturnType().isAssignableFrom(pMethod.getReturnType())) {
|
||||
return proxyClone();
|
||||
}
|
||||
|
||||
// Other methods not handled (for now)
|
||||
throw new AbstractMethodError(pMethod.getName());
|
||||
}
|
||||
|
||||
private boolean isCompatible(final Object pValue, final Class<?> pType) {
|
||||
return pValue == null && !pType.isPrimitive() || unBoxType(pType).isInstance(pValue);
|
||||
}
|
||||
|
||||
private Class<?> unBoxType(final Class<?> pType) {
|
||||
if (pType.isPrimitive()) {
|
||||
if (pType == boolean.class) {
|
||||
return Boolean.class;
|
||||
}
|
||||
if (pType == byte.class) {
|
||||
return Byte.class;
|
||||
}
|
||||
if (pType == char.class) {
|
||||
return Character.class;
|
||||
}
|
||||
if (pType == short.class) {
|
||||
return Short.class;
|
||||
}
|
||||
if (pType == int.class) {
|
||||
return Integer.class;
|
||||
}
|
||||
if (pType == float.class) {
|
||||
return Float.class;
|
||||
}
|
||||
if (pType == long.class) {
|
||||
return Long.class;
|
||||
}
|
||||
if (pType == double.class) {
|
||||
return Double.class;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type: " + pType);
|
||||
}
|
||||
return pType;
|
||||
}
|
||||
|
||||
private int proxyHashCode() {
|
||||
// NOTE: Implies mMap instance must follow Map.equals contract
|
||||
return mMap.hashCode();
|
||||
}
|
||||
|
||||
private boolean proxyEquals(final Object pThisProxy, final Object pThat) {
|
||||
if (pThisProxy == pThat) {
|
||||
return true;
|
||||
}
|
||||
if (pThat == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Document that subclasses are considered equal (if no extra properties)
|
||||
if (!mClass.isInstance(pThat)) {
|
||||
return false;
|
||||
}
|
||||
if (!Proxy.isProxyClass(pThat.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: This implies that we should put default values in map at creation time
|
||||
// NOTE: Implies mMap instance must follow Map.equals contract
|
||||
InvocationHandler handler = Proxy.getInvocationHandler(pThat);
|
||||
return handler.getClass() == getClass() && mMap.equals(((MappedBeanInvocationHandler) handler).mMap);
|
||||
|
||||
}
|
||||
|
||||
private Object proxyClone() throws CloneNotSupportedException {
|
||||
return as(
|
||||
mClass,
|
||||
new LinkedHashMap<String, Object>(mMap),
|
||||
mConverters.values().toArray(new Converter[mConverters.values().size()])
|
||||
);
|
||||
}
|
||||
|
||||
private String proxyToString() {
|
||||
return String.format("%s$MapProxy@%s: %s", mClass.getName(), System.identityHashCode(this), mMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/PaintKey.java
Executable file
53
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/PaintKey.java
Executable file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* PaintKey class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/PaintKey.java#1 $
|
||||
*/
|
||||
public class PaintKey extends TypedMap.AbstractKey implements Serializable {
|
||||
public PaintKey() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PaintKey(String pName) {
|
||||
super(pName);
|
||||
}
|
||||
|
||||
public boolean isCompatibleValue(Object pValue) {
|
||||
return pValue instanceof Paint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
/**
|
||||
* PersistentMap
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PersistentMap.java,v 1.0 May 13, 2009 2:31:29 PM haraldk Exp$
|
||||
*/
|
||||
public class PersistentMap {
|
||||
// TODO: Implement Map
|
||||
// TODO: Delta synchronization (db?)
|
||||
}
|
||||
|
||||
/*
|
||||
Persistent format
|
||||
|
||||
Header
|
||||
File ID 4-8 bytes
|
||||
Size
|
||||
|
||||
Entry pointer array block
|
||||
Size
|
||||
Next entry pointer block address
|
||||
Entry 1 address
|
||||
...
|
||||
Entry n address
|
||||
|
||||
Entry 1
|
||||
...
|
||||
Entry n
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Rectangle2DKey class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/Rectangle2DKey.java#1 $
|
||||
*/
|
||||
public class Rectangle2DKey extends TypedMap.AbstractKey implements Serializable {
|
||||
public Rectangle2DKey() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Rectangle2DKey(String pName) {
|
||||
super(pName);
|
||||
}
|
||||
|
||||
public boolean isCompatibleValue(Object pValue) {
|
||||
return pValue instanceof Rectangle2D;
|
||||
}
|
||||
}
|
||||
80
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/Resource.java
Executable file
80
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/Resource.java
Executable file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Resource class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/Resource.java#1 $
|
||||
*/
|
||||
public interface Resource {
|
||||
/**
|
||||
* Returns the id of this resource.
|
||||
*
|
||||
* The id might be a {@code URL}, a {@code File} or a string
|
||||
* representation of some system resource.
|
||||
* It will always be equal to the {@code resourceId} parameter
|
||||
* sent to the {@link ResourceMonitor#addResourceChangeListener} method
|
||||
* for a given resource.
|
||||
*
|
||||
* @return the id of this resource
|
||||
*/
|
||||
public Object getId();
|
||||
|
||||
/**
|
||||
* Returns the {@code URL} for the resource.
|
||||
*
|
||||
* @return the URL for the resource
|
||||
*/
|
||||
public URL asURL();
|
||||
|
||||
/**
|
||||
* Opens an input stream, that reads from this resource.
|
||||
*
|
||||
* @return an input stream, that reads from this resource.
|
||||
*
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public InputStream asStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the last modified time.
|
||||
* Should only be used for comparison.
|
||||
*
|
||||
* @return the time of the last modification of this resource, or
|
||||
* {@code -1} if the last modification time cannot be determined.
|
||||
*/
|
||||
public long lastModified();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* An {@code EventListener} that listens for updates in file or system
|
||||
* resources.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/ResourceChangeListener.java#1 $
|
||||
*/
|
||||
public interface ResourceChangeListener extends EventListener {
|
||||
/**
|
||||
* Invoked when a resource is changed.
|
||||
* Implementations that listens for multiple events, should check that
|
||||
* {@code Resource.getId()} is equal to the {@code resourceId} parameter
|
||||
* sent to the {@link ResourceMonitor#addResourceChangeListener} method.
|
||||
*
|
||||
* @param pResource changed file/url/etc.
|
||||
*/
|
||||
void resourceChanged(Resource pResource);
|
||||
}
|
||||
207
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/ResourceMonitor.java
Executable file
207
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/ResourceMonitor.java
Executable file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
// TODO: Could this be used for change-aware classloader? Woo..
|
||||
/**
|
||||
* Monitors changes is files and system resources.
|
||||
*
|
||||
* Based on example code and ideas from
|
||||
* <A href="http://www.javaworld.com/javaworld/javatips/jw-javatip125.html">Java
|
||||
* Tip 125: Set your timer for dynamic properties</A>.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/ResourceMonitor.java#1 $
|
||||
*/
|
||||
public abstract class ResourceMonitor {
|
||||
|
||||
private static final ResourceMonitor INSTANCE = new ResourceMonitor() {};
|
||||
|
||||
private Timer timer;
|
||||
|
||||
private final Map<Object, ResourceMonitorTask> timerEntries;
|
||||
|
||||
public static ResourceMonitor getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ResourceMonitor}.
|
||||
*/
|
||||
protected ResourceMonitor() {
|
||||
// Create timer, run timer thread as daemon...
|
||||
timer = new Timer(true);
|
||||
timerEntries = new HashMap<Object, ResourceMonitorTask>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a monitored {@code Resource} with a {@code ResourceChangeListener}.
|
||||
*
|
||||
* The {@code reourceId} might be a {@code File} a {@code URL} or a
|
||||
* {@code String} containing a file path, or a path to a resource in the
|
||||
* class path. Note that class path resources are resolved using the
|
||||
* given {@code ResourceChangeListener}'s {@code ClassLoader}, then
|
||||
* the current {@code Thread}'s context class loader, if not found.
|
||||
*
|
||||
* @param pListener pListener to notify when the file changed.
|
||||
* @param pResourceId id of the resource to monitor (a {@code File}
|
||||
* a {@code URL} or a {@code String} containing a file path).
|
||||
* @param pPeriod polling pPeriod in milliseconds.
|
||||
*
|
||||
* @see ClassLoader#getResource(String)
|
||||
*/
|
||||
public void addResourceChangeListener(ResourceChangeListener pListener,
|
||||
Object pResourceId, long pPeriod) throws IOException {
|
||||
// Create the task
|
||||
ResourceMonitorTask task = new ResourceMonitorTask(pListener, pResourceId);
|
||||
|
||||
// Get unique Id
|
||||
Object resourceId = getResourceId(pResourceId, pListener);
|
||||
|
||||
// Remove the old task for this Id, if any, and register the new one
|
||||
synchronized (timerEntries) {
|
||||
removeListenerInternal(resourceId);
|
||||
timerEntries.put(resourceId, task);
|
||||
}
|
||||
|
||||
timer.schedule(task, pPeriod, pPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the {@code ResourceChangeListener} from the notification list.
|
||||
*
|
||||
* @param pListener the pListener to be removed.
|
||||
* @param pResourceId name of the resource to monitor.
|
||||
*/
|
||||
public void removeResourceChangeListener(ResourceChangeListener pListener, Object pResourceId) {
|
||||
synchronized (timerEntries) {
|
||||
removeListenerInternal(getResourceId(pResourceId, pListener));
|
||||
}
|
||||
}
|
||||
|
||||
private void removeListenerInternal(Object pResourceId) {
|
||||
ResourceMonitorTask task = timerEntries.remove(pResourceId);
|
||||
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private Object getResourceId(Object pResourceName, ResourceChangeListener pListener) {
|
||||
return pResourceName.toString() + System.identityHashCode(pListener);
|
||||
}
|
||||
|
||||
private void fireResourceChangeEvent(ResourceChangeListener pListener, Resource pResource) {
|
||||
pListener.resourceChanged(pResource);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private class ResourceMonitorTask extends TimerTask {
|
||||
ResourceChangeListener listener;
|
||||
Resource monitoredResource;
|
||||
long lastModified;
|
||||
|
||||
public ResourceMonitorTask(ResourceChangeListener pListener, Object pResourceId) throws IOException {
|
||||
listener = pListener;
|
||||
lastModified = 0;
|
||||
|
||||
String resourceId = null;
|
||||
File file = null;
|
||||
URL url = null;
|
||||
if (pResourceId instanceof File) {
|
||||
file = (File) pResourceId;
|
||||
resourceId = file.getAbsolutePath(); // For use by exception only
|
||||
}
|
||||
else if (pResourceId instanceof URL) {
|
||||
url = (URL) pResourceId;
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
file = new File(url.getFile());
|
||||
}
|
||||
resourceId = url.toExternalForm(); // For use by exception only
|
||||
}
|
||||
else if (pResourceId instanceof String) {
|
||||
resourceId = (String) pResourceId; // This one might be looked up
|
||||
file = new File(resourceId);
|
||||
}
|
||||
|
||||
if (file != null && file.exists()) {
|
||||
// Easy, this is a file
|
||||
monitoredResource = new FileResource(pResourceId, file);
|
||||
//System.out.println("File: " + monitoredResource);
|
||||
}
|
||||
else {
|
||||
// No file there, but is it on CLASSPATH?
|
||||
if (url == null) {
|
||||
url = pListener.getClass().getClassLoader().getResource(resourceId);
|
||||
}
|
||||
if (url == null) {
|
||||
url = Thread.currentThread().getContextClassLoader().getResource(resourceId);
|
||||
}
|
||||
|
||||
if (url != null && "file".equals(url.getProtocol())
|
||||
&& (file = new File(url.getFile())).exists()) {
|
||||
// It's a file in classpath, so try this as an optimization
|
||||
monitoredResource = new FileResource(pResourceId, file);
|
||||
//System.out.println("File: " + monitoredResource);
|
||||
}
|
||||
else if (url != null) {
|
||||
// No, not a file, might even be an external resource
|
||||
monitoredResource = new URLResource(pResourceId, url);
|
||||
//System.out.println("URL: " + monitoredResource);
|
||||
}
|
||||
else {
|
||||
throw new FileNotFoundException(resourceId);
|
||||
}
|
||||
}
|
||||
|
||||
lastModified = monitoredResource.lastModified();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
long lastModified = monitoredResource.lastModified();
|
||||
|
||||
if (lastModified != this.lastModified) {
|
||||
this.lastModified = lastModified;
|
||||
fireResourceChangeEvent(listener, monitoredResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/StringKey.java
Executable file
52
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/StringKey.java
Executable file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* StringKey class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/StringKey.java#1 $
|
||||
*/
|
||||
public class StringKey extends TypedMap.AbstractKey implements Serializable {
|
||||
public StringKey() {
|
||||
super();
|
||||
}
|
||||
|
||||
public StringKey(String pName) {
|
||||
super(pName);
|
||||
}
|
||||
|
||||
public boolean isCompatibleValue(Object pValue) {
|
||||
return pValue instanceof String;
|
||||
}
|
||||
}
|
||||
320
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/TypedMap.java
Executable file
320
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/TypedMap.java
Executable file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* This {@code Map} implementation guarantees that the values have a type that
|
||||
* are compatible with it's key. Different keys may have different types.
|
||||
*
|
||||
* @see TypedMap.Key
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/TypedMap.java#1 $
|
||||
*/
|
||||
public class TypedMap<K extends TypedMap.Key, V> implements Map<K, V>, Serializable {
|
||||
|
||||
/**
|
||||
* The wrapped map
|
||||
*/
|
||||
protected Map<K, V> entries;
|
||||
|
||||
/**
|
||||
* Creates a {@code TypedMap}.
|
||||
* This {@code TypedMap} will be backed by a new {@code HashMap} instance.
|
||||
*/
|
||||
public TypedMap() {
|
||||
entries = new HashMap<K, V>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TypedMap} containing the same elements as the given
|
||||
* map.
|
||||
* This {@code TypedMap} will be backed by a new {@code HashMap} instance,
|
||||
* and <em>not</em> the map passed in as a paramter.
|
||||
* <p/>
|
||||
* <small>This is constructor is here to comply with the reccomendations for
|
||||
* "standard" constructors in the {@code Map} interface.</small>
|
||||
*
|
||||
* @param pMap the map used to populate this map
|
||||
* @throws ClassCastException if all keys in the map are not instances of
|
||||
* {@code TypedMap.Key}.
|
||||
* @see java.util.Map
|
||||
* @see #TypedMap(java.util.Map, boolean)
|
||||
*/
|
||||
public TypedMap(Map<? extends K, ? extends V> pMap) {
|
||||
this();
|
||||
|
||||
if (pMap != null) {
|
||||
putAll(pMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TypedMap}.
|
||||
* This {@code TypedMap} will be backed by the given {@code Map}.
|
||||
* <P/>
|
||||
* Note that structurally modifying the backing map directly (not through
|
||||
* this map or its collection views), is not allowed, and will produce
|
||||
* undeterministic exceptions.
|
||||
*
|
||||
* @param pBacking the map that will be used as backing.
|
||||
* @param pUseElements if {@code true}, the elements in the map are
|
||||
* retained. Otherwise, the map is cleared. For an empty {@code Map} the
|
||||
* parameter has no effect.
|
||||
* @throws ClassCastException if {@code pUseElements} is {@code true}
|
||||
* all keys in the map are not instances of {@code TypedMap.Key}.
|
||||
*/
|
||||
public TypedMap(Map<? extends K, ? extends V> pBacking, boolean pUseElements) {
|
||||
if (pBacking == null) {
|
||||
throw new IllegalArgumentException("backing == null");
|
||||
}
|
||||
|
||||
// This is safe, as we re-insert all values later
|
||||
//noinspection unchecked
|
||||
entries = (Map<K, V>) pBacking;
|
||||
|
||||
// Re-insert all elements to avoid undeterministic ClassCastExceptions
|
||||
if (pUseElements) {
|
||||
putAll(pBacking);
|
||||
}
|
||||
else if (entries.size() > 0) {
|
||||
entries.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of key-value mappings in this map. If the
|
||||
* map contains more than {@code Integer.MAX_VALUE} elements, returns
|
||||
* {@code Integer.MAX_VALUE}.
|
||||
*
|
||||
* @return the number of key-value mappings in this map.
|
||||
*/
|
||||
public int size() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map contains no key-value mappings.
|
||||
*
|
||||
* @return {@code true} if this map contains no key-value mappings.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return entries.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map contains a mapping for the specified
|
||||
* key.
|
||||
*
|
||||
* @param pKey key whose presence in this map is to be tested.
|
||||
* @return {@code true} if this map contains a mapping for the specified
|
||||
* key.
|
||||
*/
|
||||
public boolean containsKey(Object pKey) {
|
||||
return entries.containsKey(pKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map maps one or more keys to the
|
||||
* specified value. More formally, returns {@code true} if and only if
|
||||
* this map contains at least one mapping to a value {@code v} such that
|
||||
* {@code (pValue==null ? v==null : pValue.equals(v))}. This operation
|
||||
* will probably require time linear in the map size for most
|
||||
* implementations of the {@code Map} interface.
|
||||
*
|
||||
* @param pValue value whose presence in this map is to be tested.
|
||||
* @return {@code true} if this map maps one or more keys to the
|
||||
* specified value.
|
||||
*/
|
||||
public boolean containsValue(Object pValue) {
|
||||
return entries.containsValue(pValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which this map maps the specified key. Returns
|
||||
* {@code null} if the map contains no mapping for this key. A return
|
||||
* value of {@code null} does not <i>necessarily</i> indicate that the
|
||||
* map contains no mapping for the key; it's also possible that the map
|
||||
* explicitly maps the key to {@code null}. The {@code containsKey}
|
||||
* operation may be used to distinguish these two cases.
|
||||
*
|
||||
* @param pKey key whose associated value is to be returned.
|
||||
* @return the value to which this map maps the specified key, or
|
||||
* {@code null} if the map contains no mapping for this key.
|
||||
* @see #containsKey(java.lang.Object)
|
||||
*/
|
||||
public V get(Object pKey) {
|
||||
return entries.get(pKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the specified value with the specified key in this map.
|
||||
* If the map previously contained a mapping for
|
||||
* the key, the old value is replaced.
|
||||
*
|
||||
* @param pKey key with which the specified value is to be associated.
|
||||
* @param pValue value to be associated with the specified key.
|
||||
*
|
||||
* @return previous value associated with specified key, or {@code null}
|
||||
* if there was no mapping for key. A {@code null} return can
|
||||
* also indicate that the map previously associated {@code null}
|
||||
* with the specified pKey, if the implementation supports
|
||||
* {@code null} values.
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not compatible with the
|
||||
* key.
|
||||
*
|
||||
* @see TypedMap.Key
|
||||
*/
|
||||
public V put(K pKey, V pValue) {
|
||||
if (!pKey.isCompatibleValue(pValue)) {
|
||||
throw new IllegalArgumentException("incompatible value for key");
|
||||
}
|
||||
return entries.put(pKey, pValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping for this key from this map if present (optional
|
||||
* operation).
|
||||
*
|
||||
* @param pKey key whose mapping is to be removed from the map.
|
||||
* @return previous value associated with specified key, or {@code null}
|
||||
* if there was no mapping for key. A {@code null} return can
|
||||
* also indicate that the map previously associated {@code null}
|
||||
* with the specified key, if the implementation supports
|
||||
* {@code null} values.
|
||||
*/
|
||||
public V remove(Object pKey) {
|
||||
return entries.remove(pKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all of the mappings from the specified map to this map
|
||||
* (optional operation). These mappings will replace any mappings that
|
||||
* this map had for any of the keys currently in the specified map.
|
||||
* <P/>
|
||||
* Note: If you override this method, make sure you add each element through
|
||||
* the put method, to avoid resource leaks and undeterministic class casts.
|
||||
*
|
||||
* @param pMap Mappings to be stored in this map.
|
||||
*/
|
||||
public void putAll(Map<? extends K, ? extends V> pMap) {
|
||||
for (final Entry<? extends K, ? extends V> e : pMap.entrySet()) {
|
||||
put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all mappings from this map (optional operation).
|
||||
*/
|
||||
public void clear() {
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
public Collection<V> values() {
|
||||
return entries.values();
|
||||
}
|
||||
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return entries.entrySet();
|
||||
}
|
||||
|
||||
public Set<K> keySet() {
|
||||
return entries.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys for use with {@code TypedMap} must implement this interface.
|
||||
*
|
||||
* @see #isCompatibleValue(Object)
|
||||
*/
|
||||
public static interface Key {
|
||||
|
||||
/**
|
||||
* Tests if the given value is compatible with this {@code Key}.
|
||||
* Only compatible values may be passed to the
|
||||
* {@code TypedMap.put} method.
|
||||
*
|
||||
* @param pValue the value to test for compatibility
|
||||
* @return {@code true} if compatible, otherwise {@code false}
|
||||
*/
|
||||
boolean isCompatibleValue(Object pValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract {@code Key} implementation that allows keys to have
|
||||
* meaningful names.
|
||||
*/
|
||||
public static abstract class AbstractKey implements Key, Serializable {
|
||||
private final String mStringRep;
|
||||
|
||||
/**
|
||||
* Creates a {@code Key} with the given name.
|
||||
*
|
||||
* @param pName name of this key
|
||||
*/
|
||||
public AbstractKey(String pName) {
|
||||
if (pName == null) {
|
||||
throw new IllegalArgumentException("name == null");
|
||||
}
|
||||
mStringRep = getClass().getName() + '[' + pName + ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code Key} with no name.
|
||||
*/
|
||||
public AbstractKey() {
|
||||
this("null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mStringRep;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj == this ||
|
||||
(obj != null && obj.getClass() == getClass() &&
|
||||
mStringRep.equals(((AbstractKey) obj).mStringRep));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mStringRep.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
89
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/URLResource.java
Executable file
89
sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/URLResource.java
Executable file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/**
|
||||
* URLResource class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/URLResource.java#1 $
|
||||
*/
|
||||
final class URLResource extends AbstractResource {
|
||||
|
||||
// NOTE: For the time being, we rely on the URL class (and helpers) to do
|
||||
// some smart caching and reuse of connections...
|
||||
// TODO: Change the implementation if this is a problem
|
||||
private long lastModified = -1;
|
||||
|
||||
/**
|
||||
* Creates a {@code URLResource}.
|
||||
*
|
||||
* @param pResourceId the resource id
|
||||
* @param pURL the URL resource
|
||||
*/
|
||||
public URLResource(Object pResourceId, URL pURL) {
|
||||
super(pResourceId, pURL);
|
||||
}
|
||||
|
||||
private URL getURL() {
|
||||
return (URL) wrappedResource;
|
||||
}
|
||||
|
||||
public URL asURL() {
|
||||
return getURL();
|
||||
}
|
||||
|
||||
public InputStream asStream() throws IOException {
|
||||
URLConnection connection = getURL().openConnection();
|
||||
connection.setAllowUserInteraction(false);
|
||||
connection.setUseCaches(true);
|
||||
return connection.getInputStream();
|
||||
}
|
||||
|
||||
public long lastModified() {
|
||||
try {
|
||||
URLConnection connection = getURL().openConnection();
|
||||
connection.setAllowUserInteraction(false);
|
||||
connection.setUseCaches(true);
|
||||
connection.setIfModifiedSince(lastModified);
|
||||
|
||||
lastModified = connection.getLastModified();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
|
||||
return lastModified;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A factory for creating {@code UUID}s not directly supported by {@link java.util.UUID java.util.UUID}.
|
||||
* <p>
|
||||
* This class can create version 1 time based {@code UUID}s, using either IEEE 802 (mac) address or random "node" value
|
||||
* as well as version 5 SHA1 hash based {@code UUID}s.
|
||||
* </p>
|
||||
* <p>
|
||||
* The timestamp value for version 1 {@code UUID}s will use a high precision clock, when available to the Java VM.
|
||||
* If the Java system clock does not offer the needed precision, the timestamps will fall back to 100-nanosecond
|
||||
* increments, to avoid duplicates.
|
||||
* </p>
|
||||
* <p>
|
||||
* <a name="mac-node"></a>
|
||||
* The node value for version 1 {@code UUID}s will, by default, reflect the IEEE 802 (mac) address of one of
|
||||
* the network interfaces of the local computer. This node value can be manually overridden by setting
|
||||
* the system property {@code "com.twelvemonkeys.util.UUID.node"} to a valid IEEE 802 address, on the form
|
||||
* {@code "12:34:56:78:9a:bc"} or {@code "12-34-45-78-9a-bc"}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <a name="random-node"></a>
|
||||
* The node value for the random "node" based version 1 {@code UUID}s will be stable for the lifetime of the VM.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: UUIDFactory.java,v 1.0 27.02.12 09:45 haraldk Exp$
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122">RFC 4122</a>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Universally_unique_identifier">Wikipedia</a>
|
||||
* @see java.util.UUID
|
||||
*/
|
||||
public final class UUIDFactory {
|
||||
private static final String NODE_PROPERTY = "com.twelvemonkeys.util.UUID.node";
|
||||
|
||||
/**
|
||||
* The Nil UUID: {@code "00000000-0000-0000-0000-000000000000"}.
|
||||
*
|
||||
* The nil UUID is special form of UUID that is specified to have all
|
||||
* 128 bits set to zero. Not particularly useful, unless as a placeholder or template.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122#section-4.1.7">RFC 4122 4.1.7. Nil UUID</a>
|
||||
*/
|
||||
public static final UUID NIL = new UUID(0l, 0l);
|
||||
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
private static final Comparator<UUID> COMPARATOR = new UUIDComparator();
|
||||
|
||||
// Assumes MAC address is constant, which it may not be if a network card is replaced
|
||||
static final long MAC_ADDRESS_NODE = getMacAddressNode();
|
||||
|
||||
static final long SECURE_RANDOM_NODE = getSecureRandomNode();
|
||||
|
||||
private static long getSecureRandomNode() {
|
||||
// Creates a completely random "node" value, with the unicast bit set to 1, as outlined in RFC 4122.
|
||||
return 1l << 40 | SECURE_RANDOM.nextLong() & 0xffffffffffffl;
|
||||
}
|
||||
|
||||
private static long getMacAddressNode() {
|
||||
long[] addressNodes;
|
||||
|
||||
String nodeProperty = System.getProperty(NODE_PROPERTY);
|
||||
|
||||
// Read mac address/node from system property, to allow user-specified node addresses.
|
||||
if (!StringUtil.isEmpty(nodeProperty)) {
|
||||
addressNodes = parseMacAddressNodes(nodeProperty);
|
||||
}
|
||||
else {
|
||||
addressNodes = MacAddressFinder.getMacAddressNodes();
|
||||
}
|
||||
|
||||
// TODO: The UUID spec allows us to use multiple nodes, when available, to create more UUIDs per time unit...
|
||||
// For example in a round robin fashion?
|
||||
return addressNodes != null && addressNodes.length > 0 ? addressNodes[0] : -1;
|
||||
}
|
||||
|
||||
static long[] parseMacAddressNodes(final String nodeProperty) {
|
||||
// Parse comma-separated list mac addresses on format 00:11:22:33:44:55 / 00-11-22-33-44-55
|
||||
String[] nodesStrings = nodeProperty.trim().split(",\\W*");
|
||||
long[] addressNodes = new long[nodesStrings.length];
|
||||
|
||||
for (int i = 0, nodesStringsLength = nodesStrings.length; i < nodesStringsLength; i++) {
|
||||
String nodesString = nodesStrings[i];
|
||||
|
||||
try {
|
||||
String[] nodes = nodesString.split("(?<=(^|\\W)[0-9a-fA-F]{2})\\W(?=[0-9a-fA-F]{2}(\\W|$))", 6);
|
||||
|
||||
long nodeAddress = 0;
|
||||
|
||||
// Network byte order
|
||||
nodeAddress |= (long) (Integer.parseInt(nodes[0], 16) & 0xff) << 40;
|
||||
nodeAddress |= (long) (Integer.parseInt(nodes[1], 16) & 0xff) << 32;
|
||||
nodeAddress |= (long) (Integer.parseInt(nodes[2], 16) & 0xff) << 24;
|
||||
nodeAddress |= (long) (Integer.parseInt(nodes[3], 16) & 0xff) << 16;
|
||||
nodeAddress |= (long) (Integer.parseInt(nodes[4], 16) & 0xff) << 8;
|
||||
nodeAddress |= (long) (Integer.parseInt(nodes[5], 16) & 0xff);
|
||||
|
||||
addressNodes[i] = nodeAddress;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
// May be NumberformatException from parseInt or ArrayIndexOutOfBounds from nodes array
|
||||
NumberFormatException formatException = new NumberFormatException(String.format("Bad IEEE 802 node address: '%s' (from system property %s)", nodesString, NODE_PROPERTY));
|
||||
formatException.initCause(e);
|
||||
throw formatException;
|
||||
}
|
||||
}
|
||||
|
||||
return addressNodes;
|
||||
}
|
||||
|
||||
private UUIDFactory() {}
|
||||
|
||||
/**
|
||||
* Creates a type 5 (name based) {@code UUID} based on the specified byte array.
|
||||
* This method is effectively identical to {@link UUID#nameUUIDFromBytes}, except that this method
|
||||
* uses a SHA1 hash instead of the MD5 hash used in the type 3 {@code UUID}s.
|
||||
* RFC 4122 states that "SHA-1 is preferred" over MD5, without giving a reason for why.
|
||||
*
|
||||
* @param name a byte array to be used to construct a {@code UUID}
|
||||
* @return a {@code UUID} generated from the specified array.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122#section-4.3">RFC 4122 4.3. Algorithm for Creating a Name-Based UUID</a>
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122#appendix-A">RFC 4122 appendix A</a>
|
||||
* @see UUID#nameUUIDFromBytes(byte[])
|
||||
*/
|
||||
public static UUID nameUUIDv5FromBytes(byte[] name) {
|
||||
// Based on code from OpenJDK UUID#nameUUIDFromBytes + private byte[] constructor
|
||||
MessageDigest md;
|
||||
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
}
|
||||
catch (NoSuchAlgorithmException nsae) {
|
||||
throw new InternalError("SHA1 not supported");
|
||||
}
|
||||
|
||||
byte[] sha1Bytes = md.digest(name);
|
||||
sha1Bytes[6] &= 0x0f; /* clear version */
|
||||
sha1Bytes[6] |= 0x50; /* set to version 5 */
|
||||
sha1Bytes[8] &= 0x3f; /* clear variant */
|
||||
sha1Bytes[8] |= 0x80; /* set to IETF variant */
|
||||
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
|
||||
// NOTE: According to RFC 4122, only first 16 bytes are used, meaning
|
||||
// bytes 17-20 in the 160 bit SHA1 hash are simply discarded in this case...
|
||||
for (int i=0; i<8; i++) {
|
||||
msb = (msb << 8) | (sha1Bytes[i] & 0xff);
|
||||
}
|
||||
for (int i=8; i<16; i++) {
|
||||
lsb = (lsb << 8) | (sha1Bytes[i] & 0xff);
|
||||
}
|
||||
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a version 1 time (and node) based {@code UUID}.
|
||||
* The node part is by default the IEE 802 (mac) address of one of the network cards of the current machine.
|
||||
*
|
||||
* @return a {@code UUID} based on the current time and the node address of this computer.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122#section-4.2">RFC 4122 4.2. Algorithms for Creating a Time-Based UUID</a>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/MAC_address">IEEE 802 (mac) address</a>
|
||||
* @see <a href="#mac-node">Overriding the node address</a>
|
||||
*
|
||||
* @throws IllegalStateException if the IEEE 802 (mac) address of the computer (node) cannot be found.
|
||||
*/
|
||||
public static UUID timeNodeBasedUUID() {
|
||||
if (MAC_ADDRESS_NODE == -1) {
|
||||
throw new IllegalStateException("Could not determine IEEE 802 (mac) address for node");
|
||||
}
|
||||
|
||||
return createTimeBasedUUIDforNode(MAC_ADDRESS_NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a version 1 time based {@code UUID} with the node part replaced by a random based value.
|
||||
* The node part is computed using a 47 bit secure random number + lsb of first octet (unicast/multicast bit) set to 1.
|
||||
* These {@code UUID}s can never clash with "real" node based version 1 {@code UUID}s due to the difference in
|
||||
* the unicast/multicast bit, however, no uniqueness between multiple machines/vms/nodes can be guaranteed.
|
||||
*
|
||||
* @return a {@code UUID} based on the current time and a random generated "node" value.
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122#section-4.5">RFC 4122 4.5. Node IDs that Do Not Identify the Host</a>
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122#appendix-A">RFC 4122 Appendix A</a>
|
||||
* @see <a href="#random-node">Lifetime of random node value</a>
|
||||
*
|
||||
* @throws IllegalStateException if the IEEE 802 (mac) address of the computer (node) cannot be found.
|
||||
*/
|
||||
public static UUID timeRandomBasedUUID() {
|
||||
return createTimeBasedUUIDforNode(SECURE_RANDOM_NODE);
|
||||
}
|
||||
|
||||
private static UUID createTimeBasedUUIDforNode(final long node) {
|
||||
return new UUID(createTimeAndVersion(), createClockSeqAndNode(node));
|
||||
}
|
||||
|
||||
// TODO: Version 2 UUID?
|
||||
/*
|
||||
Version 2 UUIDs are similar to Version 1 UUIDs, with the upper byte of the clock sequence replaced by the
|
||||
identifier for a "local domain" (typically either the "POSIX UID domain" or the "POSIX GID domain")
|
||||
and the first 4 bytes of the timestamp replaced by the user's POSIX UID or GID (with the "local domain"
|
||||
identifier indicating which it is).[2][3]
|
||||
*/
|
||||
|
||||
private static long createClockSeqAndNode(final long node) {
|
||||
// Variant (2) + Clock seq high and low + node
|
||||
return 0x8000000000000000l | (Clock.getClockSequence() << 48) | node & 0xffffffffffffl;
|
||||
}
|
||||
|
||||
private static long createTimeAndVersion() {
|
||||
long clockTime = Clock.currentTimeHundredNanos();
|
||||
|
||||
long time = clockTime << 32; // Time low
|
||||
time |= (clockTime & 0xFFFF00000000L) >> 16; // Time mid
|
||||
time |= ((clockTime >> 48) & 0x0FFF); // Time high
|
||||
time |= 0x1000; // Version (1)
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comparator that compares UUIDs as 128 bit unsigned entities, as mentioned in RFC 4122.
|
||||
* This is different than {@link UUID#compareTo(Object)} that compares the UUIDs as signed entities.
|
||||
*
|
||||
* @return a comparator that compares UUIDs as 128 bit unsigned entities.
|
||||
*
|
||||
* @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7025832">java.lang.UUID compareTo() does not do an unsigned compare</a>
|
||||
* @see <a href="http://tools.ietf.org/html/rfc4122#appendix-A">RFC 4122 Appendix A</a>
|
||||
*/
|
||||
public static Comparator<UUID> comparator() {
|
||||
return COMPARATOR;
|
||||
}
|
||||
|
||||
static final class UUIDComparator implements Comparator<UUID> {
|
||||
public int compare(UUID left, UUID right) {
|
||||
// The ordering is intentionally set up so that the UUIDs
|
||||
// can simply be numerically compared as two *UNSIGNED* numbers
|
||||
if (left.getMostSignificantBits() >>> 32 < right.getMostSignificantBits() >>> 32) {
|
||||
return -1;
|
||||
}
|
||||
else if (left.getMostSignificantBits() >>> 32 > right.getMostSignificantBits() >>> 32) {
|
||||
return 1;
|
||||
}
|
||||
else if ((left.getMostSignificantBits() & 0xffffffffl) < (right.getMostSignificantBits() & 0xffffffffl)) {
|
||||
return -1;
|
||||
}
|
||||
else if ((left.getMostSignificantBits() & 0xffffffffl) > (right.getMostSignificantBits() & 0xffffffffl)) {
|
||||
return 1;
|
||||
}
|
||||
else if (left.getLeastSignificantBits() >>> 32 < right.getLeastSignificantBits() >>> 32) {
|
||||
return -1;
|
||||
}
|
||||
else if (left.getLeastSignificantBits() >>> 32 > right.getLeastSignificantBits() >>> 32) {
|
||||
return 1;
|
||||
}
|
||||
else if ((left.getLeastSignificantBits() & 0xffffffffl) < (right.getLeastSignificantBits() & 0xffffffffl)) {
|
||||
return -1;
|
||||
}
|
||||
else if ((left.getLeastSignificantBits() & 0xffffffffl) > (right.getLeastSignificantBits() & 0xffffffffl)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-resolution timer for use in creating version 1 {@code UUID}s.
|
||||
*/
|
||||
static final class Clock {
|
||||
// Java: 0:00, Jan. 1st, 1970 vs UUID: 0:00, Oct 15th, 1582
|
||||
private static final long JAVA_EPOCH_OFFSET_HUNDRED_NANOS = 122192928000000000L;
|
||||
|
||||
private static int clockSeq = SECURE_RANDOM.nextInt();
|
||||
|
||||
private static long initialNanos;
|
||||
private static long initialTime;
|
||||
|
||||
private static long lastMeasuredTime;
|
||||
private static long lastTime;
|
||||
|
||||
static {
|
||||
initClock();
|
||||
}
|
||||
|
||||
private static void initClock() {
|
||||
long millis = System.currentTimeMillis();
|
||||
long nanos = System.nanoTime();
|
||||
|
||||
initialTime = JAVA_EPOCH_OFFSET_HUNDRED_NANOS + millis * 10000 + (nanos / 100) % 10000;
|
||||
initialNanos = nanos;
|
||||
}
|
||||
|
||||
public static synchronized long currentTimeHundredNanos() {
|
||||
// Measure delta since init and compute accurate time
|
||||
long time;
|
||||
|
||||
while ((time = initialTime + (System.nanoTime() - initialNanos) / 100) < lastMeasuredTime) {
|
||||
// Reset clock seq (should happen VERY rarely)
|
||||
initClock();
|
||||
clockSeq++;
|
||||
}
|
||||
|
||||
lastMeasuredTime = time;
|
||||
|
||||
if (time <= lastTime) {
|
||||
// This typically means the clock isn't accurate enough, use auto-incremented time.
|
||||
// It is possible that more timestamps than available are requested for
|
||||
// each time unit in the system clock, but that is extremely unlikely.
|
||||
// TODO: RFC 4122 says we should wait in the case of too many requests...
|
||||
time = ++lastTime;
|
||||
}
|
||||
else {
|
||||
lastTime = time;
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
public static synchronized long getClockSequence() {
|
||||
return clockSeq & 0x3fff;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static inner class for 1.5 compatibility.
|
||||
*/
|
||||
static final class MacAddressFinder {
|
||||
public static long[] getMacAddressNodes() {
|
||||
List<Long> nodeAddresses = new ArrayList<Long>();
|
||||
try {
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
|
||||
if (interfaces != null) {
|
||||
while (interfaces.hasMoreElements()) {
|
||||
NetworkInterface nic = interfaces.nextElement();
|
||||
|
||||
if (!nic.isVirtual()) {
|
||||
long nodeAddress = 0;
|
||||
|
||||
byte[] hardware = nic.getHardwareAddress(); // 1.6 method
|
||||
|
||||
if (hardware != null && hardware.length == 6 && hardware[1] != (byte) 0xff) {
|
||||
// Network byte order
|
||||
nodeAddress |= (long) (hardware[0] & 0xff) << 40;
|
||||
nodeAddress |= (long) (hardware[1] & 0xff) << 32;
|
||||
nodeAddress |= (long) (hardware[2] & 0xff) << 24;
|
||||
nodeAddress |= (long) (hardware[3] & 0xff) << 16;
|
||||
nodeAddress |= (long) (hardware[4] & 0xff) << 8;
|
||||
nodeAddress |= (long) (hardware[5] & 0xff);
|
||||
|
||||
nodeAddresses.add(nodeAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException ex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long[] unwrapped = new long[nodeAddresses.size()];
|
||||
for (int i = 0, nodeAddressesSize = nodeAddresses.size(); i < nodeAddressesSize; i++) {
|
||||
unwrapped[i] = nodeAddresses.get(i);
|
||||
}
|
||||
|
||||
return unwrapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -82,9 +82,9 @@ public class REWildcardStringParser /*extends EntityObject*/ {
|
||||
|
||||
/** Field 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', 'æ',
|
||||
'ø', 'å', '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', 'Æ', 'Ø', 'Å', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_', '-'
|
||||
'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',
|
||||
'Z', '\u00c6', '\u00d8', '\u00c5', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_', '-'
|
||||
};
|
||||
|
||||
/** Field FREE_RANGE_CHARACTER */
|
||||
@@ -165,12 +165,12 @@ public class REWildcardStringParser /*extends EntityObject*/ {
|
||||
char stringMaskChar = pWildcardExpression.charAt(i);
|
||||
|
||||
if (isFreeRangeCharacter(stringMaskChar)) {
|
||||
regexpBuffer.append("(([a-åA-Å0-9]|.|_|-)*)");
|
||||
regexpBuffer.append("(([a-<EFBFBD>A-<EFBFBD>0-9]|.|_|-)*)");
|
||||
}
|
||||
|
||||
// Free-pass character '?'
|
||||
else if (isFreePassCharacter(stringMaskChar)) {
|
||||
regexpBuffer.append("([a-åA_Å0-9]|.|_|-)");
|
||||
regexpBuffer.append("([a-<EFBFBD>A_<EFBFBD>0-9]|.|_|-)");
|
||||
}
|
||||
|
||||
// Valid characters
|
||||
@@ -1,18 +1,18 @@
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
/**
|
||||
* DeflateEncoderTest
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DeflateDecoderTestCase.java#1 $
|
||||
*/
|
||||
public class DeflateEncoderTestCase extends EncoderAbstractTestCase {
|
||||
protected Encoder createEncoder() {
|
||||
return new DeflateEncoder();
|
||||
}
|
||||
|
||||
protected Decoder createCompatibleDecoder() {
|
||||
return new InflateDecoder();
|
||||
}
|
||||
}
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
/**
|
||||
* DeflateEncoderTest
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/DeflateDecoderTestCase.java#1 $
|
||||
*/
|
||||
public class DeflateEncoderTestCase extends EncoderAbstractTestCase {
|
||||
protected Encoder createEncoder() {
|
||||
return new DeflateEncoder();
|
||||
}
|
||||
|
||||
protected Decoder createCompatibleDecoder() {
|
||||
return new InflateDecoder();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
/**
|
||||
* InflateEncoderTest
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java#1 $
|
||||
*/
|
||||
public class InflateDecoderTestCase extends DecoderAbstractTestCase {
|
||||
public Decoder createDecoder() {
|
||||
return new InflateDecoder();
|
||||
}
|
||||
|
||||
public Encoder createCompatibleEncoder() {
|
||||
return new DeflateEncoder();
|
||||
}
|
||||
}
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
/**
|
||||
* InflateEncoderTest
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/test/java/com/twelvemonkeys/io/enc/InflateDecoderTestCase.java#1 $
|
||||
*/
|
||||
public class InflateDecoderTestCase extends DecoderAbstractTestCase {
|
||||
public Decoder createDecoder() {
|
||||
return new InflateDecoder();
|
||||
}
|
||||
|
||||
public Encoder createCompatibleEncoder() {
|
||||
return new DeflateEncoder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
/**
|
||||
* <20>If it walks like a duck, looks like a duck, quacks like a duck, it must be<62><65>
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/lang/DuckTypeTestCase.java#1 $
|
||||
*/
|
||||
public class DuckTypeTestCase extends TestCase {
|
||||
|
||||
static public interface Eatable {
|
||||
}
|
||||
|
||||
static public interface Vegetable extends Eatable {
|
||||
}
|
||||
|
||||
static public interface Meat extends Eatable {
|
||||
}
|
||||
|
||||
static public interface Animal {
|
||||
void walk();
|
||||
boolean canEat(Eatable pFood);
|
||||
void eat(Eatable pFood);
|
||||
}
|
||||
|
||||
static public interface Bird extends Animal {
|
||||
void fly();
|
||||
}
|
||||
|
||||
static public interface Duck extends Bird {
|
||||
void quack();
|
||||
}
|
||||
|
||||
static public class DuckLookALike {
|
||||
private boolean mWalking;
|
||||
private boolean mFlying;
|
||||
private boolean mQuacking;
|
||||
|
||||
public void walk() {
|
||||
mWalking = true;
|
||||
}
|
||||
|
||||
public void fly() {
|
||||
mFlying = true;
|
||||
}
|
||||
|
||||
public void quack() {
|
||||
mQuacking = true;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
mWalking = mFlying = mQuacking = false;
|
||||
}
|
||||
|
||||
boolean verify() {
|
||||
return mWalking && mFlying && mQuacking;
|
||||
}
|
||||
}
|
||||
|
||||
static public class Swan extends DuckLookALike {
|
||||
}
|
||||
|
||||
static public class VeggieEater {
|
||||
private boolean mHappy;
|
||||
|
||||
public boolean canEat(Eatable pFood) {
|
||||
return pFood instanceof Vegetable;
|
||||
}
|
||||
|
||||
public void eat(Eatable pFood) {
|
||||
if (pFood == this) {
|
||||
throw new IllegalArgumentException("CantEatMyselfException: duh");
|
||||
}
|
||||
if (!canEat(pFood)) {
|
||||
throw new NotVegetableException("yuck");
|
||||
}
|
||||
|
||||
mHappy = true;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
mHappy = false;
|
||||
}
|
||||
|
||||
boolean verify() {
|
||||
return mHappy;
|
||||
}
|
||||
}
|
||||
|
||||
static class NotVegetableException extends RuntimeException {
|
||||
public NotVegetableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void testTooManyThingsAtOnce() {
|
||||
DuckLookALike lookALike = new DuckLookALike();
|
||||
VeggieEater veggieEater = new VeggieEater();
|
||||
|
||||
Object obj = DuckType.implement(new Class[]{Duck.class, Meat.class},
|
||||
new Object[]{lookALike, veggieEater});
|
||||
assertTrue(obj instanceof Duck);
|
||||
assertTrue(obj instanceof Meat);
|
||||
Duck duck = (Duck) obj;
|
||||
|
||||
Bird another = (Bird) DuckType.implement(new Class[]{Duck.class, Meat.class},
|
||||
new Object[]{lookALike, veggieEater});
|
||||
|
||||
Duck uglyDuckling = (Duck) DuckType.implement(new Class[] {Duck.class, Meat.class},
|
||||
new Object[] {new Swan(), new VeggieEater()});
|
||||
|
||||
assertNotNull(duck.toString());
|
||||
|
||||
assertTrue("Duck is supposed to equal itself (identity crisis)", duck.equals(duck));
|
||||
|
||||
assertEquals("Duck is supposed to equal other duck with same stuffing", duck, another);
|
||||
|
||||
assertFalse("Some ducks are more equal than others", duck.equals(uglyDuckling));
|
||||
|
||||
duck.walk();
|
||||
duck.quack();
|
||||
duck.quack();
|
||||
duck.fly();
|
||||
|
||||
assertTrue("Duck is supposed to quack", lookALike.verify());
|
||||
|
||||
Vegetable cabbage = new Vegetable() {};
|
||||
assertTrue("Duck is supposed to like cabbage", duck.canEat(cabbage));
|
||||
duck.eat(cabbage);
|
||||
assertTrue("Duck is supposed to eat vegetables", veggieEater.verify());
|
||||
|
||||
veggieEater.reset();
|
||||
|
||||
Throwable exception = null;
|
||||
try {
|
||||
duck.eat((Meat) uglyDuckling);
|
||||
fail("Duck ate distant cousin");
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
exception = t;
|
||||
}
|
||||
assertTrue("Incorrect quack: " + exception, exception instanceof NotVegetableException);
|
||||
|
||||
|
||||
// TODO: There's a flaw in the design here..
|
||||
// The "this" keyword don't work well with proxies..
|
||||
|
||||
// Something that could possibly work, is:
|
||||
// All proxy-aware delegates need a method getThis() / getSelf()...
|
||||
// (using a field won't work for delegates that are part of multiple
|
||||
// proxies).
|
||||
// The default implementation should only return "this"..
|
||||
// TBD: How do we know which proxy the current delegate is part of?
|
||||
|
||||
exception = null;
|
||||
try {
|
||||
duck.eat((Meat) duck);
|
||||
fail("Duck ate itself");
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
exception = t;
|
||||
}
|
||||
assertTrue("Duck tried to eat itself: " + exception, exception instanceof IllegalArgumentException);
|
||||
}
|
||||
|
||||
public void testExpandedArgs() {
|
||||
Object walker = new Object() {
|
||||
public void walk() {
|
||||
}
|
||||
};
|
||||
Object eater = new Object() {
|
||||
// Assignable, but not direct match
|
||||
public boolean canEat(Object pFood) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Assignable, but not direct match
|
||||
public void eat(Object pFood) {
|
||||
}
|
||||
};
|
||||
|
||||
Animal rat = (Animal) DuckType.implement(new Class[]{Animal.class, Meat.class},
|
||||
new Object[]{walker, eater});
|
||||
|
||||
assertNotNull(rat);
|
||||
assertTrue(rat instanceof Meat);
|
||||
|
||||
// Rats eat everything
|
||||
Eatable smellyFood = new Eatable() {boolean tastesVeryBad = true;};
|
||||
assertTrue("Rat did not eat smelly food", rat.canEat(smellyFood));
|
||||
}
|
||||
|
||||
public void testExpandedArgsFail() {
|
||||
try {
|
||||
Object walker = new Object() {
|
||||
public void walk() {
|
||||
}
|
||||
};
|
||||
Object eater = new Object() {
|
||||
// Not assignable return type
|
||||
public int canEat(Eatable pFood) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Assignable, but not direct match
|
||||
public void eat(Object pFood) {
|
||||
}
|
||||
};
|
||||
DuckType.implement(new Class[]{Animal.class},
|
||||
new Object[]{walker, eater});
|
||||
|
||||
fail("This kind of animal won't live long");
|
||||
}
|
||||
catch (DuckType.NoMatchingMethodException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testStubAbstract() {
|
||||
Object obj = DuckType.implement(new Class[]{Animal.class},
|
||||
new Object[]{new Object()}, true);
|
||||
assertTrue(obj instanceof Animal);
|
||||
Animal unicorn = (Animal) obj;
|
||||
assertNotNull(unicorn);
|
||||
|
||||
// Should create a meaningful string representation
|
||||
assertNotNull(unicorn.toString());
|
||||
|
||||
// Unicorns don't fly, as they are only an abstract idea..
|
||||
try {
|
||||
unicorn.walk();
|
||||
fail("Unicorns should not fly, as they are only an abstract idea");
|
||||
}
|
||||
catch (AbstractMethodError e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.lang;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* ExceptionUtilTest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: ExceptionUtilTest.java,v 1.0 11.04.12 16:07 haraldk Exp$
|
||||
*/
|
||||
@Ignore("Under development")
|
||||
public class ExceptionUtilTest {
|
||||
@Test(expected = BadException.class)
|
||||
@SuppressWarnings({"InfiniteLoopStatement"})
|
||||
public void test() {
|
||||
while (true) {
|
||||
foo();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "varargs"})
|
||||
private static void foo() {
|
||||
try {
|
||||
bar();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
ExceptionUtil.handle(t,
|
||||
new ExceptionUtil.ThrowableHandler<IOException>(IOException.class) {
|
||||
public void handle(final IOException pThrowable) {
|
||||
System.out.println("IOException: " + pThrowable + " handled");
|
||||
}
|
||||
},
|
||||
new ExceptionUtil.ThrowableHandler<Exception>(SQLException.class, NumberFormatException.class) {
|
||||
public void handle(final Exception pThrowable) {
|
||||
System.out.println("Exception: " + pThrowable + " handled");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void bar() {
|
||||
baz();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"ThrowableInstanceNeverThrown"})
|
||||
private static void baz() {
|
||||
double random = Math.random();
|
||||
if (random < (2.0 / 3.0)) {
|
||||
ExceptionUtil.throwUnchecked(new FileNotFoundException("FNF Boo"));
|
||||
}
|
||||
if (random < (5.0 / 6.0)) {
|
||||
ExceptionUtil.throwUnchecked(new SQLException("SQL Boo"));
|
||||
}
|
||||
else {
|
||||
ExceptionUtil.throwUnchecked(new BadException("Some Boo"));
|
||||
}
|
||||
}
|
||||
|
||||
static final class BadException extends Exception {
|
||||
public BadException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import com.twelvemonkeys.util.MappedBeanFactory;
|
||||
import junit.framework.AssertionFailedError;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* MappedBeanFactoryTestCase
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-sandbox/src/test/java/com/twelvemonkeys/sandbox/MappedBeanFactoryTestCase.java#1 $
|
||||
*/
|
||||
public class MappedBeanFactoryTestCase {
|
||||
|
||||
public static interface Foo {
|
||||
boolean isFoo();
|
||||
|
||||
int getBar();
|
||||
void setBar(int bar);
|
||||
|
||||
Rectangle getBounds();
|
||||
void setBounds(Rectangle bounds);
|
||||
}
|
||||
|
||||
public static interface DefaultFoo extends Foo {
|
||||
// @MappedBeanFactory.DefaultBooleanValue
|
||||
@MappedBeanFactory.DefaultValue(booleanValue = false)
|
||||
boolean isFoo();
|
||||
|
||||
@MappedBeanFactory.DefaultIntValue
|
||||
int getBar();
|
||||
void setBar(int bar);
|
||||
|
||||
Rectangle getBounds();
|
||||
void setBounds(Rectangle bounds);
|
||||
|
||||
@SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException"})
|
||||
DefaultFoo clone();
|
||||
}
|
||||
|
||||
static interface ObservableFoo extends DefaultFoo {
|
||||
@MappedBeanFactory.DefaultBooleanValue(true)
|
||||
boolean isFoo();
|
||||
|
||||
@MappedBeanFactory.DefaultIntValue(1)
|
||||
int getBar();
|
||||
|
||||
@MappedBeanFactory.NotNull
|
||||
Rectangle getBounds();
|
||||
|
||||
@MappedBeanFactory.Observable
|
||||
void setBounds(@MappedBeanFactory.NotNull Rectangle bounds);
|
||||
|
||||
// TODO: This method should be implicitly supported, and throw IllegalArgument, if NoSuchProperty
|
||||
// TODO: An observable interface to extend?
|
||||
void addPropertyChangeListener(String property, PropertyChangeListener listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class);
|
||||
assertNotNull(foo);
|
||||
assertNotNull(foo.toString());
|
||||
assertTrue(foo.toString().contains(DefaultFoo.class.getName()));
|
||||
|
||||
// TODO: Consider this:
|
||||
// assertTrue(foo.toString().contains("foo=false"));
|
||||
// assertTrue(foo.toString().contains("bar=0"));
|
||||
// assertTrue(foo.toString().contains("bounds=null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClone() {
|
||||
DefaultFoo foo = MappedBeanFactory.as(DefaultFoo.class, Collections.singletonMap("foo", true));
|
||||
DefaultFoo clone = foo.clone();
|
||||
assertNotSame(foo, clone);
|
||||
assertEquals(foo, clone);
|
||||
assertEquals(foo.hashCode(), clone.hashCode());
|
||||
assertEquals(foo.isFoo(), clone.isFoo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializable() throws IOException, ClassNotFoundException {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, Collections.singletonMap("foo", true));
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
ObjectOutputStream outputStream = new ObjectOutputStream(bytes);
|
||||
outputStream.writeObject(foo);
|
||||
|
||||
ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()));
|
||||
Foo bar = (Foo) inputStream.readObject();
|
||||
|
||||
assertNotSame(foo, bar);
|
||||
assertEquals(foo, bar);
|
||||
assertEquals(foo.hashCode(), bar.hashCode());
|
||||
assertEquals(foo.isFoo(), bar.isFoo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEqualsNull() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class);
|
||||
|
||||
@SuppressWarnings({"ObjectEqualsNull"})
|
||||
boolean equalsNull = foo.equals(null);
|
||||
|
||||
assertFalse(equalsNull);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsSelf() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>() {
|
||||
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
throw new AssertionFailedError("Don't need to test map for equals if same object");
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(foo.equals(foo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsOther() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class);
|
||||
Foo other = MappedBeanFactory.as(DefaultFoo.class);
|
||||
|
||||
assertEquals(foo, other);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsOtherModifiedSameValue() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>());
|
||||
Foo other = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("bar", 0)));
|
||||
|
||||
assertEquals(foo, other);
|
||||
|
||||
// No real change
|
||||
other.setBar(foo.getBar());
|
||||
assertTrue(foo.equals(other));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEqualsOtherModified() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class);
|
||||
Foo other = MappedBeanFactory.as(DefaultFoo.class);
|
||||
|
||||
assertEquals(foo, other);
|
||||
|
||||
// Real change
|
||||
other.setBar(42);
|
||||
assertFalse(foo.equals(other));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsSubclass() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class);
|
||||
|
||||
Foo sub = MappedBeanFactory.as(ObservableFoo.class);
|
||||
assertEquals(foo, sub);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEqualsDifferentValues() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class);
|
||||
Foo bar = MappedBeanFactory.as(DefaultFoo.class, Collections.singletonMap("bar", true));
|
||||
assertFalse(foo.equals(bar));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotEqualsDifferentClass() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class);
|
||||
ActionListener actionListener = MappedBeanFactory.as(ActionListener.class);
|
||||
assertFalse(foo.equals(actionListener));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanReadOnly() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, Collections.singletonMap("foo", true));
|
||||
|
||||
assertNotNull(foo);
|
||||
assertEquals(true, foo.isFoo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanEmpty() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>());
|
||||
|
||||
assertNotNull(foo);
|
||||
|
||||
try {
|
||||
foo.isFoo();
|
||||
fail("Expected NullPointerException");
|
||||
}
|
||||
catch (NullPointerException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanEmptyWithConverter() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(), new NullBooleanConverter(true));
|
||||
|
||||
assertNotNull(foo);
|
||||
|
||||
assertEquals(true, foo.isFoo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntReadOnly() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, Collections.singletonMap("bar", 1));
|
||||
|
||||
assertNotNull(foo);
|
||||
assertEquals(1, foo.getBar());
|
||||
|
||||
try {
|
||||
foo.setBar(42);
|
||||
fail("Expected UnsupportedOperationException");
|
||||
}
|
||||
catch (UnsupportedOperationException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntReadWrite() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("bar", 1)));
|
||||
|
||||
assertNotNull(foo);
|
||||
assertEquals(1, foo.getBar());
|
||||
|
||||
foo.setBar(42);
|
||||
assertEquals(42, foo.getBar());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntNull() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("bar", null)));
|
||||
|
||||
assertNotNull(foo);
|
||||
|
||||
// TODO: Handle null-values smarter, maybe throw a better exception?
|
||||
// TODO: Consider allowing custom initializers?
|
||||
try {
|
||||
foo.getBar();
|
||||
fail("Expected NullPointerException");
|
||||
}
|
||||
catch (NullPointerException expected) {
|
||||
}
|
||||
|
||||
foo.setBar(42);
|
||||
assertEquals(42, foo.getBar());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntNullWithConverter() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("bar", null)), new NullIntConverter(1));
|
||||
|
||||
assertNotNull(foo);
|
||||
|
||||
assertEquals(1, foo.getBar());
|
||||
|
||||
foo.setBar(42);
|
||||
assertEquals(42, foo.getBar());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntWrongType() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("bar", "1")));
|
||||
|
||||
assertNotNull(foo);
|
||||
|
||||
// TODO: Handle conversion smarter, maybe throw a better exception?
|
||||
try {
|
||||
foo.getBar();
|
||||
fail("Expected ClassCastException");
|
||||
}
|
||||
catch (ClassCastException expected) {
|
||||
}
|
||||
|
||||
// TODO: Should we allow changing type?
|
||||
try {
|
||||
foo.setBar(42);
|
||||
fail("Expected ClassCastException");
|
||||
}
|
||||
catch (ClassCastException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBounds() {
|
||||
Rectangle rectangle = new Rectangle(2, 2, 4, 4);
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("bounds", rectangle)));
|
||||
|
||||
assertNotNull(foo);
|
||||
assertEquals(rectangle, foo.getBounds());
|
||||
|
||||
foo.setBounds(new Rectangle());
|
||||
assertEquals(new Rectangle(), foo.getBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoundsNull() {
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("bounds", null)));
|
||||
|
||||
assertNotNull(foo);
|
||||
assertNull(foo.getBounds());
|
||||
|
||||
Rectangle rectangle = new Rectangle(2, 2, 4, 4);
|
||||
foo.setBounds(rectangle);
|
||||
assertEquals(rectangle, foo.getBounds());
|
||||
|
||||
foo.setBounds(null);
|
||||
assertEquals(null, foo.getBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoundsNullWithConverter() {
|
||||
// TODO: Allow @NotNull annotations, to say that null is not a valid return value/paramter?
|
||||
Foo foo = MappedBeanFactory.as(ObservableFoo.class, new HashMap<String, Object>(Collections.singletonMap("bounds", null)), new MappedBeanFactory.Converter<Void, Rectangle>() {
|
||||
public Class<Void> getFromType() {
|
||||
return Void.class;
|
||||
}
|
||||
|
||||
public Class<Rectangle> getToType() {
|
||||
return Rectangle.class;
|
||||
}
|
||||
|
||||
public Rectangle convert(Void value, Rectangle old) {
|
||||
return new Rectangle(10, 10, 10, 10);
|
||||
}
|
||||
});
|
||||
|
||||
assertNotNull(foo);
|
||||
// TODO: The current problem is that null is okay as return value, even if not specified for interface...
|
||||
assertEquals(new Rectangle(10, 10, 10, 10), foo.getBounds());
|
||||
|
||||
Rectangle rectangle = new Rectangle(2, 2, 4, 4);
|
||||
foo.setBounds(rectangle);
|
||||
assertEquals(rectangle, foo.getBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoundsAsMapWithConverter() throws IntrospectionException {
|
||||
Rectangle rectangle = new Rectangle(2, 2, 4, 4);
|
||||
Map<String, Object> recAsMap = new HashMap<String, Object>();
|
||||
recAsMap.put("x", 2);
|
||||
recAsMap.put("y", 2);
|
||||
recAsMap.put("width", 4);
|
||||
recAsMap.put("height", 4);
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>(Collections.singletonMap("bounds", recAsMap));
|
||||
|
||||
// TODO: Allow for registering superclasses/interfaces like Map...
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, map, new MapRectangleConverter(), new RectangleMapConverter());
|
||||
|
||||
assertNotNull(foo);
|
||||
|
||||
assertEquals(rectangle, foo.getBounds());
|
||||
|
||||
foo.setBounds(new Rectangle());
|
||||
assertEquals(new Rectangle(), foo.getBounds());
|
||||
assertEquals(recAsMap, map.get("bounds"));
|
||||
assertSame(recAsMap, map.get("bounds"));
|
||||
|
||||
// TODO: The converter should maybe not have to handle this
|
||||
foo.setBounds(null);
|
||||
assertNull(foo.getBounds());
|
||||
assertEquals(recAsMap, map.get("bounds"));
|
||||
assertSame(recAsMap, map.get("bounds"));
|
||||
|
||||
Rectangle bounds = new Rectangle(1, 1, 1, 1);
|
||||
foo.setBounds(bounds);
|
||||
assertEquals(bounds, foo.getBounds());
|
||||
assertEquals(1, foo.getBounds().x);
|
||||
assertEquals(1, foo.getBounds().y);
|
||||
assertEquals(1, foo.getBounds().width);
|
||||
assertEquals(1, foo.getBounds().height);
|
||||
assertEquals(recAsMap, map.get("bounds"));
|
||||
assertSame(recAsMap, map.get("bounds"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpeed() {
|
||||
// How many times faster may the direct access be, before we declare failure?
|
||||
final int threshold = 50;
|
||||
|
||||
Foo foo = MappedBeanFactory.as(DefaultFoo.class, new HashMap<String, Object>(Collections.singletonMap("foo", false)));
|
||||
|
||||
Foo bar = new Foo() {
|
||||
public boolean isFoo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getBar() {
|
||||
throw new UnsupportedOperationException("Method getBar not implemented");
|
||||
}
|
||||
|
||||
public void setBar(int bar) {
|
||||
throw new UnsupportedOperationException("Method setBar not implemented");
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
throw new UnsupportedOperationException("Method getBounds not implemented"); // TODO: Implement
|
||||
}
|
||||
|
||||
public void setBounds(Rectangle bounds) {
|
||||
throw new UnsupportedOperationException("Method setBounds not implemented"); // TODO: Implement
|
||||
}
|
||||
};
|
||||
|
||||
final int warmup = 50005;
|
||||
final int iter = 2000000;
|
||||
for (int i = 0; i < warmup; i++) {
|
||||
if (foo.isFoo()) {
|
||||
fail();
|
||||
}
|
||||
if (bar.isFoo()) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
long startProxy = System.nanoTime();
|
||||
for (int i = 0; i < iter; i++) {
|
||||
if (foo.isFoo()) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
long proxyTime = System.nanoTime() - startProxy;
|
||||
|
||||
long startJava = System.nanoTime();
|
||||
for (int i = 0; i < iter; i++) {
|
||||
if (bar.isFoo()) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
long javaTime = System.nanoTime() - startJava;
|
||||
|
||||
assertTrue(
|
||||
String.format(
|
||||
"Proxy time (%1$,d ms) greater than %3$d times direct invocation (%2$,d ms)",
|
||||
proxyTime / 1000, javaTime / 1000, threshold
|
||||
),
|
||||
proxyTime < threshold * javaTime);
|
||||
}
|
||||
|
||||
private static class MapRectangleConverter implements MappedBeanFactory.Converter<HashMap, Rectangle> {
|
||||
public Class<HashMap> getFromType() {
|
||||
return HashMap.class;
|
||||
}
|
||||
|
||||
public Class<Rectangle> getToType() {
|
||||
return Rectangle.class;
|
||||
}
|
||||
|
||||
public Rectangle convert(final HashMap pMap, Rectangle pOldValue) {
|
||||
if (pMap == null || pMap.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Rectangle rectangle = pOldValue != null ? pOldValue : new Rectangle();
|
||||
|
||||
rectangle.x = (Integer) pMap.get("x");
|
||||
rectangle.y = (Integer) pMap.get("y");
|
||||
rectangle.width = (Integer) pMap.get("width");
|
||||
rectangle.height = (Integer) pMap.get("height");
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RectangleMapConverter implements MappedBeanFactory.Converter<Rectangle, HashMap> {
|
||||
public Class<HashMap> getToType() {
|
||||
return HashMap.class;
|
||||
}
|
||||
|
||||
public Class<Rectangle> getFromType() {
|
||||
return Rectangle.class;
|
||||
}
|
||||
|
||||
public HashMap convert(final Rectangle pRectangle, HashMap pOldValue) {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, Integer> map = pOldValue != null ? pOldValue : new HashMap<String, Integer>();
|
||||
|
||||
if (pRectangle != null) {
|
||||
map.put("x", pRectangle.x);
|
||||
map.put("y", pRectangle.y);
|
||||
map.put("width", pRectangle.width);
|
||||
map.put("height", pRectangle.height);
|
||||
}
|
||||
else {
|
||||
map.remove("x");
|
||||
map.remove("y");
|
||||
map.remove("width");
|
||||
map.remove("height");
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NullIntConverter implements MappedBeanFactory.Converter<Void, Integer> {
|
||||
private Integer mInitialValue;
|
||||
|
||||
public NullIntConverter(int pValue) {
|
||||
mInitialValue = pValue;
|
||||
}
|
||||
|
||||
public Class<Void> getFromType() {
|
||||
return Void.class;
|
||||
}
|
||||
|
||||
public Class<Integer> getToType() {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
public Integer convert(Void value, Integer old) {
|
||||
return mInitialValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NullBooleanConverter implements MappedBeanFactory.Converter<Void, Boolean> {
|
||||
private Boolean mInitialValue;
|
||||
|
||||
public NullBooleanConverter(boolean pValue) {
|
||||
mInitialValue = pValue;
|
||||
}
|
||||
|
||||
public Class<Void> getFromType() {
|
||||
return Void.class;
|
||||
}
|
||||
|
||||
public Class<Boolean> getToType() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
public Boolean convert(Void value, Boolean old) {
|
||||
return mInitialValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class UUIDFactoryTest {
|
||||
private static final String EXAMPLE_COM_UUID = "http://www.example.com/uuid/";
|
||||
|
||||
// Nil UUID
|
||||
|
||||
@Test
|
||||
public void testNilUUIDVariant() {
|
||||
assertEquals(0, UUIDFactory.NIL.variant());
|
||||
}
|
||||
@Test
|
||||
public void testNilUUIDVersion() {
|
||||
assertEquals(0, UUIDFactory.NIL.version());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNilUUIDFromStringRep() {
|
||||
assertEquals(UUID.fromString("00000000-0000-0000-0000-000000000000"), UUIDFactory.NIL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNilUUIDFromLong() {
|
||||
assertEquals(new UUID(0l, 0l), UUIDFactory.NIL);
|
||||
}
|
||||
|
||||
// Version 3 UUIDs (for comparison with v5)
|
||||
|
||||
@Test
|
||||
public void testVersion3NameBasedMD5Variant() throws UnsupportedEncodingException {
|
||||
assertEquals(2, UUID.nameUUIDFromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8")).variant());
|
||||
}
|
||||
@Test
|
||||
public void testVersion3NameBasedMD5Version() throws UnsupportedEncodingException {
|
||||
assertEquals(3, UUID.nameUUIDFromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8")).version());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion3NameBasedMD5Equals() throws UnsupportedEncodingException {
|
||||
UUID a = UUID.nameUUIDFromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
UUID b = UUID.nameUUIDFromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertEquals(a, b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion3NameBasedMD5NotEqualSHA1() throws UnsupportedEncodingException {
|
||||
UUID a = UUID.nameUUIDFromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
UUID b = UUIDFactory.nameUUIDv5FromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertFalse(a.equals(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion3NameBasedMD5FromStringRep() throws UnsupportedEncodingException {
|
||||
UUID a = UUID.nameUUIDFromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertEquals(a, UUID.fromString(a.toString()));
|
||||
}
|
||||
|
||||
// Version 5 UUIDs
|
||||
|
||||
@Test
|
||||
public void testVersion5NameBasedSHA1Variant() throws UnsupportedEncodingException {
|
||||
UUID a = UUIDFactory.nameUUIDv5FromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertEquals(2, a.variant());
|
||||
}
|
||||
@Test
|
||||
public void testVersion5NameBasedSHA1Version() throws UnsupportedEncodingException {
|
||||
UUID a = UUIDFactory.nameUUIDv5FromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertEquals(5, a.version());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion5NameBasedSHA1Equals() throws UnsupportedEncodingException {
|
||||
UUID a = UUIDFactory.nameUUIDv5FromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
UUID b = UUIDFactory.nameUUIDv5FromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertEquals(a, b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion5NameBasedSHA1Different() throws UnsupportedEncodingException {
|
||||
Random random = new Random();
|
||||
byte[] data = new byte[128];
|
||||
random.nextBytes(data);
|
||||
|
||||
UUID a = UUIDFactory.nameUUIDv5FromBytes(data);
|
||||
|
||||
// Swap a random byte with its "opposite"
|
||||
int i;
|
||||
while (data[i = random.nextInt(data.length)] == data[data.length - 1 - i]) {}
|
||||
data[i] = data[data.length - 1 - i];
|
||||
|
||||
UUID b = UUIDFactory.nameUUIDv5FromBytes(data);
|
||||
|
||||
assertFalse(a.equals(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion5NameBasedSHA1NotEqualMD5() throws UnsupportedEncodingException {
|
||||
UUID a = UUIDFactory.nameUUIDv5FromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
UUID b = UUID.nameUUIDFromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertFalse(a.equals(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion5NameBasedSHA1FromStringRep() throws UnsupportedEncodingException {
|
||||
UUID a = UUIDFactory.nameUUIDv5FromBytes(EXAMPLE_COM_UUID.getBytes("UTF-8"));
|
||||
assertEquals(a, UUID.fromString(a.toString()));
|
||||
}
|
||||
|
||||
// Version 1 UUIDs
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedVariant() {
|
||||
assertEquals(2, UUIDFactory.timeNodeBasedUUID().variant());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedVersion() {
|
||||
assertEquals(1, UUIDFactory.timeNodeBasedUUID().version());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedFromStringRep() {
|
||||
UUID uuid = UUIDFactory.timeNodeBasedUUID();
|
||||
assertEquals(uuid, UUID.fromString(uuid.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedMacAddress() {
|
||||
UUID uuid = UUIDFactory.timeNodeBasedUUID();
|
||||
assertEquals(UUIDFactory.MAC_ADDRESS_NODE, uuid.node());
|
||||
// TODO: Test that this is actually a Mac address from the local computer, or specified through system property?
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedClockSeq() {
|
||||
UUID uuid = UUIDFactory.timeNodeBasedUUID();
|
||||
assertEquals(UUIDFactory.Clock.getClockSequence(), uuid.clockSequence());
|
||||
|
||||
// Test time fields (within reasonable limits +/- 100 ms or so?)
|
||||
assertEquals(UUIDFactory.Clock.currentTimeHundredNanos(), uuid.timestamp(), 1e6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedTimestamp() {
|
||||
UUID uuid = UUIDFactory.timeNodeBasedUUID();
|
||||
// Test time fields (within reasonable limits +/- 100 ms or so?)
|
||||
assertEquals(UUIDFactory.Clock.currentTimeHundredNanos(), uuid.timestamp(), 1e6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedUniMulticastBitUnset() {
|
||||
// Do it a couple of times, to avoid accidentally have correct bit
|
||||
for (int i = 0; i < 100; i++) {
|
||||
UUID uuid = UUIDFactory.timeNodeBasedUUID();
|
||||
assertEquals(0, (uuid.node() >> 40) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1NodeBasedUnique() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
UUID a = UUIDFactory.timeNodeBasedUUID();
|
||||
UUID b = UUIDFactory.timeNodeBasedUUID();
|
||||
assertFalse(a.equals(b));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomVariant() {
|
||||
assertEquals(2, UUIDFactory.timeRandomBasedUUID().variant());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomVersion() {
|
||||
assertEquals(1, UUIDFactory.timeRandomBasedUUID().version());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomFromStringRep() {
|
||||
UUID uuid = UUIDFactory.timeRandomBasedUUID();
|
||||
assertEquals(uuid, UUID.fromString(uuid.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomNode() {
|
||||
UUID uuid = UUIDFactory.timeRandomBasedUUID();
|
||||
assertEquals(UUIDFactory.SECURE_RANDOM_NODE, uuid.node());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomClockSeq() {
|
||||
UUID uuid = UUIDFactory.timeRandomBasedUUID();
|
||||
assertEquals(UUIDFactory.Clock.getClockSequence(), uuid.clockSequence());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomTimestamp() {
|
||||
UUID uuid = UUIDFactory.timeRandomBasedUUID();
|
||||
|
||||
// Test time fields (within reasonable limits +/- 100 ms or so?)
|
||||
assertEquals(UUIDFactory.Clock.currentTimeHundredNanos(), uuid.timestamp(), 1e6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomUniMulticastBit() {
|
||||
// Do it a couple of times, to avoid accidentally have correct bit
|
||||
for (int i = 0; i < 100; i++) {
|
||||
UUID uuid = UUIDFactory.timeRandomBasedUUID();
|
||||
assertEquals(1, (uuid.node() >> 40) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion1SecureRandomUnique() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
UUID a = UUIDFactory.timeRandomBasedUUID();
|
||||
UUID b = UUIDFactory.timeRandomBasedUUID();
|
||||
assertFalse(a.equals(b));
|
||||
}
|
||||
}
|
||||
|
||||
// Clock tests
|
||||
|
||||
@Test(timeout = 10000l)
|
||||
public void testClock() throws InterruptedException {
|
||||
final long[] times = new long[100000];
|
||||
|
||||
ExecutorService service = Executors.newFixedThreadPool(20);
|
||||
for (int i = 0; i < times.length; i++) {
|
||||
final int index = i;
|
||||
|
||||
service.submit(new Runnable() {
|
||||
public void run() {
|
||||
times[index] = UUIDFactory.Clock.currentTimeHundredNanos();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
service.shutdown();
|
||||
assertTrue("Execution timed out", service.awaitTermination(10, TimeUnit.SECONDS));
|
||||
|
||||
Arrays.sort(times); // This is what really takes time...
|
||||
|
||||
for (int i = 0, timesLength = times.length; i < timesLength; i++) {
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
assertFalse(String.format("times[%d] == times[%d]: 0x%016x", i - 1, i, times[i]), times[i - 1] == times[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 10000l)
|
||||
public void testClockSkew() throws InterruptedException {
|
||||
long clockSequence = UUIDFactory.Clock.getClockSequence();
|
||||
|
||||
ExecutorService service = Executors.newFixedThreadPool(10);
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
service.submit(new Runnable() {
|
||||
public void run() {
|
||||
UUIDFactory.Clock.currentTimeHundredNanos();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
service.shutdown();
|
||||
assertTrue("Execution timed out", service.awaitTermination(10, TimeUnit.SECONDS));
|
||||
|
||||
assertEquals(clockSequence, UUIDFactory.Clock.getClockSequence(), 1); // Verify that clock skew doesn't happen "often"
|
||||
}
|
||||
|
||||
// Tests for node address system property
|
||||
|
||||
@Test
|
||||
public void testParseNodeAddressesSingle() {
|
||||
long[] nodes = UUIDFactory.parseMacAddressNodes("00:11:22:33:44:55");
|
||||
|
||||
assertEquals(1, nodes.length);
|
||||
assertEquals(0x001122334455l, nodes[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseNodeAddressesSingleWhitespace() {
|
||||
long[] nodes = UUIDFactory.parseMacAddressNodes(" 00:11:22:33:44:55\r\n");
|
||||
|
||||
assertEquals(1, nodes.length);
|
||||
assertEquals(0x001122334455l, nodes[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseNodeAddressesMulti() {
|
||||
long[] nodes = UUIDFactory.parseMacAddressNodes("00:11:22:33:44:55, aa:bb:cc:dd:ee:ff, \n\t 0a-1b-2c-3d-4e-5f,");
|
||||
|
||||
assertEquals(3, nodes.length);
|
||||
assertEquals(0x001122334455l, nodes[0]);
|
||||
assertEquals(0xaabbccddeeffl, nodes[1]);
|
||||
assertEquals(0x0a1b2c3d4e5fl, nodes[2]);
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void testParseNodeAddressesNull() {
|
||||
UUIDFactory.parseMacAddressNodes(null);
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseNodeAddressesEmpty() {
|
||||
UUIDFactory.parseMacAddressNodes("");
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseNodeAddressesNonAddress() {
|
||||
UUIDFactory.parseMacAddressNodes("127.0.0.1");
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseNodeAddressesBadAddress() {
|
||||
UUIDFactory.parseMacAddressNodes("00a:11:22:33:44:55");
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseNodeAddressesBadAddress4() {
|
||||
UUIDFactory.parseMacAddressNodes("00:11:22:33:44:550");
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseNodeAddressesBadAddress2() {
|
||||
UUIDFactory.parseMacAddressNodes("0x:11:22:33:44:55");
|
||||
}
|
||||
|
||||
@Test(expected = NumberFormatException.class)
|
||||
public void testParseNodeAddressesBadAddress3() {
|
||||
UUIDFactory.parseMacAddressNodes("00:11:22:33:44:55:99");
|
||||
}
|
||||
|
||||
// Comparator test
|
||||
|
||||
@Test
|
||||
public void testComparator() {
|
||||
UUID min = new UUID(0, 0);
|
||||
// Long.MAX_VALUE and MIN_VALUE are really adjacent values when comparing unsigned...
|
||||
UUID midLow = new UUID(Long.MAX_VALUE, Long.MAX_VALUE);
|
||||
UUID midHigh = new UUID(Long.MIN_VALUE, Long.MIN_VALUE);
|
||||
UUID max = new UUID(-1l, -1l);
|
||||
|
||||
Comparator<UUID> comparator = UUIDFactory.comparator();
|
||||
|
||||
assertEquals(0, comparator.compare(min, min));
|
||||
assertEquals(-1, comparator.compare(min, midLow));
|
||||
assertEquals(-1, comparator.compare(min, midHigh));
|
||||
assertEquals(-1, comparator.compare(min, max));
|
||||
|
||||
assertEquals(1, comparator.compare(midLow, min));
|
||||
assertEquals(0, comparator.compare(midLow, midLow));
|
||||
assertEquals(-1, comparator.compare(midLow, midHigh));
|
||||
assertEquals(-1, comparator.compare(midLow, max));
|
||||
|
||||
assertEquals(1, comparator.compare(midHigh, min));
|
||||
assertEquals(1, comparator.compare(midHigh, midLow));
|
||||
assertEquals(0, comparator.compare(midHigh, midHigh));
|
||||
assertEquals(-1, comparator.compare(midHigh, max));
|
||||
|
||||
assertEquals(1, comparator.compare(max, min));
|
||||
assertEquals(1, comparator.compare(max, midLow));
|
||||
assertEquals(1, comparator.compare(max, midHigh));
|
||||
assertEquals(0, comparator.compare(max, max));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparatorRandom() {
|
||||
final Comparator<UUID> comparator = UUIDFactory.comparator();
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
UUID one = UUID.randomUUID();
|
||||
UUID two = UUID.randomUUID();
|
||||
|
||||
if (one.getMostSignificantBits() < 0 && two.getMostSignificantBits() >= 0
|
||||
|| one.getMostSignificantBits() >= 0 && two.getMostSignificantBits() < 0
|
||||
|| one.getLeastSignificantBits() < 0 && two.getLeastSignificantBits() >= 0
|
||||
|| one.getLeastSignificantBits() >= 0 && two.getLeastSignificantBits() < 0) {
|
||||
// These will differ due to the differing signs
|
||||
assertEquals(-one.compareTo(two), comparator.compare(one, two));
|
||||
}
|
||||
else {
|
||||
assertEquals(one.compareTo(two), comparator.compare(one, two));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Various testing
|
||||
|
||||
@Ignore("Development testing only")
|
||||
@Test
|
||||
public void testOracleSYS_GUID() {
|
||||
// TODO: Consider including this as a "fromCompactString" or similar...
|
||||
String str = "AEB87F28E222D08AE043803BD559D08A";
|
||||
BigInteger bigInteger = new BigInteger(str, 16); // ALT: Create byte array of every 2 chars.
|
||||
long msb = bigInteger.shiftRight(64).longValue();
|
||||
long lsb = bigInteger.longValue();
|
||||
UUID uuid = new UUID(msb, lsb);
|
||||
System.err.println("uuid: " + uuid);
|
||||
System.err.println("uuid.variant(): " + uuid.variant());
|
||||
System.err.println("uuid.version(): " + uuid.version());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twlevemonkeys.image;
|
||||
|
||||
import com.twelvemonkeys.image.MappedFileBuffer;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* MappedFileBufferTest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: MappedFileBufferTest.java,v 1.0 01.06.12 14:23 haraldk Exp$
|
||||
*/
|
||||
public class MappedFileBufferTest {
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateInvalidType() throws IOException {
|
||||
MappedFileBuffer.create(-1, 1, 1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateInvalidSize() throws IOException {
|
||||
MappedFileBuffer.create(DataBuffer.TYPE_USHORT, -1, 1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateInvalidBands() throws IOException {
|
||||
MappedFileBuffer.create(DataBuffer.TYPE_BYTE, 1, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateByte() throws IOException {
|
||||
DataBuffer buffer = MappedFileBuffer.create(DataBuffer.TYPE_BYTE, 256, 3);
|
||||
assertNotNull(buffer);
|
||||
|
||||
assertEquals(DataBuffer.TYPE_BYTE, buffer.getDataType());
|
||||
assertEquals(256, buffer.getSize());
|
||||
assertEquals(3, buffer.getNumBanks());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGetElemByte() throws IOException {
|
||||
final int size = 256;
|
||||
DataBuffer buffer = MappedFileBuffer.create(DataBuffer.TYPE_BYTE, size, 3);
|
||||
assertNotNull(buffer);
|
||||
|
||||
for (int b = 0; b < 3; b++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
buffer.setElem(b, i, i);
|
||||
|
||||
assertEquals(i, buffer.getElem(b, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUShort() throws IOException {
|
||||
DataBuffer buffer = MappedFileBuffer.create(DataBuffer.TYPE_USHORT, 256, 3);
|
||||
assertNotNull(buffer);
|
||||
|
||||
assertEquals(DataBuffer.TYPE_USHORT, buffer.getDataType());
|
||||
assertEquals(256, buffer.getSize());
|
||||
assertEquals(3, buffer.getNumBanks());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGetElemUShort() throws IOException {
|
||||
final int size = (Short.MAX_VALUE + 1) * 2;
|
||||
DataBuffer buffer = MappedFileBuffer.create(DataBuffer.TYPE_USHORT, size, 3);
|
||||
assertNotNull(buffer);
|
||||
|
||||
for (int b = 0; b < 3; b++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
buffer.setElem(b, i, i);
|
||||
|
||||
assertEquals(i, buffer.getElem(b, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInt() throws IOException {
|
||||
DataBuffer buffer = MappedFileBuffer.create(DataBuffer.TYPE_INT, 256, 3);
|
||||
assertNotNull(buffer);
|
||||
|
||||
assertEquals(DataBuffer.TYPE_INT, buffer.getDataType());
|
||||
assertEquals(256, buffer.getSize());
|
||||
assertEquals(3, buffer.getNumBanks());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGetElemInt() throws IOException {
|
||||
final int size = (Short.MAX_VALUE + 1) * 2;
|
||||
DataBuffer buffer = MappedFileBuffer.create(DataBuffer.TYPE_INT, size, 3);
|
||||
assertNotNull(buffer);
|
||||
|
||||
for (int b = 0; b < 3; b++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
buffer.setElem(b, i, i * i);
|
||||
|
||||
assertEquals(i * i, buffer.getElem(b, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
sandbox/sandbox-imageio/pom.xml
Normal file
80
sandbox/sandbox-imageio/pom.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Copyright (c) 2011, Harald Kuhr
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without
|
||||
~ modification, are permitted provided that the following conditions are met:
|
||||
~ * Redistributions of source code must retain the above copyright
|
||||
~ notice, this list of conditions and the following disclaimer.
|
||||
~ * Redistributions in binary form must reproduce the above copyright
|
||||
~ notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~ * Neither the name "TwelveMonkeys" nor the
|
||||
~ names of its contributors may be used to endorse or promote products
|
||||
~ derived from this software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
~ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
~ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
~ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
~ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
~ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
~ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
~ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
~ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
~ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<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.sandbox</groupId>
|
||||
<artifactId>sandbox</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>sandbox-imageio</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Sandbox :: ImageIO</name>
|
||||
<description>
|
||||
The TwelveMonkeys ImageIO Sandbox. Experimental stuff. Old retired stuff.
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-image</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<scope>test</scope>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<scope>test</scope>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
90
sandbox/sandbox-servlet/pom.xml
Normal file
90
sandbox/sandbox-servlet/pom.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Copyright (c) 2011, Harald Kuhr
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without
|
||||
~ modification, are permitted provided that the following conditions are met:
|
||||
~ * Redistributions of source code must retain the above copyright
|
||||
~ notice, this list of conditions and the following disclaimer.
|
||||
~ * Redistributions in binary form must reproduce the above copyright
|
||||
~ notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~ * Neither the name "TwelveMonkeys" nor the
|
||||
~ names of its contributors may be used to endorse or promote products
|
||||
~ derived from this software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
~ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
~ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
~ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
~ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
~ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
~ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
~ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
~ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
~ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<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.sandbox</groupId>
|
||||
<artifactId>sandbox</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>sandbox-servlet</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Sandbox :: Servlet</name>
|
||||
<description>
|
||||
The TwelveMonkeys Servlet Sandbox. Experimental stuff. Old stuff that didn't cut it.
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-image</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jsp-api</artifactId>
|
||||
<version>2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.14</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.image;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.ServletUtil;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* style or color, into an image, and output it as a GIF, JPEG or PNG image,
|
||||
* with optional caching of the rendered image files.
|
||||
*
|
||||
* <P><HR><P>
|
||||
*
|
||||
* <A name="parameters"></A><STRONG>Parameters:</STRONG><BR>
|
||||
* <DL>
|
||||
* <DT>{@code text}</DT>
|
||||
* <DD>string, the text string to render.
|
||||
* <DT>{@code width}</DT>
|
||||
* <DD>integer, the width of the image
|
||||
* <DT>{@code height}</DT>
|
||||
* <DD>integer, the height of the image
|
||||
* <DT>{@code fontFamily}</DT>
|
||||
* <DD>string, the name of the font family.
|
||||
* Default is {@code "Helvetica"}.
|
||||
* <DT>{@code fontSize}</DT>
|
||||
* <DD>integer, the size of the font. Default is {@code 12}.
|
||||
* <DT>{@code fontStyle}</DT>
|
||||
* <DD>string, the tyle of the font. Can be one of the constants
|
||||
* {@code plain} (default), {@code bold}, {@code italic} or
|
||||
* {@code bolditalic}. Any other will result in {@code plain}.
|
||||
* <DT>{@code fgcolor}</DT>
|
||||
* <DD>color (HTML form, {@code #RRGGBB}), or color constant from
|
||||
* {@link java.awt.Color}, default is {@code "black"}.
|
||||
* <DT>{@code bgcolor}</DT>
|
||||
* <DD>color (HTML form, {@code #RRGGBB}), or color constant from
|
||||
* {@link java.awt.Color}, default is {@code "transparent"}.
|
||||
* Note that the hash character ({@code "#"}) used in colors must be
|
||||
* escaped as {@code %23} in the query string. See
|
||||
* {@link StringUtil#toColor(String)}, <A href="#examples">examples</A>.
|
||||
*
|
||||
* <!-- inherited from ImageServlet below: -->
|
||||
*
|
||||
* <DT>{@code cache}</DT>
|
||||
* <DD>boolean, {@code true} if you want to cache the result
|
||||
* to disk (default).
|
||||
*
|
||||
* <DT>{@code compression}</DT>
|
||||
* <DD>float, the optional compression ratio for the output image. For JPEG
|
||||
* images, the quality is the inverse of the compression ratio. See
|
||||
* {@link #JPEG_DEFAULT_COMPRESSION_LEVEL},
|
||||
* {@link #PNG_DEFAULT_COMPRESSION_LEVEL}.
|
||||
* <DD>Applies to JPEG and PNG images only.
|
||||
*
|
||||
* <DT>{@code dither}</DT>
|
||||
* <DD>enumerated, one of {@code NONE}, {@code DEFAULT} or
|
||||
* {@code FS}, if you want to dither the result ({@code DEFAULT} is
|
||||
* default).
|
||||
* {@code FS} will produce the best results, but it's slower.
|
||||
* <DD>Use in conjuction with {@code indexed}, {@code palette}
|
||||
* and {@code websafe}.
|
||||
* <DD>Applies to GIF and PNG images only.
|
||||
*
|
||||
* <DT>{@code fileName}</DT>
|
||||
* <DD>string, an optional filename. If not set, the path after the servlet
|
||||
* ({@link HttpServletRequest#getPathInfo}) will be used for the cache
|
||||
* filename. See {@link #getCacheFile(ServletRequest)},
|
||||
* {@link #getCacheRoot}.
|
||||
*
|
||||
* <DT>{@code height}</DT>
|
||||
* <DD>integer, the height of the image.
|
||||
*
|
||||
* <DT>{@code width}</DT>
|
||||
* <DD>integer, the width of the image.
|
||||
*
|
||||
* <DT>{@code indexed}</DT>
|
||||
* <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
|
||||
* {@code IndexColorModel} with
|
||||
* the number of colors specified. Otherwise the image will be true color.
|
||||
* <DD>Applies to GIF and PNG images only.
|
||||
*
|
||||
* <DT>{@code palette}</DT>
|
||||
* <DD>string, an optional filename. If set, the image will use IndexColorModel
|
||||
* with a palette read from the given file.
|
||||
* <DD>Applies to GIF and PNG images only.
|
||||
*
|
||||
* <DT>{@code websafe}</DT>
|
||||
* <DD>boolean, {@code true} if you want the result to use the 216 color
|
||||
* websafe palette (default is false).
|
||||
* <DD>Applies to GIF and PNG images only.
|
||||
* </DL>
|
||||
*
|
||||
* @example
|
||||
* <IMG src="/text/test.gif?height=40&width=600
|
||||
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=%23990033
|
||||
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
||||
* %20lazy%20dog&cache=false" />
|
||||
*
|
||||
* @example
|
||||
* <IMG src="/text/test.jpg?height=40&width=600
|
||||
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=black
|
||||
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
||||
* %20lazy%20dog&compression=3&cache=false" />
|
||||
*
|
||||
* @example
|
||||
* <IMG src="/text/test.png?height=40&width=600
|
||||
* &fontFamily=TimesRoman&fontSize=30&fontStyle=italic&fgcolor=%23336699
|
||||
* &bgcolor=%23cccccc&text=the%20quick%20brown%20fox%20jumps%20over%20the
|
||||
* %20lazy%20dog&cache=true" />
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: TextRenderer.java#2 $
|
||||
*/
|
||||
|
||||
class TextRenderer /*extends ImageServlet implements ImagePainterServlet*/ {
|
||||
// TODO: Create something usable out of this piece of old junk.. ;-)
|
||||
// It just needs a graphics object to write onto
|
||||
// Alternatively, defer, and compute the size needed
|
||||
// Or, make it a filter...
|
||||
|
||||
/** {@code "italic"} */
|
||||
public final static String FONT_STYLE_ITALIC = "italic";
|
||||
/** {@code "plain"} */
|
||||
public final static String FONT_STYLE_PLAIN = "plain";
|
||||
/** {@code "bold"} */
|
||||
public final static String FONT_STYLE_BOLD = "bold";
|
||||
|
||||
/** {@code text} */
|
||||
public final static String PARAM_TEXT = "text";
|
||||
/** {@code marginLeft} */
|
||||
public final static String PARAM_MARGIN_LEFT = "marginLeft";
|
||||
/** {@code marginTop} */
|
||||
public final static String PARAM_MARGIN_TOP = "marginTop";
|
||||
/** {@code fontFamily} */
|
||||
public final static String PARAM_FONT_FAMILY = "fontFamily";
|
||||
/** {@code fontSize} */
|
||||
public final static String PARAM_FONT_SIZE = "fontSize";
|
||||
/** {@code fontStyle} */
|
||||
public final static String PARAM_FONT_STYLE = "fontStyle";
|
||||
/** {@code textRotation} */
|
||||
public final static String PARAM_TEXT_ROTATION = "textRotation";
|
||||
/** {@code textRotation} */
|
||||
public final static String PARAM_TEXT_ROTATION_UNITS = "textRotationUnits";
|
||||
|
||||
/** {@code bgcolor} */
|
||||
public final static String PARAM_BGCOLOR = "bgcolor";
|
||||
/** {@code fgcolor} */
|
||||
public final static String PARAM_FGCOLOR = "fgcolor";
|
||||
|
||||
protected final static String ROTATION_DEGREES = "DEGREES";
|
||||
protected final static String ROTATION_RADIANS = "RADIANS";
|
||||
|
||||
/**
|
||||
* Creates the TextRender servlet.
|
||||
*/
|
||||
|
||||
public TextRenderer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the text string for this servlet request.
|
||||
*/
|
||||
private void paint(ServletRequest pReq, Graphics2D pRes, int pWidth, int pHeight)
|
||||
throws ImageServletException {
|
||||
|
||||
// Get parameters
|
||||
String text = pReq.getParameter(PARAM_TEXT);
|
||||
String[] lines = StringUtil.toStringArray(text, "\n\r");
|
||||
|
||||
String fontFamily = pReq.getParameter(PARAM_FONT_FAMILY);
|
||||
String fontSize = pReq.getParameter(PARAM_FONT_SIZE);
|
||||
String fontStyle = pReq.getParameter(PARAM_FONT_STYLE);
|
||||
|
||||
String bgcolor = pReq.getParameter(PARAM_BGCOLOR);
|
||||
String fgcolor = pReq.getParameter(PARAM_FGCOLOR);
|
||||
|
||||
// TODO: Make them static..
|
||||
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_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY));
|
||||
// pRes.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
|
||||
|
||||
//System.out.println(pRes.getBackground());
|
||||
|
||||
// Clear area with bgcolor
|
||||
if (!StringUtil.isEmpty(bgcolor)) {
|
||||
pRes.setBackground(StringUtil.toColor(bgcolor));
|
||||
pRes.clearRect(0, 0, pWidth, pHeight);
|
||||
|
||||
//System.out.println(pRes.getBackground());
|
||||
}
|
||||
|
||||
// Create and set font
|
||||
Font font = new Font(
|
||||
fontFamily != null ? fontFamily : "Helvetica",
|
||||
getFontStyle(fontStyle),
|
||||
fontSize != null ? Integer.parseInt(fontSize) : 12
|
||||
);
|
||||
pRes.setFont(font);
|
||||
|
||||
// Set rotation
|
||||
double angle = getAngle(pReq);
|
||||
pRes.rotate(angle, pWidth / 2.0, pHeight / 2.0);
|
||||
|
||||
// Draw string in fgcolor
|
||||
pRes.setColor(fgcolor != null ? StringUtil.toColor(fgcolor) : Color.black);
|
||||
|
||||
float x = ServletUtil.getFloatParameter(pReq, PARAM_MARGIN_LEFT, Float.MIN_VALUE);
|
||||
Rectangle2D[] bounds = new Rectangle2D[lines.length];
|
||||
if (x <= Float.MIN_VALUE) {
|
||||
// Center
|
||||
float longest = 0f;
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
bounds[i] = font.getStringBounds(lines[i], pRes.getFontRenderContext());
|
||||
if (bounds[i].getWidth() > longest) {
|
||||
longest = (float) bounds[i].getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
//x = (float) ((pWidth - bounds.getWidth()) / 2f);
|
||||
x = (float) ((pWidth - longest) / 2f);
|
||||
|
||||
//System.out.println("marginLeft: " + x);
|
||||
}
|
||||
//else {
|
||||
//System.out.println("marginLeft (from param): " + x);
|
||||
//}
|
||||
|
||||
float y = ServletUtil.getFloatParameter(pReq, PARAM_MARGIN_TOP, Float.MIN_VALUE);
|
||||
float lineHeight = (float) (bounds[0] != null ?
|
||||
bounds[0].getHeight() : font.getStringBounds(lines[0], pRes.getFontRenderContext()).getHeight());
|
||||
|
||||
if (y <= Float.MIN_VALUE) {
|
||||
// Center
|
||||
y = (float) ((pHeight - lineHeight) / 2f)
|
||||
- (lineHeight * (lines.length - 2.5f) / 2f);
|
||||
|
||||
//System.out.println("marginTop: " + y);
|
||||
}
|
||||
else {
|
||||
// Todo: Correct for font height?
|
||||
y += font.getSize2D();
|
||||
//System.out.println("marginTop (from param):" + y);
|
||||
|
||||
}
|
||||
|
||||
//System.out.println("Font size: " + font.getSize2D());
|
||||
//System.out.println("Line height: " + lineHeight);
|
||||
|
||||
// Draw
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
pRes.drawString(lines[i], x, y + lineHeight * i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font style constant.
|
||||
*
|
||||
* @param pStyle a string containing either the word {@code "plain"} or one
|
||||
* or more of {@code "bold"} and {@code italic}.
|
||||
* @return the font style constant as defined in {@link Font}.
|
||||
*
|
||||
* @see Font#PLAIN
|
||||
* @see Font#BOLD
|
||||
* @see Font#ITALIC
|
||||
*/
|
||||
private int getFontStyle(String pStyle) {
|
||||
if (pStyle == null || StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_PLAIN)) {
|
||||
return Font.PLAIN;
|
||||
}
|
||||
|
||||
// Try to find bold/italic
|
||||
int style = Font.PLAIN;
|
||||
if (StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_BOLD)) {
|
||||
style |= Font.BOLD;
|
||||
}
|
||||
if (StringUtil.containsIgnoreCase(pStyle, FONT_STYLE_ITALIC)) {
|
||||
style |= Font.ITALIC;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the angle of rotation from the request.
|
||||
*
|
||||
* @param pRequest the servlet request to get parameters from
|
||||
* @return the angle in radians.
|
||||
*/
|
||||
private double getAngle(ServletRequest pRequest) {
|
||||
// Get angle
|
||||
double angle = ServletUtil.getDoubleParameter(pRequest, PARAM_TEXT_ROTATION, 0.0);
|
||||
|
||||
// Convert to radians, if needed
|
||||
String units = pRequest.getParameter(PARAM_TEXT_ROTATION_UNITS);
|
||||
if (!StringUtil.isEmpty(units) && ROTATION_DEGREES.equalsIgnoreCase(units)) {
|
||||
angle = Math.toRadians(angle);
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: Droplet.java,v $
|
||||
* Revision 1.3 2003/10/06 14:25:19 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.2 2002/10/18 14:12:16 WMHAKUR
|
||||
* Now, it even compiles. :-/
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:02:16 WMHAKUR
|
||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||
|
||||
import com.twelvemonkeys.servlet.jsp.droplet.taglib.IncludeTag;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Dynamo Droplet like Servlet.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*
|
||||
*/
|
||||
public abstract class Droplet extends HttpServlet implements JspFragment {
|
||||
|
||||
public abstract void service(PageContext pPageContext)
|
||||
throws ServletException, IOException;
|
||||
|
||||
/**
|
||||
* Services a parameter. Programatically equivalent to the
|
||||
* <d:valueof param="pParameter"/> JSP tag.
|
||||
*/
|
||||
public void serviceParameter(String pParameter, PageContext pPageContext) throws ServletException, IOException {
|
||||
Object param = pPageContext.getRequest().getAttribute(pParameter);
|
||||
|
||||
if (param != null) {
|
||||
if (param instanceof Param) {
|
||||
((Param) param).service(pPageContext);
|
||||
}
|
||||
else {
|
||||
pPageContext.getOut().print(param);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Try to get value from parameters
|
||||
Object obj = pPageContext.getRequest().getParameter(pParameter);
|
||||
|
||||
// Print parameter or default value
|
||||
pPageContext.getOut().print((obj != null) ? obj : "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "There's no need to override this method." :-)
|
||||
*/
|
||||
final public void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException {
|
||||
PageContext pageContext = (PageContext) pRequest.getAttribute(IncludeTag.PAGE_CONTEXT);
|
||||
|
||||
// TODO: What if pageContext == null
|
||||
service(pageContext);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: JspFragment.java,v $
|
||||
* Revision 1.2 2003/10/06 14:25:36 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:02:16 WMHAKUR
|
||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Interface for JSP sub pages or page fragments to implement.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*/
|
||||
public interface JspFragment {
|
||||
|
||||
/**
|
||||
* Services a sub page or a page fragment inside another page
|
||||
* (or PageContext).
|
||||
*
|
||||
* @param pContext the PageContext that is used to render the subpage.
|
||||
*
|
||||
* @throws ServletException if an exception occurs that interferes with the
|
||||
* subpage's normal operation
|
||||
* @throws IOException if an input or output exception occurs
|
||||
*/
|
||||
public void service(PageContext pContext) throws ServletException, IOException;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Oparam (Open parameter)
|
||||
*/
|
||||
public class Oparam extends Param implements JspFragment {
|
||||
/**
|
||||
* Creates an Oparam.
|
||||
*
|
||||
* @param pValue the value of the parameter
|
||||
*/
|
||||
public Oparam(String pValue) {
|
||||
super(pValue);
|
||||
}
|
||||
|
||||
public void service(PageContext pContext) throws ServletException, IOException {
|
||||
pContext.getServletContext().log("Service subpage " + pContext.getServletContext().getRealPath(value));
|
||||
|
||||
pContext.include(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Param
|
||||
*/
|
||||
public class Param implements JspFragment {
|
||||
|
||||
/** The value member field. */
|
||||
protected String value = null;
|
||||
|
||||
/**
|
||||
* Creates a Param.
|
||||
*
|
||||
* @param pValue the value of the parameter
|
||||
*/
|
||||
public Param(String pValue) {
|
||||
value = pValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the parameter.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Services the page fragment. This version simply prints the value of
|
||||
* this parameter to teh PageContext's out.
|
||||
*/
|
||||
public void service(PageContext pContext)
|
||||
throws ServletException, IOException {
|
||||
JspWriter writer = pContext.getOut();
|
||||
writer.print(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Dynamo Droplet-like functionality for JSP.
|
||||
*
|
||||
* This package is early beta, not for commercial use! :-)
|
||||
* Read: The interfaces and classes in this package (and subpackages) will be
|
||||
* developed and modified for a while.
|
||||
*
|
||||
*/
|
||||
package com.twelvemonkeys.servlet.jsp.droplet;
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: IncludeTag.java,v $
|
||||
* Revision 1.2 2003/10/06 14:25:36 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||
|
||||
import com.twelvemonkeys.servlet.jsp.taglib.ExTagSupport;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Include tag tag that emulates ATG Dynamo Droplet tag JHTML behaviour for
|
||||
* JSP.
|
||||
*
|
||||
* @author Thomas Purcell (CSC Australia)
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*
|
||||
*/
|
||||
public class IncludeTag extends ExTagSupport {
|
||||
/**
|
||||
* This will contain the names of all the parameters that have been
|
||||
* added to the PageContext.REQUEST_SCOPE scope by this tag.
|
||||
*/
|
||||
private ArrayList<String> parameterNames = null;
|
||||
|
||||
/**
|
||||
* If any of the parameters we insert for this tag already exist, then
|
||||
* we back up the older parameter in this {@code HashMap} and
|
||||
* restore them when the tag is finished.
|
||||
*/
|
||||
private HashMap<String, Object> oldParameters = null;
|
||||
|
||||
/**
|
||||
* This is the URL for the JSP page that the parameters contained in this
|
||||
* tag are to be inserted into.
|
||||
*/
|
||||
private String page;
|
||||
|
||||
/**
|
||||
* The name of the PageContext attribute
|
||||
*/
|
||||
public final static String PAGE_CONTEXT = "com.twelvemonkeys.servlet.jsp.PageContext";
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param pPage The URL for the JSP page to insert parameters into.
|
||||
*/
|
||||
public void setPage(String pPage) {
|
||||
page = pPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter to the {@code PageContext.REQUEST_SCOPE} scope.
|
||||
* If a parameter with the same name as {@code pName} already exists,
|
||||
* then the old parameter is first placed in the {@code OldParameters}
|
||||
* member variable. When this tag is finished, the old value will be
|
||||
* restored.
|
||||
*
|
||||
* @param pName The name of the new parameter to be stored in the
|
||||
* {@code PageContext.REQUEST_SCOPE} scope.
|
||||
* @param pValue The value for the parmeter to be stored in the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
public void addParameter(String pName, Object pValue) {
|
||||
// Check that we haven't already saved this parameter
|
||||
if (!parameterNames.contains(pName)) {
|
||||
parameterNames.add(pName);
|
||||
|
||||
// Now check if this parameter already exists in the page.
|
||||
Object obj = getRequest().getAttribute(pName);
|
||||
if (obj != null) {
|
||||
oldParameters.put(pName, obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, insert the parameter in the request scope.
|
||||
getRequest().setAttribute(pName, pValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the method called when the JSP interpreter first hits the tag
|
||||
* associated with this class. This method will firstly determine whether
|
||||
* the page referenced by the {@code page} attribute exists. If the
|
||||
* 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
|
||||
* page.
|
||||
*
|
||||
* @exception JspException
|
||||
*/
|
||||
public int doStartTag() throws JspException {
|
||||
oldParameters = new HashMap<String, Object>();
|
||||
parameterNames = new ArrayList<String>();
|
||||
|
||||
return EVAL_BODY_INCLUDE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the {@code PageContext.REQUEST_SCOPE} scope. This method includes
|
||||
* the JSP page whose URL is stored in the {@code mPage} member
|
||||
* variable.
|
||||
*
|
||||
* @exception JspException
|
||||
*/
|
||||
public int doEndTag() throws JspException {
|
||||
String msg;
|
||||
|
||||
try {
|
||||
Iterator<String> iterator;
|
||||
String parameterName;
|
||||
|
||||
// -- Harald K 20020726
|
||||
// Include the page, in place
|
||||
//getDispatcher().include(getRequest(), getResponse());
|
||||
addParameter(PAGE_CONTEXT, pageContext); // Will be cleared later
|
||||
pageContext.include(page);
|
||||
|
||||
// Remove all the parameters that were added to the request scope
|
||||
// for this insert tag.
|
||||
iterator = parameterNames.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
parameterName = iterator.next();
|
||||
|
||||
getRequest().removeAttribute(parameterName);
|
||||
}
|
||||
|
||||
iterator = oldParameters.keySet().iterator();
|
||||
|
||||
// Restore the parameters we temporarily replaced (if any).
|
||||
while (iterator.hasNext()) {
|
||||
parameterName = iterator.next();
|
||||
|
||||
getRequest().setAttribute(parameterName, oldParameters.get(parameterName));
|
||||
}
|
||||
|
||||
return super.doEndTag();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
msg = "Caught an IOException while including " + page
|
||||
+ "\n" + ioe.toString();
|
||||
log(msg, ioe);
|
||||
throw new JspException(msg);
|
||||
}
|
||||
catch (ServletException se) {
|
||||
msg = "Caught a ServletException while including " + page
|
||||
+ "\n" + se.toString();
|
||||
log(msg, se);
|
||||
throw new JspException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free up the member variables that we've used throughout this tag.
|
||||
*/
|
||||
protected void clearServiceState() {
|
||||
oldParameters = null;
|
||||
parameterNames = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request dispatcher for the JSP page whose URL is stored in
|
||||
* the {@code mPage} member variable.
|
||||
*
|
||||
* @return The RequestDispatcher for the JSP page whose URL is stored in
|
||||
* the {@code mPage} member variable.
|
||||
*/
|
||||
/*
|
||||
private RequestDispatcher getDispatcher() {
|
||||
return getRequest().getRequestDispatcher(page);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the HttpServletRequest object for the current user request.
|
||||
*
|
||||
* @return The HttpServletRequest object for the current user request.
|
||||
*/
|
||||
private HttpServletRequest getRequest() {
|
||||
return (HttpServletRequest) pageContext.getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HttpServletResponse object for the current user request.
|
||||
*
|
||||
* @return The HttpServletResponse object for the current user request.
|
||||
*/
|
||||
private HttpServletResponse getResponse() {
|
||||
return (HttpServletResponse) pageContext.getResponse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: NestingHandler.java,v $
|
||||
* Revision 1.4 2003/10/06 14:25:44 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.3 2003/08/04 15:26:30 WMHAKUR
|
||||
* Code clean-up.
|
||||
*
|
||||
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
||||
* Fixed package error.
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import org.xml.sax.*;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* A SAX handler that returns an exception if the nesting of
|
||||
* {@code param}, {@code oparam}, {@code droplet} and
|
||||
* {@code valueof} is not correct.
|
||||
*
|
||||
* Based on the NestingHandler.java,
|
||||
* taken from More Servlets and JavaServer Pages
|
||||
* from Prentice Hall and Sun Microsystems Press,
|
||||
* http://www.moreservlets.com/.
|
||||
* © 2002 Marty Hall; may be freely used or adapted.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*/
|
||||
public class NestingHandler extends DefaultHandler {
|
||||
private String includeTagName = "include";
|
||||
private String paramTagName = "param";
|
||||
private String openParamTagName = "oparam";
|
||||
|
||||
//private Stack mParents = new Stack();
|
||||
|
||||
private boolean inIncludeTag = false;
|
||||
|
||||
private String namespacePrefix = null;
|
||||
private String namespaceURI = null;
|
||||
|
||||
private NestingValidator validator = null;
|
||||
|
||||
public NestingHandler(String pNamespacePrefix, String pNameSpaceURI,
|
||||
NestingValidator pValidator) {
|
||||
namespacePrefix = pNamespacePrefix;
|
||||
namespaceURI = pNameSpaceURI;
|
||||
|
||||
validator = pValidator;
|
||||
}
|
||||
|
||||
public void startElement(String pNamespaceURI, String pLocalName,
|
||||
String pQualifiedName, Attributes pAttributes)
|
||||
throws SAXException {
|
||||
String namespacePrefix = !StringUtil.isEmpty(pNamespaceURI)
|
||||
? getNSPrefixFromURI(pNamespaceURI)
|
||||
: getNamespacePrefix(pQualifiedName);
|
||||
|
||||
String localName = !StringUtil.isEmpty(pLocalName)
|
||||
? pLocalName : getLocalName(pQualifiedName);
|
||||
/*
|
||||
if (namespacePrefix.equals(namespacePrefix)) {
|
||||
System.out.println("startElement:\nnamespaceURI=" + pNamespaceURI
|
||||
+ " namespacePrefix=" + namespacePrefix
|
||||
+ " localName=" + localName
|
||||
+ " qName=" + pQualifiedName
|
||||
+ " attributes=" + pAttributes);
|
||||
}
|
||||
*/
|
||||
if (localName.equals(includeTagName)) {
|
||||
// include
|
||||
//System.out.println("<" + namespacePrefix + ":"
|
||||
// + includeTagName + ">");
|
||||
if (inIncludeTag) {
|
||||
validator.reportError("Cannot nest " + namespacePrefix + ":"
|
||||
+ includeTagName);
|
||||
}
|
||||
inIncludeTag = true;
|
||||
}
|
||||
else if (localName.equals(paramTagName)) {
|
||||
// param
|
||||
//System.out.println("<" + namespacePrefix + ":"
|
||||
// + paramTagName + "/>");
|
||||
if (!inIncludeTag) {
|
||||
validator.reportError(this.namespacePrefix + ":"
|
||||
+ paramTagName
|
||||
+ " can only appear within "
|
||||
+ this.namespacePrefix + ":"
|
||||
+ includeTagName);
|
||||
}
|
||||
}
|
||||
else if (localName.equals(openParamTagName)) {
|
||||
// oparam
|
||||
//System.out.println("<" + namespacePrefix + ":"
|
||||
// + openParamTagName + ">");
|
||||
if (!inIncludeTag) {
|
||||
validator.reportError(this.namespacePrefix + ":"
|
||||
+ openParamTagName
|
||||
+ " can only appear within "
|
||||
+ this.namespacePrefix + ":"
|
||||
+ includeTagName);
|
||||
}
|
||||
inIncludeTag = false;
|
||||
}
|
||||
else {
|
||||
// Only jsp:text allowed inside include!
|
||||
if (inIncludeTag && !localName.equals("text")) {
|
||||
validator.reportError(namespacePrefix + ":" + localName
|
||||
+ " can not appear within "
|
||||
+ this.namespacePrefix + ":"
|
||||
+ includeTagName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String pNamespaceURI,
|
||||
String pLocalName,
|
||||
String pQualifiedName)
|
||||
throws SAXException {
|
||||
String namespacePrefix = !StringUtil.isEmpty(pNamespaceURI)
|
||||
? getNSPrefixFromURI(pNamespaceURI)
|
||||
: getNamespacePrefix(pQualifiedName);
|
||||
|
||||
String localName = !StringUtil.isEmpty(pLocalName)
|
||||
? pLocalName : getLocalName(pQualifiedName);
|
||||
/*
|
||||
if (namespacePrefix.equals(namespacePrefix)) {
|
||||
System.out.println("endElement:\nnamespaceURI=" + pNamespaceURI
|
||||
+ " namespacePrefix=" + namespacePrefix
|
||||
+ " localName=" + localName
|
||||
+ " qName=" + pQualifiedName);
|
||||
}
|
||||
*/
|
||||
if (namespacePrefix.equals(this.namespacePrefix)
|
||||
&& localName.equals(includeTagName)) {
|
||||
|
||||
//System.out.println("</" + namespacePrefix + ":"
|
||||
// + includeTagName + ">");
|
||||
|
||||
inIncludeTag = false;
|
||||
}
|
||||
else if (namespacePrefix.equals(this.namespacePrefix)
|
||||
&& localName.equals(openParamTagName)) {
|
||||
|
||||
//System.out.println("</" + namespacePrefix + ":"
|
||||
// + openParamTagName + ">");
|
||||
|
||||
inIncludeTag = true; // assuming no errors before this...
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stupid broken namespace-support "fix"..
|
||||
*/
|
||||
|
||||
private String getNSPrefixFromURI(String pNamespaceURI) {
|
||||
return (pNamespaceURI.equals(namespaceURI)
|
||||
? namespacePrefix : "");
|
||||
}
|
||||
|
||||
private String getNamespacePrefix(String pQualifiedName) {
|
||||
return pQualifiedName.substring(0, pQualifiedName.indexOf(':'));
|
||||
}
|
||||
|
||||
private String getLocalName(String pQualifiedName) {
|
||||
return pQualifiedName.substring(pQualifiedName.indexOf(':') + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: NestingValidator.java,v $
|
||||
* Revision 1.4 2003/08/04 15:26:40 WMHAKUR
|
||||
* Code clean-up.
|
||||
*
|
||||
* Revision 1.3 2002/11/18 14:12:43 WMHAKUR
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
||||
* Fixed package error.
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.servlet.jsp.tagext.PageData;
|
||||
import javax.servlet.jsp.tagext.TagLibraryValidator;
|
||||
import javax.servlet.jsp.tagext.ValidationMessage;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A validator that verifies that tags follow
|
||||
* proper nesting order.
|
||||
* <P>
|
||||
* Based on NestingValidator.java,
|
||||
* taken from More Servlets and JavaServer Pages
|
||||
* from Prentice Hall and Sun Microsystems Press,
|
||||
* http://www.moreservlets.com/.
|
||||
* © 2002 Marty Hall; may be freely used or adapted.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*
|
||||
*/
|
||||
public class NestingValidator extends TagLibraryValidator {
|
||||
|
||||
private List<ValidationMessage> errors = new ArrayList<ValidationMessage>();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public ValidationMessage[] validate(String pPrefix, String pURI, PageData pPage) {
|
||||
|
||||
//System.out.println("Validating " + pPrefix + " (" + pURI + ") for "
|
||||
// + pPage + ".");
|
||||
|
||||
// Pass the parser factory in on the command line with
|
||||
// -D to override the use of the Apache parser.
|
||||
|
||||
DefaultHandler handler = new NestingHandler(pPrefix, pURI, this);
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
|
||||
try {
|
||||
// FileUtil.copy(pPage.getInputStream(), System.out);
|
||||
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
InputSource source =
|
||||
new InputSource(pPage.getInputStream());
|
||||
|
||||
// Parse, handler will use callback to report errors
|
||||
parser.parse(source, handler);
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
String errorMessage = e.getMessage();
|
||||
|
||||
reportError(errorMessage);
|
||||
}
|
||||
|
||||
// Return any errors and exceptions, empty array means okay
|
||||
return errors.toArray(new ValidationMessage[errors.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for the handler to report errors
|
||||
*/
|
||||
public void reportError(String pMessage) {
|
||||
// The first argument to the ValidationMessage
|
||||
// constructor can be a tag ID. Since tag IDs
|
||||
// are not universally supported, use null for
|
||||
// portability. The important part is the second
|
||||
// argument: the error message.
|
||||
errors.add(new ValidationMessage(null, pMessage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: OparamTag.java,v $
|
||||
* Revision 1.4 2003/10/06 14:25:53 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.3 2002/11/18 14:12:43 WMHAKUR
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.2 2002/11/07 12:20:14 WMHAKUR
|
||||
* Updated to reflect changes in com.twelvemonkeys.util.*Util
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||
|
||||
import com.twelvemonkeys.io.FileUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.servlet.jsp.droplet.Oparam;
|
||||
import com.twelvemonkeys.servlet.jsp.taglib.BodyReaderTag;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Open parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
||||
*
|
||||
* @author Thomas Purcell (CSC Australia)
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: jsp/droplet/taglib/OparamTag.java#1 $
|
||||
*/
|
||||
public class OparamTag extends BodyReaderTag {
|
||||
|
||||
protected final static String COUNTER = "com.twelvemonkeys.servlet.jsp.taglib.OparamTag.counter";
|
||||
|
||||
private File subpage = null;
|
||||
|
||||
/**
|
||||
* This is the name of the parameter to be inserted into the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
private String parameterName = null;
|
||||
|
||||
private String language = null;
|
||||
|
||||
private String prefix = null;
|
||||
|
||||
/**
|
||||
* This method allows the JSP page to set the name for the parameter by
|
||||
* using the {@code name} tag attribute.
|
||||
*
|
||||
* @param pName The name for the parameter to insert into the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
public void setName(String pName) {
|
||||
parameterName = pName;
|
||||
}
|
||||
|
||||
public void setLanguage(String pLanguage) {
|
||||
//System.out.println("setLanguage:"+pLanguage);
|
||||
language = pLanguage;
|
||||
}
|
||||
|
||||
public void setPrefix(String pPrefix) {
|
||||
//System.out.println("setPrefix:"+pPrefix);
|
||||
prefix = pPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @throws JspException
|
||||
*/
|
||||
public int doStartTag() throws JspException {
|
||||
//checkEnclosedInIncludeTag(); // Moved to TagLibValidator
|
||||
|
||||
// Get request
|
||||
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
|
||||
|
||||
// Get filename
|
||||
subpage = createFileNameFromRequest(request);
|
||||
|
||||
// Get include tag, and add to parameters
|
||||
IncludeTag includeTag = (IncludeTag) getParent();
|
||||
includeTag.addParameter(parameterName, new Oparam(subpage.getName()));
|
||||
|
||||
// if ! subpage.exist || jsp newer than subpage, write new
|
||||
File jsp = new File(pageContext.getServletContext().getRealPath(request.getServletPath()));
|
||||
|
||||
if (!subpage.exists() || jsp.lastModified() > subpage.lastModified()) {
|
||||
return EVAL_BODY_BUFFERED;
|
||||
}
|
||||
|
||||
// No need to evaluate body again!
|
||||
return SKIP_BODY;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the method responsible for actually testing that the tag
|
||||
* implemented by this class is enclosed within an {@code IncludeTag}.
|
||||
*
|
||||
* @exception JspException
|
||||
*/
|
||||
/*
|
||||
protected void checkEnclosedInIncludeTag() throws JspException {
|
||||
Tag parentTag = getParent();
|
||||
|
||||
if ((parentTag != null) && (parentTag instanceof IncludeTag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = "A class that extends EnclosedIncludeBodyReaderTag " +
|
||||
"is not enclosed within an IncludeTag.";
|
||||
log(msg);
|
||||
throw new JspException(msg);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* life cycle just in case a JspException was thrown during the tag
|
||||
* execution.
|
||||
*/
|
||||
protected void clearServiceState() {
|
||||
parameterName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* request scope session. If any problems occur while loading the body
|
||||
* into the session scope then a {@code JspException} will be thrown.
|
||||
*
|
||||
* @param pContent The body of the tag as a String.
|
||||
* @throws JspException
|
||||
*/
|
||||
protected void processBody(String pContent) throws JspException {
|
||||
// Okay, we have the content, we need to write it to disk somewhere
|
||||
String content = pContent;
|
||||
|
||||
if (!StringUtil.isEmpty(language)) {
|
||||
content = "<%@page language=\"" + language + "\" %>" + content;
|
||||
}
|
||||
|
||||
if (!StringUtil.isEmpty(prefix)) {
|
||||
content = "<%@taglib uri=\"/twelvemonkeys-common\" prefix=\"" + prefix + "\" %>" + content;
|
||||
}
|
||||
|
||||
// Write the content of the oparam to disk
|
||||
try {
|
||||
log("Processing subpage " + subpage.getPath());
|
||||
FileUtil.write(subpage, content.getBytes());
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new JspException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a unique filename for each (nested) oparam */
|
||||
private File createFileNameFromRequest(HttpServletRequest pRequest) {
|
||||
//System.out.println("ServletPath" + pRequest.getServletPath());
|
||||
String path = pRequest.getServletPath();
|
||||
|
||||
// Find last '/'
|
||||
int splitIndex = path.lastIndexOf("/");
|
||||
|
||||
// Split -> path + name
|
||||
String name = path.substring(splitIndex + 1);
|
||||
path = path.substring(0, splitIndex);
|
||||
|
||||
// Replace special chars in name with '_'
|
||||
name = name.replace('.', '_');
|
||||
String param = parameterName.replace('.', '_');
|
||||
param = param.replace('/', '_');
|
||||
param = param.replace('\\', '_');
|
||||
param = param.replace(':', '_');
|
||||
|
||||
// tempfile = realPath(path) + name + "_oparam_" + number + ".jsp"
|
||||
int count = getOparamCountFromRequest(pRequest);
|
||||
|
||||
// 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");
|
||||
//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");
|
||||
}
|
||||
|
||||
/** Gets the current oparam count for this request */
|
||||
private int getOparamCountFromRequest(HttpServletRequest pRequest) {
|
||||
// Use request.attribute for incrementing oparam counter
|
||||
Integer count = (Integer) pRequest.getAttribute(COUNTER);
|
||||
if (count == null) {
|
||||
count = new Integer(0);
|
||||
}
|
||||
else {
|
||||
count = new Integer(count.intValue() + 1);
|
||||
}
|
||||
|
||||
// ... and set it back
|
||||
pRequest.setAttribute(COUNTER, count);
|
||||
|
||||
return count.intValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: ParamTag.java,v $
|
||||
* Revision 1.2 2003/10/06 14:26:00 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:03:09 WMHAKUR
|
||||
* Moved to 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.taglib.ExTagSupport;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
/**
|
||||
* Parameter tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
||||
*
|
||||
* @author Thomas Purcell (CSC Australia)
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*
|
||||
*/
|
||||
public class ParamTag extends ExTagSupport {
|
||||
|
||||
/**
|
||||
* This is the name of the parameter to be inserted into the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
private String parameterName;
|
||||
|
||||
/**
|
||||
* This is the value for the parameter to be inserted into the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
private Object parameterValue;
|
||||
|
||||
/**
|
||||
* This method allows the JSP page to set the name for the parameter by
|
||||
* using the {@code name} tag attribute.
|
||||
*
|
||||
* @param pName The name for the parameter to insert into the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
public void setName(String pName) {
|
||||
parameterName = pName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the JSP page to set the value for hte parameter by
|
||||
* using the {@code value} tag attribute.
|
||||
*
|
||||
* @param pValue The value for the parameter to insert into the <code>
|
||||
* PageContext.REQUEST_SCOPE</page> scope.
|
||||
*/
|
||||
public void setValue(String pValue) {
|
||||
parameterValue = new Param(pValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return If this tag is enclosed within an {@code IncludeTag}, then
|
||||
* the default return value from this method is the {@code
|
||||
* TagSupport.SKIP_BODY} value.
|
||||
* @exception JspException
|
||||
*/
|
||||
public int doStartTag() throws JspException {
|
||||
//checkEnclosedInIncludeTag();
|
||||
|
||||
addParameter();
|
||||
|
||||
return SKIP_BODY;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the method responsible for actually testing that the tag
|
||||
* implemented by this class is enclosed within an {@code IncludeTag}.
|
||||
*
|
||||
* @exception JspException
|
||||
*/
|
||||
/*
|
||||
protected void checkEnclosedInIncludeTag() throws JspException {
|
||||
Tag parentTag = getParent();
|
||||
|
||||
if ((parentTag != null) && (parentTag instanceof IncludeTag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = "A class that extends EnclosedIncludeBodyReaderTag " +
|
||||
"is not enclosed within an IncludeTag.";
|
||||
log(msg);
|
||||
throw new JspException(msg);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* This method adds the parameter whose name and value were passed to this
|
||||
* object via the tag attributes to the parent {@code Include} tag.
|
||||
*/
|
||||
private void addParameter() {
|
||||
IncludeTag includeTag = (IncludeTag) getParent();
|
||||
|
||||
includeTag.addParameter(parameterName, parameterValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* life cycle just in case a JspException was thrown during the tag
|
||||
* execution.
|
||||
*/
|
||||
protected void clearServiceState() {
|
||||
parameterName = null;
|
||||
parameterValue = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: ValueOfTEI.java,v $
|
||||
* Revision 1.3 2003/10/06 14:26:07 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.2 2002/10/18 14:28:07 WMHAKUR
|
||||
* Fixed package error.
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:03:52 WMHAKUR
|
||||
* Moved to com.twelvemonkeys.servlet.jsp.droplet.taglib
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||
|
||||
import javax.servlet.jsp.tagext.TagData;
|
||||
import javax.servlet.jsp.tagext.TagExtraInfo;
|
||||
|
||||
/**
|
||||
* TagExtraInfo for ValueOf.
|
||||
* @todo More meaningful response to the user.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*
|
||||
*/
|
||||
|
||||
public class ValueOfTEI extends TagExtraInfo {
|
||||
|
||||
public boolean isValid(TagData pTagData) {
|
||||
Object nameAttr = pTagData.getAttribute("name");
|
||||
Object paramAttr = pTagData.getAttribute("param");
|
||||
|
||||
if ((nameAttr != null && paramAttr == null) || (nameAttr == null && paramAttr != null)) {
|
||||
return true; // Exactly one of name or param set
|
||||
}
|
||||
|
||||
// Either both or none,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: ValueOfTag.java,v $
|
||||
* Revision 1.2 2003/10/06 14:26:14 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.1 2002/10/18 14:03:52 WMHAKUR
|
||||
* Moved to 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.taglib.ExTagSupport;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* ValueOf tag that emulates ATG Dynamo JHTML behaviour for JSP.
|
||||
*
|
||||
* @author Thomas Purcell (CSC Australia)
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
*
|
||||
* @version $Revision: #1 $, ($Date: 2008/05/05 $)
|
||||
*/
|
||||
public class ValueOfTag extends ExTagSupport {
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* attribute.
|
||||
*/
|
||||
private String parameterName;
|
||||
|
||||
/**
|
||||
* This is the value of the parameter read from the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope. If the parameter doesn't exist,
|
||||
* then this will be null.
|
||||
*/
|
||||
private Object parameterValue;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*
|
||||
* @param pName The name of the parameter to be read from the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
public void setName(String pName) {
|
||||
parameterName = pName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* PageContext.REQUEST_SCOPE} scope. This is just a synonym for
|
||||
* setName, to be more like ATG Dynamo.
|
||||
*
|
||||
* @param pName The name of the parameter to be read from the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope.
|
||||
*/
|
||||
public void setParam(String pName) {
|
||||
parameterName = pName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method looks in the session scope for the session-scoped attribute
|
||||
* 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
|
||||
* session-scoped attribute. If it fails to find the session-scoped
|
||||
* attribute, it displays the body for this tag.
|
||||
*
|
||||
* @return If the session-scoped attribute is found, then this method will
|
||||
* return {@code TagSupport.SKIP_BODY}, otherwise it will return
|
||||
* {@code TagSupport.EVAL_BODY_INCLUDE}.
|
||||
* @exception JspException
|
||||
*
|
||||
*/
|
||||
public int doStartTag() throws JspException {
|
||||
try {
|
||||
if (parameterExists()) {
|
||||
if (parameterValue instanceof JspFragment) {
|
||||
// OPARAM or PARAM
|
||||
((JspFragment) parameterValue).service(pageContext);
|
||||
/*
|
||||
log("Service subpage " + pageContext.getServletContext().getRealPath(((Oparam) parameterValue).getName()));
|
||||
|
||||
pageContext.include(((Oparam) parameterValue).getName());
|
||||
*/
|
||||
}
|
||||
else {
|
||||
// Normal JSP parameter value
|
||||
JspWriter writer = pageContext.getOut();
|
||||
writer.print(parameterValue);
|
||||
}
|
||||
|
||||
return SKIP_BODY;
|
||||
}
|
||||
else {
|
||||
return EVAL_BODY_INCLUDE;
|
||||
}
|
||||
}
|
||||
catch (ServletException se) {
|
||||
log(se.getMessage(), se);
|
||||
throw new JspException(se);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
String msg = "Caught an IOException in ValueOfTag.doStartTag()\n"
|
||||
+ ioe.toString();
|
||||
log(msg, ioe);
|
||||
throw new JspException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to determine whether the parameter whose name is
|
||||
* stored in {@code mParameterName} exists within the {@code
|
||||
* PageContext.REQUEST_SCOPE} scope. If the parameter does exist,
|
||||
* then this method will return {@code true}, otherwise it returns
|
||||
* {@code false}. This method has the side affect of loading the
|
||||
* parameter value into {@code mParameterValue} if the parameter
|
||||
* does exist.
|
||||
*
|
||||
* @return {@code true} if the parameter whose name is in {@code
|
||||
* mParameterName} exists in the {@code PageContext.REQUEST_SCOPE
|
||||
* } scope, {@code false} otherwise.
|
||||
*/
|
||||
private boolean parameterExists() {
|
||||
parameterValue = pageContext.getAttribute(parameterName, PageContext.REQUEST_SCOPE);
|
||||
|
||||
// -- Harald K 20020726
|
||||
if (parameterValue == null) {
|
||||
parameterValue = pageContext.getRequest().getParameter(parameterName);
|
||||
}
|
||||
|
||||
return (parameterValue != null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dynamo Droplet-like functionality for JSP.
|
||||
*
|
||||
* This package is early beta, not for commercial use! :-)
|
||||
* Read: The interfaces and classes in this package (and subpackages) will be
|
||||
* developed and modified for a while.
|
||||
*
|
||||
* TODO: Insert taglib-descriptor here?
|
||||
*/
|
||||
package com.twelvemonkeys.servlet.jsp.droplet.taglib;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* JSP support.
|
||||
*/
|
||||
package com.twelvemonkeys.servlet.jsp;
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Thomas Purcell (CSC Australia)
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public abstract class BodyReaderTag extends ExBodyTagSupport {
|
||||
/**
|
||||
* 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
|
||||
* method takes the content as a string and passes it to the {@code
|
||||
* processBody} method.
|
||||
*
|
||||
* @return This method returns the {@code BodyTagSupport.SKIP_BODY}
|
||||
* constant. This means that the body of the tag will only be
|
||||
* processed the one time.
|
||||
* @exception JspException
|
||||
*/
|
||||
public int doAfterBody() throws JspException {
|
||||
processBody(bodyContent.getString());
|
||||
return SKIP_BODY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the tag will have been interpreted to a String by the JSP engine before
|
||||
* this method is called.
|
||||
*
|
||||
* @param pContent The body for the custom tag converted to a String.
|
||||
* @exception JspException
|
||||
*/
|
||||
protected abstract void processBody(String pContent) throws JspException;
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: CSVToTableTag.java,v $
|
||||
* Revision 1.3 2003/10/06 14:24:50 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.2 2002/11/26 17:33:49 WMHAKUR
|
||||
* Added documentation & removed System.out.println()s.
|
||||
*
|
||||
* Revision 1.1 2002/11/19 10:50:10 WMHAKUR
|
||||
* Renamed from CSVToTable, to follow naming conventions.
|
||||
*
|
||||
* Revision 1.1 2002/11/18 22:11:16 WMHAKUR
|
||||
* Tag to convert CSV to HTML table.
|
||||
* Can be further transformed, using XSLT.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import javax.servlet.jsp.tagext.BodyContent;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Creates a table from a string of "comma-separated values" (CSV).
|
||||
* The delimiter character can be any character (or combination of characters).
|
||||
* The default delimiter is TAB ({@code \t}).
|
||||
*
|
||||
* <P/>
|
||||
* <HR/>
|
||||
* <P/>
|
||||
*
|
||||
* The input may look like this:
|
||||
* <PRE>
|
||||
* <c:totable firstRowIsHeader="true" delimiter=";">
|
||||
* header A;header B
|
||||
* data 1A; data 1B
|
||||
* data 2A; data 2B
|
||||
* </c:totable>
|
||||
* </PRE>
|
||||
*
|
||||
* The output (source) will look like this:
|
||||
* <PRE>
|
||||
* <TABLE>
|
||||
* <TR>
|
||||
* <TH>header A</TH><TH>header B</TH>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>data 1A</TD><TD>data 1B</TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>data 2A</TD><TD>data 2B</TD>
|
||||
* </TR>
|
||||
* </TABLE>
|
||||
* </PRE>
|
||||
* You wil probably want to use XSLT to make the final output look nicer. :-)
|
||||
*
|
||||
* @see StringTokenizer
|
||||
* @see <A href="http://www.w3.org/TR/xslt">XSLT spec</A>
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
*
|
||||
* @version $Id: jsp/taglib/CSVToTableTag.java#1 $
|
||||
*/
|
||||
public class CSVToTableTag extends ExBodyTagSupport {
|
||||
public final static String TAB = "\t";
|
||||
|
||||
protected String delimiter = null;
|
||||
protected boolean firstRowIsHeader = false;
|
||||
protected boolean firstColIsHeader = false;
|
||||
|
||||
public void setDelimiter(String pDelimiter) {
|
||||
delimiter = pDelimiter;
|
||||
}
|
||||
|
||||
public String getDelimiter() {
|
||||
return delimiter != null ? delimiter : TAB;
|
||||
}
|
||||
|
||||
public void setFirstRowIsHeader(String pBoolean) {
|
||||
firstRowIsHeader = Boolean.valueOf(pBoolean);
|
||||
}
|
||||
|
||||
public void setFirstColIsHeader(String pBoolean) {
|
||||
firstColIsHeader = Boolean.valueOf(pBoolean);
|
||||
}
|
||||
|
||||
|
||||
public int doEndTag() throws JspException {
|
||||
BodyContent content = getBodyContent();
|
||||
|
||||
try {
|
||||
Table table =
|
||||
Table.parseContent(content.getReader(), getDelimiter());
|
||||
|
||||
JspWriter out = pageContext.getOut();
|
||||
|
||||
//System.out.println("CSVToTable: " + table.getRows() + " rows, "
|
||||
// + table.getCols() + " cols.");
|
||||
|
||||
if (table.getRows() > 0) {
|
||||
out.println("<TABLE>");
|
||||
// Loop over rows
|
||||
for (int row = 0; row < table.getRows(); row++) {
|
||||
out.println("<TR>");
|
||||
|
||||
// Loop over cells in each row
|
||||
for (int col = 0; col < table.getCols(); col++) {
|
||||
// Test if we are using headers, else normal cell
|
||||
if (firstRowIsHeader && row == 0 || firstColIsHeader && col == 0) {
|
||||
out.println("<TH>" + table.get(row, col) + " </TH>");
|
||||
}
|
||||
else {
|
||||
out.println("<TD>" + table.get(row, col) + " </TD>");
|
||||
}
|
||||
}
|
||||
|
||||
out.println("</TR>");
|
||||
|
||||
}
|
||||
out.println("</TABLE>");
|
||||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new JspException(ioe);
|
||||
}
|
||||
|
||||
return super.doEndTag();
|
||||
}
|
||||
|
||||
static class Table {
|
||||
List rows = null;
|
||||
int cols = 0;
|
||||
|
||||
private Table(List pRows, int pCols) {
|
||||
rows = pRows;
|
||||
cols = pCols;
|
||||
}
|
||||
|
||||
int getRows() {
|
||||
return rows != null ? rows.size() : 0;
|
||||
}
|
||||
|
||||
int getCols() {
|
||||
return cols;
|
||||
}
|
||||
|
||||
List getTableRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
List getTableRow(int pRow) {
|
||||
return rows != null
|
||||
? (List) rows.get(pRow)
|
||||
: Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
String get(int pRow, int pCol) {
|
||||
List row = getTableRow(pRow);
|
||||
// Rows may contain unequal number of cols
|
||||
return (row.size() > pCol) ? (String) row.get(pCol) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a BodyContent to a table.
|
||||
*
|
||||
*/
|
||||
static Table parseContent(Reader pContent, String pDelim) throws IOException {
|
||||
List<List<String>> tableRows = new ArrayList<List<String>>();
|
||||
int tdsPerTR = 0;
|
||||
|
||||
// Loop through TRs
|
||||
BufferedReader reader = new BufferedReader(pContent);
|
||||
String tr;
|
||||
while ((tr = reader.readLine()) != null) {
|
||||
// Discard blank lines
|
||||
if (tr.trim().length() <= 0 && tr.indexOf(pDelim) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//System.out.println("CSVToTable: read LINE=\"" + tr + "\"");
|
||||
|
||||
List<String> tableDatas = new ArrayList<String>();
|
||||
StringTokenizer tableRow = new StringTokenizer(tr, pDelim,
|
||||
true);
|
||||
|
||||
boolean lastWasDelim = false;
|
||||
while (tableRow.hasMoreTokens()) {
|
||||
String td = tableRow.nextToken();
|
||||
|
||||
//System.out.println("CSVToTable: read data=\"" + td + "\"");
|
||||
|
||||
// Test if we have empty TD
|
||||
if (td.equals(pDelim)) {
|
||||
if (lastWasDelim) {
|
||||
// Add empty TD
|
||||
tableDatas.add("");
|
||||
}
|
||||
|
||||
// We just read a delimitter
|
||||
lastWasDelim = true;
|
||||
}
|
||||
else {
|
||||
// No tab, normal data
|
||||
lastWasDelim = false;
|
||||
|
||||
// Add normal TD
|
||||
tableDatas.add(td);
|
||||
}
|
||||
} // end while (tableRow.hasNext())
|
||||
|
||||
// Store max TD count
|
||||
if (tableDatas.size() > tdsPerTR) {
|
||||
tdsPerTR = tableDatas.size();
|
||||
}
|
||||
|
||||
// Add a table row
|
||||
tableRows.add(tableDatas);
|
||||
}
|
||||
|
||||
// Return TABLE
|
||||
return new Table(tableRows, tdsPerTR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: ExBodyTagSupport.java,v $
|
||||
* Revision 1.3 2003/10/06 14:24:57 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.2 2002/11/18 22:10:27 WMHAKUR
|
||||
* *** empty log message ***
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import javax.servlet.jsp.tagext.BodyTagSupport;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Thomas Purcell (CSC Australia)
|
||||
* @author Harald Kuhr
|
||||
*
|
||||
* @version $Id: jsp/taglib/ExBodyTagSupport.java#1 $
|
||||
*/
|
||||
|
||||
public class ExBodyTagSupport extends BodyTagSupport implements ExTag {
|
||||
/**
|
||||
* writeHtml ensures that the text being outputted appears as it was
|
||||
* entered. This prevents users from hacking the system by entering
|
||||
* html or jsp code into an entry form where that value will be displayed
|
||||
* later in the site.
|
||||
*
|
||||
* @param pOut The JspWriter to write the output to.
|
||||
* @param pHtml The original html to filter and output to the user.
|
||||
* @throws IOException If the user clicks Stop in the browser, or their
|
||||
* browser crashes, then the JspWriter will throw an IOException when
|
||||
* the jsp tries to write to it.
|
||||
*/
|
||||
|
||||
public void writeHtml(JspWriter pOut, String pHtml) throws IOException {
|
||||
StringTokenizer parser = new StringTokenizer(pHtml, "<>&", true);
|
||||
|
||||
while (parser.hasMoreTokens()) {
|
||||
String token = parser.nextToken();
|
||||
|
||||
if (token.equals("<")) {
|
||||
pOut.print("<");
|
||||
}
|
||||
else if (token.equals(">")) {
|
||||
pOut.print(">");
|
||||
}
|
||||
else if (token.equals("&")) {
|
||||
pOut.print("&");
|
||||
}
|
||||
else {
|
||||
pOut.print(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message to the servlet context.
|
||||
*
|
||||
* @param pMsg The error message to log.
|
||||
*/
|
||||
|
||||
public void log(String pMsg) {
|
||||
getServletContext().log(pMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message to the servlet context and include the exception that is
|
||||
* passed in as the second parameter.
|
||||
*
|
||||
* @param pMsg The error message to log.
|
||||
* @param pException The exception that caused this error message to be
|
||||
* logged.
|
||||
*/
|
||||
|
||||
public void log(String pMsg, Throwable pException) {
|
||||
getServletContext().log(pMsg, pException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ServletContext object associated with the current
|
||||
* PageContext object.
|
||||
*
|
||||
* @return The ServletContext object associated with the current
|
||||
* PageContext object.
|
||||
*/
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return pageContext.getServletContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* called in the {@code clearServiceState()} method call.
|
||||
*
|
||||
* @exception JspException
|
||||
*/
|
||||
|
||||
public int doEndTag() throws JspException {
|
||||
clearServiceState();
|
||||
return super.doEndTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a tag's role in the current JSP page is finished. After
|
||||
* the {@code clearProperties()} method is called, the custom tag
|
||||
* should be in an identical state as when it was first created. The
|
||||
* {@code clearServiceState()} method is called here just in case an
|
||||
* exception was thrown in the custom tag. If an exception was thrown,
|
||||
* then the {@code doEndTag()} method will not have been called and
|
||||
* the tag might not have been cleaned up properly.
|
||||
*/
|
||||
|
||||
public void release() {
|
||||
clearServiceState();
|
||||
|
||||
clearProperties();
|
||||
super.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation for the {@code clearProperties()}. 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
|
||||
* super.clearProperties()}. So, if the class extends a different
|
||||
* 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
|
||||
* tag has finished for the current page and should be returned to it's
|
||||
* initial state.
|
||||
*/
|
||||
|
||||
protected void clearProperties() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation for the {@code clearServiceState()}.
|
||||
* 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
|
||||
* super.clearServiceState()}. So, if the class extends a different
|
||||
* 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
|
||||
* within the page, but may be called upon again in this same JSP page.
|
||||
*/
|
||||
|
||||
protected void clearServiceState() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initialisation parameter from the {@code
|
||||
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
||||
* parameters are defined in the {@code web.xml} configuration file.
|
||||
*
|
||||
* @param pName The name of the initialisation parameter to return the
|
||||
* value for.
|
||||
* @return The value for the parameter whose name was passed in as a
|
||||
* parameter. If the parameter does not exist, then {@code null}
|
||||
* will be returned.
|
||||
*/
|
||||
|
||||
public String getInitParameter(String pName) {
|
||||
return getInitParameter(pName, PageContext.APPLICATION_SCOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Enumeration containing all the names for all the
|
||||
* initialisation parametes defined in the {@code
|
||||
* PageContext.APPLICATION_SCOPE} scope.
|
||||
*
|
||||
* @return An {@code Enumeration} containing all the names for all the
|
||||
* initialisation parameters.
|
||||
*/
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
return getInitParameterNames(PageContext.APPLICATION_SCOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initialisation parameter from the scope specified with the
|
||||
* name specified.
|
||||
*
|
||||
* @param pName The name of the initialisation parameter to return the
|
||||
* value for.
|
||||
* @param pScope The scope to search for the initialisation parameter
|
||||
* within.
|
||||
* @return The value of the parameter found. If no parameter with the
|
||||
* name specified is found in the scope specified, then {@code null
|
||||
* } is returned.
|
||||
*/
|
||||
|
||||
public String getInitParameter(String pName, int pScope) {
|
||||
switch (pScope) {
|
||||
case PageContext.PAGE_SCOPE:
|
||||
return getServletConfig().getInitParameter(pName);
|
||||
case PageContext.APPLICATION_SCOPE:
|
||||
return getServletContext().getInitParameter(pName);
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal scope.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an enumeration containing all the parameters defined in the
|
||||
* scope specified by the parameter.
|
||||
*
|
||||
* @param pScope The scope to return the names of all the parameters
|
||||
* defined within.
|
||||
* @return An {@code Enumeration} containing all the names for all the
|
||||
* parameters defined in the scope passed in as a parameter.
|
||||
*/
|
||||
|
||||
public Enumeration getInitParameterNames(int pScope) {
|
||||
switch (pScope) {
|
||||
case PageContext.PAGE_SCOPE:
|
||||
return getServletConfig().getInitParameterNames();
|
||||
case PageContext.APPLICATION_SCOPE:
|
||||
return getServletContext().getInitParameterNames();
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal scope");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the servlet config associated with the current JSP page request.
|
||||
*
|
||||
* @return The {@code ServletConfig} associated with the current
|
||||
* request.
|
||||
*/
|
||||
|
||||
public ServletConfig getServletConfig() {
|
||||
return pageContext.getServletConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context path associated with the current JSP page request.
|
||||
* If the request is not a HttpServletRequest, this method will
|
||||
* return "/".
|
||||
*
|
||||
* @return a path relative to the current context's root, or
|
||||
* {@code "/"} if this is not a HTTP request.
|
||||
*/
|
||||
|
||||
public String getContextPath() {
|
||||
ServletRequest request = pageContext.getRequest();
|
||||
if (request instanceof HttpServletRequest) {
|
||||
return ((HttpServletRequest) request).getContextPath();
|
||||
}
|
||||
return "/";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource associated with the given relative path for the
|
||||
* current JSP page request.
|
||||
* The path may be absolute, or relative to the current context root.
|
||||
*
|
||||
* @param pPath the path
|
||||
*
|
||||
* @return a path relative to the current context root
|
||||
*/
|
||||
|
||||
public InputStream getResourceAsStream(String pPath) {
|
||||
// throws MalformedURLException {
|
||||
String path = pPath;
|
||||
|
||||
if (pPath != null && !pPath.startsWith("/")) {
|
||||
path = getContextPath() + pPath;
|
||||
}
|
||||
|
||||
return pageContext.getServletContext().getResourceAsStream(path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: ExTag.java,v $
|
||||
* Revision 1.2 2003/10/06 14:25:05 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.1 2002/11/18 22:10:27 WMHAKUR
|
||||
* *** empty log message ***
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* This interface contains a lot of helper methods for simplifying common
|
||||
* taglib related tasks.
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
*
|
||||
* @version $Id: jsp/taglib/ExTag.java#1 $
|
||||
*/
|
||||
|
||||
public interface ExTag extends Tag {
|
||||
|
||||
/**
|
||||
* writeHtml ensures that the text being outputted appears as it was
|
||||
* entered. This prevents users from hacking the system by entering
|
||||
* html or jsp code into an entry form where that value will be displayed
|
||||
* later in the site.
|
||||
*
|
||||
* @param pOut The JspWriter to write the output to.
|
||||
* @param pHtml The original html to filter and output to the user.
|
||||
* @throws IOException If the user clicks Stop in the browser, or their
|
||||
* browser crashes, then the JspWriter will throw an IOException when
|
||||
* the jsp tries to write to it.
|
||||
*/
|
||||
|
||||
public void writeHtml(JspWriter pOut, String pHtml) throws IOException;
|
||||
|
||||
/**
|
||||
* Log a message to the servlet context.
|
||||
*
|
||||
* @param pMsg The error message to log.
|
||||
*/
|
||||
|
||||
public void log(String pMsg);
|
||||
|
||||
/**
|
||||
* Logs a message to the servlet context and include the exception that is
|
||||
* passed in as the second parameter.
|
||||
*
|
||||
* @param pMsg The error message to log.
|
||||
* @param pException The exception that caused this error message to be
|
||||
* logged.
|
||||
*/
|
||||
|
||||
public void log(String pMsg, Throwable pException);
|
||||
|
||||
/**
|
||||
* Retrieves the ServletContext object associated with the current
|
||||
* PageContext object.
|
||||
*
|
||||
* @return The ServletContext object associated with the current
|
||||
* PageContext object.
|
||||
*/
|
||||
|
||||
public ServletContext getServletContext();
|
||||
|
||||
/**
|
||||
* Returns the initialisation parameter from the {@code
|
||||
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
||||
* parameters are defined in the {@code web.xml} configuration file.
|
||||
*
|
||||
* @param pName The name of the initialisation parameter to return the
|
||||
* value for.
|
||||
* @return The value for the parameter whose name was passed in as a
|
||||
* parameter. If the parameter does not exist, then {@code null}
|
||||
* will be returned.
|
||||
*/
|
||||
|
||||
public String getInitParameter(String pName);
|
||||
|
||||
/**
|
||||
* Returns an Enumeration containing all the names for all the
|
||||
* initialisation parametes defined in the {@code
|
||||
* PageContext.APPLICATION_SCOPE} scope.
|
||||
*
|
||||
* @return An {@code Enumeration} containing all the names for all the
|
||||
* initialisation parameters.
|
||||
*/
|
||||
|
||||
public Enumeration getInitParameterNames();
|
||||
|
||||
/**
|
||||
* Returns the initialisation parameter from the scope specified with the
|
||||
* name specified.
|
||||
*
|
||||
* @param pName The name of the initialisation parameter to return the
|
||||
* value for.
|
||||
* @param pScope The scope to search for the initialisation parameter
|
||||
* within.
|
||||
* @return The value of the parameter found. If no parameter with the
|
||||
* name specified is found in the scope specified, then {@code null
|
||||
* } is returned.
|
||||
*/
|
||||
|
||||
public String getInitParameter(String pName, int pScope);
|
||||
|
||||
/**
|
||||
* Returns an enumeration containing all the parameters defined in the
|
||||
* scope specified by the parameter.
|
||||
*
|
||||
* @param pScope The scope to return the names of all the parameters
|
||||
* defined within.
|
||||
* @return An {@code Enumeration} containing all the names for all the
|
||||
* parameters defined in the scope passed in as a parameter.
|
||||
*/
|
||||
|
||||
public Enumeration getInitParameterNames(int pScope);
|
||||
|
||||
/**
|
||||
* Returns the servlet config associated with the current JSP page request.
|
||||
*
|
||||
* @return The {@code ServletConfig} associated with the current
|
||||
* request.
|
||||
*/
|
||||
|
||||
public ServletConfig getServletConfig();
|
||||
|
||||
/**
|
||||
* Gets the context path associated with the current JSP page request.
|
||||
*
|
||||
* @return a path relative to the current context's root.
|
||||
*/
|
||||
|
||||
public String getContextPath();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the resource associated with the given relative path for the
|
||||
* current JSP page request.
|
||||
* The path may be absolute, or relative to the current context root.
|
||||
*
|
||||
* @param pPath the path
|
||||
*
|
||||
* @return a path relative to the current context root
|
||||
*/
|
||||
|
||||
public InputStream getResourceAsStream(String pPath);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: ExTagSupport.java,v $
|
||||
* Revision 1.3 2003/10/06 14:25:11 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.2 2002/11/18 22:10:27 WMHAKUR
|
||||
* *** empty log message ***
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* tasks.
|
||||
*
|
||||
* @author Thomas Purcell (CSC Australia)
|
||||
* @author Harald Kuhr
|
||||
*
|
||||
* @version $Id: jsp/taglib/ExTagSupport.java#1 $
|
||||
*/
|
||||
|
||||
public class ExTagSupport extends TagSupport implements ExTag {
|
||||
/**
|
||||
* writeHtml ensures that the text being outputted appears as it was
|
||||
* entered. This prevents users from hacking the system by entering
|
||||
* html or jsp code into an entry form where that value will be displayed
|
||||
* later in the site.
|
||||
*
|
||||
* @param pOut The JspWriter to write the output to.
|
||||
* @param pHtml The original html to filter and output to the user.
|
||||
* @throws IOException If the user clicks Stop in the browser, or their
|
||||
* browser crashes, then the JspWriter will throw an IOException when
|
||||
* the jsp tries to write to it.
|
||||
*/
|
||||
|
||||
public void writeHtml(JspWriter pOut, String pHtml) throws IOException {
|
||||
StringTokenizer parser = new StringTokenizer(pHtml, "<>&", true);
|
||||
|
||||
while (parser.hasMoreTokens()) {
|
||||
String token = parser.nextToken();
|
||||
|
||||
if (token.equals("<")) {
|
||||
pOut.print("<");
|
||||
}
|
||||
else if (token.equals(">")) {
|
||||
pOut.print(">");
|
||||
}
|
||||
else if (token.equals("&")) {
|
||||
pOut.print("&");
|
||||
}
|
||||
else {
|
||||
pOut.print(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message to the servlet context.
|
||||
*
|
||||
* @param pMsg The error message to log.
|
||||
*/
|
||||
|
||||
public void log(String pMsg) {
|
||||
getServletContext().log(pMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message to the servlet context and include the exception that is
|
||||
* passed in as the second parameter.
|
||||
*
|
||||
* @param pMsg The error message to log.
|
||||
* @param pException The exception that caused this error message to be
|
||||
* logged.
|
||||
*/
|
||||
|
||||
public void log(String pMsg, Throwable pException) {
|
||||
getServletContext().log(pMsg, pException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ServletContext object associated with the current
|
||||
* PageContext object.
|
||||
*
|
||||
* @return The ServletContext object associated with the current
|
||||
* PageContext object.
|
||||
*/
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return pageContext.getServletContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* called in the {@code clearServiceState()} method call.
|
||||
*
|
||||
* @exception JspException
|
||||
*/
|
||||
|
||||
public int doEndTag() throws JspException {
|
||||
clearServiceState();
|
||||
return super.doEndTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a tag's role in the current JSP page is finished. After
|
||||
* the {@code clearProperties()} method is called, the custom tag
|
||||
* should be in an identical state as when it was first created. The
|
||||
* {@code clearServiceState()} method is called here just in case an
|
||||
* exception was thrown in the custom tag. If an exception was thrown,
|
||||
* then the {@code doEndTag()} method will not have been called and
|
||||
* the tag might not have been cleaned up properly.
|
||||
*/
|
||||
|
||||
public void release() {
|
||||
clearServiceState();
|
||||
|
||||
clearProperties();
|
||||
super.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation for the {@code clearProperties()}. 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
|
||||
* super.clearProperties()}. So, if the class extends a different
|
||||
* 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
|
||||
* tag has finished for the current page and should be returned to it's
|
||||
* initial state.
|
||||
*/
|
||||
|
||||
protected void clearProperties() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation for the {@code clearServiceState()}.
|
||||
* 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
|
||||
* super.clearServiceState()}. So, if the class extends a different
|
||||
* 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
|
||||
* within the page, but may be called upon again in this same JSP page.
|
||||
*/
|
||||
|
||||
protected void clearServiceState() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initialisation parameter from the {@code
|
||||
* PageContext.APPLICATION_SCOPE} scope. These initialisation
|
||||
* parameters are defined in the {@code web.xml} configuration file.
|
||||
*
|
||||
* @param pName The name of the initialisation parameter to return the
|
||||
* value for.
|
||||
* @return The value for the parameter whose name was passed in as a
|
||||
* parameter. If the parameter does not exist, then {@code null}
|
||||
* will be returned.
|
||||
*/
|
||||
|
||||
public String getInitParameter(String pName) {
|
||||
return getInitParameter(pName, PageContext.APPLICATION_SCOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Enumeration containing all the names for all the
|
||||
* initialisation parametes defined in the {@code
|
||||
* PageContext.APPLICATION_SCOPE} scope.
|
||||
*
|
||||
* @return An {@code Enumeration} containing all the names for all the
|
||||
* initialisation parameters.
|
||||
*/
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
return getInitParameterNames(PageContext.APPLICATION_SCOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initialisation parameter from the scope specified with the
|
||||
* name specified.
|
||||
*
|
||||
* @param pName The name of the initialisation parameter to return the
|
||||
* value for.
|
||||
* @param pScope The scope to search for the initialisation parameter
|
||||
* within.
|
||||
* @return The value of the parameter found. If no parameter with the
|
||||
* name specified is found in the scope specified, then {@code null
|
||||
* } is returned.
|
||||
*/
|
||||
|
||||
public String getInitParameter(String pName, int pScope) {
|
||||
switch (pScope) {
|
||||
case PageContext.PAGE_SCOPE:
|
||||
return getServletConfig().getInitParameter(pName);
|
||||
case PageContext.APPLICATION_SCOPE:
|
||||
return getServletContext().getInitParameter(pName);
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal scope.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an enumeration containing all the parameters defined in the
|
||||
* scope specified by the parameter.
|
||||
*
|
||||
* @param pScope The scope to return the names of all the parameters
|
||||
* defined within.
|
||||
* @return An {@code Enumeration} containing all the names for all the
|
||||
* parameters defined in the scope passed in as a parameter.
|
||||
*/
|
||||
|
||||
public Enumeration getInitParameterNames(int pScope) {
|
||||
switch (pScope) {
|
||||
case PageContext.PAGE_SCOPE:
|
||||
return getServletConfig().getInitParameterNames();
|
||||
case PageContext.APPLICATION_SCOPE:
|
||||
return getServletContext().getInitParameterNames();
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal scope");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the servlet config associated with the current JSP page request.
|
||||
*
|
||||
* @return The {@code ServletConfig} associated with the current
|
||||
* request.
|
||||
*/
|
||||
|
||||
public ServletConfig getServletConfig() {
|
||||
return pageContext.getServletConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context path associated with the current JSP page request.
|
||||
* If the request is not a HttpServletRequest, this method will
|
||||
* return "/".
|
||||
*
|
||||
* @return a path relative to the current context's root, or
|
||||
* {@code "/"} if this is not a HTTP request.
|
||||
*/
|
||||
|
||||
public String getContextPath() {
|
||||
ServletRequest request = pageContext.getRequest();
|
||||
if (request instanceof HttpServletRequest) {
|
||||
return ((HttpServletRequest) request).getContextPath();
|
||||
}
|
||||
return "/";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource associated with the given relative path for the
|
||||
* current JSP page request.
|
||||
* The path may be absolute, or relative to the current context root.
|
||||
*
|
||||
* @param pPath the path
|
||||
*
|
||||
* @return a path relative to the current context root
|
||||
*/
|
||||
|
||||
public InputStream getResourceAsStream(String pPath) {
|
||||
//throws MalformedURLException {
|
||||
String path = pPath;
|
||||
|
||||
if (pPath != null && !pPath.startsWith("/")) {
|
||||
path = getContextPath() + pPath;
|
||||
}
|
||||
|
||||
return pageContext.getServletContext().getResourceAsStream(path);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
import javax.servlet.jsp.*;
|
||||
import javax.servlet.jsp.tagext.*;
|
||||
|
||||
/**
|
||||
* TagExtraInfo for LastModifiedTag
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
*
|
||||
* @version 1.1
|
||||
*/
|
||||
|
||||
public class LastModifiedTEI extends TagExtraInfo {
|
||||
public VariableInfo[] getVariableInfo(TagData pData) {
|
||||
return new VariableInfo[]{
|
||||
new VariableInfo("lastModified", "java.lang.String", true, VariableInfo.NESTED),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
import com.twelvemonkeys.util.convert.Converter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Prints the last modified
|
||||
*/
|
||||
|
||||
public class LastModifiedTag extends TagSupport {
|
||||
private String fileName = null;
|
||||
private String format = null;
|
||||
|
||||
public void setFile(String pFileName) {
|
||||
fileName = pFileName;
|
||||
}
|
||||
|
||||
public void setFormat(String pFormat) {
|
||||
format = pFormat;
|
||||
}
|
||||
|
||||
public int doStartTag() throws JspException {
|
||||
File file;
|
||||
|
||||
if (fileName != null) {
|
||||
file = new File(pageContext.getServletContext().getRealPath(fileName));
|
||||
}
|
||||
else {
|
||||
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
|
||||
|
||||
// Get the file containing the servlet
|
||||
file = new File(pageContext.getServletContext().getRealPath(request.getServletPath()));
|
||||
}
|
||||
|
||||
Date lastModified = new Date(file.lastModified());
|
||||
Converter conv = Converter.getInstance();
|
||||
|
||||
// Set the last modified value back
|
||||
pageContext.setAttribute("lastModified", conv.toString(lastModified, format));
|
||||
|
||||
return Tag.EVAL_BODY_INCLUDE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
/**
|
||||
* This tag truncates all consecutive whitespace in sequence inside its body,
|
||||
* 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).
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class TrimWhiteSpaceTag extends ExBodyTagSupport {
|
||||
|
||||
/**
|
||||
* doStartTag implementation, simply returns
|
||||
* {@code BodyTag.EVAL_BODY_BUFFERED}.
|
||||
*
|
||||
* @return {@code BodyTag.EVAL_BODY_BUFFERED}
|
||||
*/
|
||||
|
||||
public int doStartTag() throws JspException {
|
||||
return EVAL_BODY_BUFFERED;
|
||||
}
|
||||
|
||||
/**
|
||||
* doEndTag implementation, truncates all whitespace.
|
||||
*
|
||||
* @return {@code super.doEndTag()}
|
||||
*/
|
||||
|
||||
public int doEndTag() throws JspException {
|
||||
// Trim
|
||||
String trimmed = truncateWS(bodyContent.getString());
|
||||
try {
|
||||
// Print trimmed content
|
||||
//pageContext.getOut().print("<!--TWS-->\n");
|
||||
pageContext.getOut().print(trimmed);
|
||||
//pageContext.getOut().print("\n<!--/TWS-->");
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new JspException(ioe);
|
||||
}
|
||||
|
||||
return super.doEndTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates whitespace from the given string.
|
||||
*
|
||||
* @todo Candidate for StringUtil?
|
||||
*/
|
||||
|
||||
private static String truncateWS(String pStr) {
|
||||
char[] chars = pStr.toCharArray();
|
||||
|
||||
int count = 0;
|
||||
boolean lastWasWS = true; // Avoids leading WS
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
if (!Character.isWhitespace(chars[i])) {
|
||||
// if char is not WS, just store
|
||||
chars[count++] = chars[i];
|
||||
lastWasWS = false;
|
||||
}
|
||||
else {
|
||||
// else, if char is WS, store first, skip the rest
|
||||
if (!lastWasWS) {
|
||||
if (chars[i] == 0x0d) {
|
||||
chars[count++] = 0x0a; //Always new line
|
||||
}
|
||||
else {
|
||||
chars[count++] = chars[i];
|
||||
}
|
||||
}
|
||||
lastWasWS = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the trucated string
|
||||
return new String(chars, 0, count);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2002 TwelveMonkeys.
|
||||
* All rights reserved.
|
||||
*
|
||||
* $Log: XMLTransformTag.java,v $
|
||||
* Revision 1.2 2003/10/06 14:25:43 WMHAKUR
|
||||
* Code clean-up only.
|
||||
*
|
||||
* Revision 1.1 2002/11/19 10:50:41 WMHAKUR
|
||||
* *** empty log message ***
|
||||
*
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
import javax.servlet.jsp.*;
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.stream.*;
|
||||
|
||||
/**
|
||||
* This tag performs XSL Transformations (XSLT) on a given XML document or its
|
||||
* body content.
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
*
|
||||
* @version $Id: jsp/taglib/XMLTransformTag.java#1 $
|
||||
*/
|
||||
|
||||
public class XMLTransformTag extends ExBodyTagSupport {
|
||||
private String mDocumentURI = null;
|
||||
private String mStylesheetURI = null;
|
||||
|
||||
/**
|
||||
* Sets the document attribute for this tag.
|
||||
*/
|
||||
|
||||
public void setDocumentURI(String pDocumentURI) {
|
||||
mDocumentURI = pDocumentURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stylesheet attribute for this tag.
|
||||
*/
|
||||
|
||||
public void setStylesheetURI(String pStylesheetURI) {
|
||||
mStylesheetURI = pStylesheetURI;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* doStartTag implementation, that performs XML Transformation on the
|
||||
* given document, if any.
|
||||
* If the documentURI attribute is set, then the transformation is
|
||||
* performed on the document at that location, and
|
||||
* {@code Tag.SKIP_BODY} is returned.
|
||||
* Otherwise, this method simply returns
|
||||
* {@code BodyTag.EVAL_BODY_BUFFERED} and leaves the transformation to
|
||||
* the doEndTag.
|
||||
*
|
||||
* @return {@code Tag.SKIP_BODY} if {@code documentURI} is not
|
||||
* {@code null}, otherwise
|
||||
* {@code BodyTag.EVAL_BODY_BUFFERED}.
|
||||
*
|
||||
* @todo Is it really a good idea to allow "inline" XML in a JSP?
|
||||
*/
|
||||
|
||||
public int doStartTag() throws JspException {
|
||||
//log("XML: " + mDocumentURI + " XSL: " + mStylesheetURI);
|
||||
|
||||
if (mDocumentURI != null) {
|
||||
// If document given, transform and skip body...
|
||||
try {
|
||||
transform(getSource(mDocumentURI));
|
||||
}
|
||||
catch (MalformedURLException murle) {
|
||||
throw new JspException(murle.getMessage(), murle);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new JspException(ioe.getMessage(), ioe);
|
||||
}
|
||||
|
||||
return SKIP_BODY;
|
||||
}
|
||||
|
||||
// ...else process the body
|
||||
return EVAL_BODY_BUFFERED;
|
||||
}
|
||||
|
||||
/**
|
||||
* doEndTag implementation, that will perform XML Transformation on the
|
||||
* body content.
|
||||
*
|
||||
* @return super.doEndTag()
|
||||
*/
|
||||
|
||||
public int doEndTag() throws JspException {
|
||||
// Get body content (trim is CRUCIAL, as some XML parsers are picky...)
|
||||
String body = bodyContent.getString().trim();
|
||||
|
||||
// Do transformation
|
||||
transform(new StreamSource(new ByteArrayInputStream(body.getBytes())));
|
||||
|
||||
return super.doEndTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the transformation and writes the result to the JSP writer.
|
||||
*
|
||||
* @param in the source document to transform.
|
||||
*/
|
||||
|
||||
public void transform(Source pIn) throws JspException {
|
||||
try {
|
||||
// Create transformer
|
||||
Transformer transformer = TransformerFactory.newInstance()
|
||||
.newTransformer(getSource(mStylesheetURI));
|
||||
|
||||
// Store temporary output in a bytearray, as the transformer will
|
||||
// usually try to flush the stream (illegal operation from a custom
|
||||
// tag).
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
StreamResult out = new StreamResult(os);
|
||||
|
||||
// Perform the transformation
|
||||
transformer.transform(pIn, out);
|
||||
|
||||
// Write the result back to the JSP writer
|
||||
pageContext.getOut().print(os.toString());
|
||||
}
|
||||
catch (MalformedURLException murle) {
|
||||
throw new JspException(murle.getMessage(), murle);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new JspException(ioe.getMessage(), ioe);
|
||||
}
|
||||
catch (TransformerException te) {
|
||||
throw new JspException("XSLT Trandformation failed: " + te.getMessage(), te);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a StreamSource object, for the given URI
|
||||
*/
|
||||
|
||||
private StreamSource getSource(String pURI)
|
||||
throws IOException, MalformedURLException {
|
||||
if (pURI != null && pURI.indexOf("://") < 0) {
|
||||
// If local, get as stream
|
||||
return new StreamSource(getResourceAsStream(pURI));
|
||||
}
|
||||
|
||||
// ...else, create from URI string
|
||||
return new StreamSource(pURI);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/****************************************************
|
||||
* *
|
||||
* (c) 2000-2003 TwelveMonkeys *
|
||||
* All rights reserved *
|
||||
* http://www.twelvemonkeys.no *
|
||||
* *
|
||||
* $RCSfile: ConditionalTagBase.java,v $
|
||||
* @version $Revision: #1 $
|
||||
* $Date: 2008/05/05 $
|
||||
* *
|
||||
* @author Last modified by: $Author: haku $
|
||||
* *
|
||||
****************************************************/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Produced (p) 2002 TwelveMonkeys
|
||||
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
||||
* Phone : +47 22 57 70 00
|
||||
* Fax : +47 22 57 70 70
|
||||
*/
|
||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
|
||||
|
||||
/**
|
||||
* <p>An abstract base class for tags with some kind of conditional presentation of the tag body.</p>
|
||||
*
|
||||
* @version 1.0
|
||||
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
||||
*/
|
||||
public abstract class ConditionalTagBase extends TagSupport {
|
||||
|
||||
// Members
|
||||
protected String objectName;
|
||||
protected String objectValue;
|
||||
|
||||
// Properties
|
||||
|
||||
/**
|
||||
* Method getName
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public String getName() {
|
||||
return objectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setName
|
||||
*
|
||||
*
|
||||
* @param pObjectName
|
||||
*
|
||||
*/
|
||||
public void setName(String pObjectName) {
|
||||
this.objectName = pObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getValue
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public String getValue() {
|
||||
return objectValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setValue
|
||||
*
|
||||
*
|
||||
* @param pObjectValue
|
||||
*
|
||||
*/
|
||||
public void setValue(String pObjectValue) {
|
||||
this.objectValue = pObjectValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Perform the test required for this particular tag, and either evaluate or skip the body of this tag.</p>
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @exception JspException if a JSP exception occurs.
|
||||
*/
|
||||
public int doStartTag() throws JspException {
|
||||
|
||||
if (condition()) {
|
||||
return (EVAL_BODY_INCLUDE);
|
||||
} else {
|
||||
return (SKIP_BODY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Evaluate the remainder of the current page as normal.</p>
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @exception JspException if a JSP exception occurs.
|
||||
*/
|
||||
public int doEndTag() throws JspException {
|
||||
return (EVAL_PAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Release all allocated resources.</p>
|
||||
*/
|
||||
public void release() {
|
||||
|
||||
super.release();
|
||||
objectName = null;
|
||||
objectValue = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The condition that must be met in order to display the body of this tag.</p>
|
||||
*
|
||||
* @exception JspException if a JSP exception occurs.
|
||||
* @return {@code true} if and only if all conditions are met.
|
||||
*/
|
||||
protected abstract boolean condition() throws JspException;
|
||||
}
|
||||
|
||||
|
||||
/*--- Formatted in Sun Java Convention Style on ma, des 1, '03 ---*/
|
||||
|
||||
|
||||
/*------ Formatted by Jindent 3.23 Basic 1.0 --- http://www.jindent.de ------*/
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Produced (p) 2002 TwelveMonkeys
|
||||
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
||||
* Phone : +47 22 57 70 00
|
||||
* Fax : +47 22 57 70 70
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Custom tag for testing equality of an attribute against a given value.
|
||||
* The attribute types supported so far is:
|
||||
* <ul>
|
||||
* <li>{@code java.lang.String} (ver. 1.0)
|
||||
* <li>{@code javax.servlet.http.Cookie} (ver. 1.0)
|
||||
* </ul>
|
||||
* </p>
|
||||
* See the implemented <a href="#condition">{@code condition}</a> method for details regarding the equality conditions.
|
||||
*
|
||||
* <p><hr></p>
|
||||
*
|
||||
* <h3>Tag Reference</h3>
|
||||
* <table border="0" cellspacing="3" cellpadding="3" width="90%">
|
||||
* <tr bgcolor="#cccccc">
|
||||
* <td colspan="5" class="body"><b>equal</b></td>
|
||||
* <td width="17%" align="right" class="body">Availability: 1.0</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td colspan="6" class="body"><p>Tag for testing if an attribute is equal to a given value.</p></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td width="15%" class="body"><b>Tag Body</b></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>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td class="body"><b>Restrictions</b></td>
|
||||
* <td colspan="5" class="body"><p>None</p></td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td class="body"><b>Attributes</b></td>
|
||||
* <td class="body">Name</td>
|
||||
* <td class="body">Required</td>
|
||||
* <td colspan="2" class="body">Runtime Expression Evaluation</td>
|
||||
* <td class="body">Availability</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr bgcolor="#cccccc">
|
||||
* <td bgcolor="#ffffff"> </td>
|
||||
* <td class="body_grey"><b>name</b></td>
|
||||
* <td class="body_grey"> Yes</td>
|
||||
* <td colspan="2" class="body_grey"> Yes</td>
|
||||
* <td class="body_grey"> 1.0</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td bgcolor="#ffffff"> </td>
|
||||
* <td colspan="5" class="body"><p>The attribute name</p></td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr bgcolor="#cccccc">
|
||||
* <td bgcolor="#ffffff"> </td>
|
||||
* <td class="body_grey"><b>value</b></td>
|
||||
* <td class="body_grey"> No</td>
|
||||
* <td colspan="2" class="body_grey"> Yes</td>
|
||||
* <td class="body_grey"> 1.0</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td bgcolor="#ffffff" class="body"> </td>
|
||||
* <td colspan="5" class="body"><p>The value for equality testing</p></td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td class="body" valign="top"><b>Variables</b></td>
|
||||
* <td colspan="5" class="body">None</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td class="body" valign="top"><b>Examples</b></td>
|
||||
* <td colspan="5" class="body">
|
||||
* <pre>
|
||||
*<%@ taglib prefix="twelvemonkeys" uri="twelvemonkeys-logic" %>
|
||||
*<bean:cookie id="logonUsernameCookie"
|
||||
* name="<%= com.strutscommand.Constants.LOGON_USERNAME_COOKIE_NAME %>"
|
||||
* value="no_username_set" />
|
||||
*<twelvemonkeys:equal name="logonUsernameCookie" value="no_username_set">
|
||||
* <html:text property="username" />
|
||||
*</twelvemonkeys:equal>
|
||||
* </pre>
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <hr>
|
||||
*
|
||||
* @version 1.0
|
||||
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
||||
* @see <a href="NotEqualTag.html">notEqual</a>
|
||||
*/
|
||||
public class EqualTag extends ConditionalTagBase {
|
||||
|
||||
/**
|
||||
* <a name="condition"></a>
|
||||
*
|
||||
* The conditions that must be met in order to display the body of this tag:
|
||||
* <ol>
|
||||
* <li>The attribute name property ({@code name} -> {@code mObjectName}) must not be empty.
|
||||
* <li>The attribute must exist.
|
||||
* <li>The attribute must be an instance of one of the supported classes:
|
||||
* <ul>
|
||||
* <li>{@code java.lang.String}
|
||||
* <li>{@code javax.servlet.http.Cookie}
|
||||
* </ul>
|
||||
* <li>The value of the attribute must be equal to the object value property ({@code value} -> {@code mObjectValue}).
|
||||
* </ol>
|
||||
* <p>
|
||||
* NB! If the object value property ({@code value} -> {@code mObjectValue}) is empty than {@code true} will be returned.
|
||||
* </p>
|
||||
*
|
||||
* @return {@code true} if and only if all conditions are met.
|
||||
*/
|
||||
protected boolean condition() throws JspException {
|
||||
|
||||
if (StringUtil.isEmpty(objectName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtil.isEmpty(objectValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Object pageScopedAttribute = pageContext.getAttribute(objectName);
|
||||
if (pageScopedAttribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String pageScopedStringAttribute;
|
||||
|
||||
// String
|
||||
if (pageScopedAttribute instanceof String) {
|
||||
pageScopedStringAttribute = (String) pageScopedAttribute;
|
||||
|
||||
// Cookie
|
||||
}
|
||||
else if (pageScopedAttribute instanceof Cookie) {
|
||||
pageScopedStringAttribute = ((Cookie) pageScopedAttribute).getValue();
|
||||
|
||||
// Type not yet supported...
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (pageScopedStringAttribute.equals(objectValue));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||
|
||||
import javax.servlet.jsp.tagext.*;
|
||||
|
||||
/**
|
||||
* TagExtraInfo class for IteratorProvider tags.
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
* @version $id: $
|
||||
*/
|
||||
public class IteratorProviderTEI extends TagExtraInfo {
|
||||
/**
|
||||
* Gets the variable info for IteratorProvider tags. The attribute with the
|
||||
* name defined by the "id" attribute and type defined by the "type"
|
||||
* attribute is declared with scope {@code VariableInfo.AT_END}.
|
||||
*
|
||||
* @param pData TagData instance provided by container
|
||||
* @return an VariableInfo array of lenght 1, containing the attribute
|
||||
* defined by the id parameter, declared, and with scope
|
||||
* {@code VariableInfo.AT_END}.
|
||||
*/
|
||||
public VariableInfo[] getVariableInfo(TagData pData) {
|
||||
// Get attribute name
|
||||
String attributeName = pData.getId();
|
||||
if (attributeName == null) {
|
||||
attributeName = IteratorProviderTag.getDefaultIteratorName();
|
||||
}
|
||||
|
||||
// Get type
|
||||
String type = pData.getAttributeString(IteratorProviderTag.ATTRIBUTE_TYPE);
|
||||
if (type == null) {
|
||||
type = IteratorProviderTag.getDefaultIteratorType();
|
||||
}
|
||||
|
||||
// Return the variable info
|
||||
return new VariableInfo[]{
|
||||
new VariableInfo(attributeName, type, true, VariableInfo.AT_END),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Abstract base class for adding iterators to a page.
|
||||
*
|
||||
* @todo Possible to use same strategy for all types of objects? Rename class
|
||||
* to ObjectProviderTag? Hmmm... Might work.
|
||||
*
|
||||
* @author Harald Kuhr
|
||||
* @version $id: $
|
||||
*/
|
||||
public abstract class IteratorProviderTag extends TagSupport {
|
||||
/** {@code iterator} */
|
||||
protected final static String DEFAULT_ITERATOR_NAME = "iterator";
|
||||
/** {@code java.util.iterator} */
|
||||
protected final static String DEFAULT_ITERATOR_TYPE = "java.util.Iterator";
|
||||
/** {@code type} */
|
||||
public final static String ATTRIBUTE_TYPE = "type";
|
||||
|
||||
/** */
|
||||
private String type = null;
|
||||
|
||||
/**
|
||||
* Gets the type.
|
||||
*
|
||||
* @return the type (class name)
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type.
|
||||
*
|
||||
* @param pType
|
||||
*/
|
||||
|
||||
public void setType(String pType) {
|
||||
type = pType;
|
||||
}
|
||||
|
||||
/**
|
||||
* doEndTag implementation.
|
||||
*
|
||||
* @return {@code Tag.EVAL_PAGE}
|
||||
* @throws JspException
|
||||
*/
|
||||
|
||||
public int doEndTag() throws JspException {
|
||||
// Set the iterator
|
||||
pageContext.setAttribute(getId(), getIterator());
|
||||
|
||||
return Tag.EVAL_PAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the iterator for this tag.
|
||||
*
|
||||
* @return an {@link java.util.Iterator}
|
||||
*/
|
||||
protected abstract Iterator getIterator();
|
||||
|
||||
/**
|
||||
* Gets the default iterator name.
|
||||
*
|
||||
* @return {@link #DEFAULT_ITERATOR_NAME}
|
||||
*/
|
||||
protected static String getDefaultIteratorName() {
|
||||
return DEFAULT_ITERATOR_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default iterator type.
|
||||
*
|
||||
* @return {@link #DEFAULT_ITERATOR_TYPE}
|
||||
*/
|
||||
protected static String getDefaultIteratorType() {
|
||||
return DEFAULT_ITERATOR_TYPE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Produced (p) 2002 TwelveMonkeys
|
||||
* Address : Svovelstikka 1, Box 6432 Etterstad, 0605 Oslo, Norway.
|
||||
* Phone : +47 22 57 70 00
|
||||
* Fax : +47 22 57 70 70
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.jsp.taglib.logic;
|
||||
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Custom tag for testing non-equality of an attribute against a given value.
|
||||
* The attribute types supported so far is:
|
||||
* <ul>
|
||||
* <li>{@code java.lang.String} (ver. 1.0)
|
||||
* <li>{@code javax.servlet.http.Cookie} (ver. 1.0)
|
||||
* </ul>
|
||||
* </p>
|
||||
* See the implemented <a href="#condition">{@code condition}</a> method for details regarding the non-equality conditions.
|
||||
*
|
||||
* <p><hr></p>
|
||||
*
|
||||
* <h3>Tag Reference</h3>
|
||||
* <table border="0" cellspacing="3" cellpadding="3" width="90%">
|
||||
* <tr bgcolor="#cccccc">
|
||||
* <td colspan="5" class="body"><b>notEqual</b></td>
|
||||
* <td width="17%" align="right" class="body">Availability: 1.0</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td colspan="6" class="body"><p>Tag for testing if an attribute is NOT equal to a given value.</p></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td width="15%" class="body"><b>Tag Body</b></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>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td class="body"><b>Restrictions</b></td>
|
||||
* <td colspan="5" class="body"><p>None</p></td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td class="body"><b>Attributes</b></td>
|
||||
* <td class="body">Name</td>
|
||||
* <td class="body">Required</td>
|
||||
* <td colspan="2" class="body">Runtime Expression Evaluation</td>
|
||||
* <td class="body">Availability</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr bgcolor="#cccccc">
|
||||
* <td bgcolor="#ffffff"> </td>
|
||||
* <td class="body_grey"><b>name</b></td>
|
||||
* <td class="body_grey"> Yes</td>
|
||||
* <td colspan="2" class="body_grey"> Yes</td>
|
||||
* <td class="body_grey"> 1.0</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td bgcolor="#ffffff"> </td>
|
||||
* <td colspan="5" class="body"><p>The attribute name</p></td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr bgcolor="#cccccc">
|
||||
* <td bgcolor="#ffffff"> </td>
|
||||
* <td class="body_grey"><b>value</b></td>
|
||||
* <td class="body_grey"> No</td>
|
||||
* <td colspan="2" class="body_grey"> Yes</td>
|
||||
* <td class="body_grey"> 1.0</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td bgcolor="#ffffff" class="body"> </td>
|
||||
* <td colspan="5" class="body"><p>The value for equality testing</p></td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td class="body" valign="top"><b>Variables</b></td>
|
||||
* <td colspan="5" class="body">None</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td class="body" valign="top"><b>Examples</b></td>
|
||||
* <td colspan="5" class="body">
|
||||
* <pre>
|
||||
*<%@ taglib prefix="twelvemonkeys" uri="twelvemonkeys-logic" %>
|
||||
*<bean:cookie id="logonUsernameCookie"
|
||||
* name="<%= com.strutscommand.Constants.LOGON_USERNAME_COOKIE_NAME %>"
|
||||
* value="no_username_set" />
|
||||
*<twelvemonkeys:notEqual name="logonUsernameCookie" value="no_username_set">
|
||||
* <html:text property="username" value="<%= logonUsernameCookie.getValue() %>" />
|
||||
*</twelvemonkeys:notEqual>
|
||||
* </pre>
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <hr>
|
||||
*
|
||||
* @version 1.0
|
||||
* @author <a href="mailto:eirik.torske@twelvemonkeys.no">Eirik Torske</a>
|
||||
* @see <a href="EqualTag.html">equal</a>
|
||||
*/
|
||||
public class NotEqualTag extends ConditionalTagBase {
|
||||
|
||||
/**
|
||||
* <a name="condition"></a>
|
||||
*
|
||||
* The condition that must be met in order to display the body of this tag:
|
||||
* <ol>
|
||||
* <li>The attribute name property ({@code name} -> {@code mObjectName}) must not be empty.
|
||||
* <li>The attribute must exist.
|
||||
* <li>The attribute must be an instance of one of the supported classes:
|
||||
* <ul>
|
||||
* <li>{@code java.lang.String}
|
||||
* <li>{@code javax.servlet.http.Cookie}
|
||||
* </ul>
|
||||
* <li>The value of the attribute must NOT be equal to the object value property ({@code value} -> {@code mObjectValue}).
|
||||
* </ol>
|
||||
* <p>
|
||||
* NB! If the object value property ({@code value} -> {@code mObjectValue}) is empty than {@code true} will be returned.
|
||||
* </p>
|
||||
*
|
||||
* @return {@code true} if and only if all conditions are met.
|
||||
*/
|
||||
protected boolean condition() throws JspException {
|
||||
|
||||
if (StringUtil.isEmpty(objectName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtil.isEmpty(objectValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Object pageScopedAttribute = pageContext.getAttribute(objectName);
|
||||
if (pageScopedAttribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String pageScopedStringAttribute;
|
||||
|
||||
// String
|
||||
if (pageScopedAttribute instanceof String) {
|
||||
pageScopedStringAttribute = (String) pageScopedAttribute;
|
||||
|
||||
// Cookie
|
||||
}
|
||||
else if (pageScopedAttribute instanceof Cookie) {
|
||||
pageScopedStringAttribute = ((Cookie) pageScopedAttribute).getValue();
|
||||
|
||||
// Type not yet supported...
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (!(pageScopedStringAttribute.equals(objectValue)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* The TwelveMonkeys common TagLib.
|
||||
*/
|
||||
package com.twelvemonkeys.servlet.jsp.taglib;
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.twelvemonkeys.servlet.log4j;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Log4JContextWrapper
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: log4j/Log4JContextWrapper.java#1 $
|
||||
*/
|
||||
final class Log4JContextWrapper implements ServletContext {
|
||||
// TODO: Move to sandbox
|
||||
|
||||
// TODO: This solution sucks...
|
||||
// How about starting to create some kind of pluggable decorator system,
|
||||
// something along the lines of AOP mixins/interceptor pattern..
|
||||
// Probably using a dynamic Proxy, delegating to the mixins and or the
|
||||
// wrapped object based on configuration.
|
||||
// This way we could simply call ServletUtil.decorate(ServletContext):ServletContext
|
||||
// And the context would be decorated with all configured mixins at once,
|
||||
// requiring less boilerplate delegation code, and less layers of wrapping
|
||||
// (alternatively we could decorate the Servlet/FilterConfig objects).
|
||||
// See the ServletUtil.createWrapper methods for some hints..
|
||||
|
||||
|
||||
// Something like this:
|
||||
public static ServletContext wrap(final ServletContext pContext, final Object[] pDelegates, final ClassLoader pLoader) {
|
||||
ClassLoader cl = pLoader != null ? pLoader : Thread.currentThread().getContextClassLoader();
|
||||
|
||||
// TODO: Create a "static" mapping between methods in the ServletContext
|
||||
// and the corresponding delegate
|
||||
|
||||
// TODO: Resolve super-invokations, to delegate to next delegate in
|
||||
// chain, and finally invoke pContext
|
||||
|
||||
return (ServletContext) Proxy.newProxyInstance(cl, new Class[] {ServletContext.class}, new InvocationHandler() {
|
||||
public Object invoke(Object pProxy, Method pMethod, Object[] pArgs) throws Throwable {
|
||||
// TODO: Test if any of the delegates should receive, if so invoke
|
||||
|
||||
// Else, invoke on original object
|
||||
return pMethod.invoke(pContext, pArgs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private final ServletContext context;
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
Log4JContextWrapper(ServletContext pContext) {
|
||||
context = pContext;
|
||||
|
||||
// TODO: We want a logger per servlet, not per servlet context, right?
|
||||
logger = Logger.getLogger(pContext.getServletContextName());
|
||||
|
||||
// TODO: Automatic init/config of Log4J using context parameter for log4j.xml?
|
||||
// See Log4JInit.java
|
||||
|
||||
// TODO: Automatic config of properties in the context wrapper?
|
||||
}
|
||||
|
||||
public final void log(final Exception pException, final String pMessage) {
|
||||
log(pMessage, pException);
|
||||
}
|
||||
|
||||
// TODO: Add more logging methods to interface info/warn/error?
|
||||
// TODO: Implement these mehtods in GenericFilter/GenericServlet?
|
||||
|
||||
public void log(String pMessage) {
|
||||
// TODO: Get logger for caller..
|
||||
// Should be possible using some stack peek hack, but that's slow...
|
||||
// Find a good way...
|
||||
// Maybe just pass it into the constuctor, and have one wrapper per servlet
|
||||
logger.info(pMessage);
|
||||
}
|
||||
|
||||
public void log(String pMessage, Throwable pCause) {
|
||||
// TODO: Get logger for caller..
|
||||
|
||||
logger.error(pMessage, pCause);
|
||||
}
|
||||
|
||||
public Object getAttribute(String pMessage) {
|
||||
return context.getAttribute(pMessage);
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames() {
|
||||
return context.getAttributeNames();
|
||||
}
|
||||
|
||||
public ServletContext getContext(String pMessage) {
|
||||
return context.getContext(pMessage);
|
||||
}
|
||||
|
||||
public String getInitParameter(String pMessage) {
|
||||
return context.getInitParameter(pMessage);
|
||||
}
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
return context.getInitParameterNames();
|
||||
}
|
||||
|
||||
public int getMajorVersion() {
|
||||
return context.getMajorVersion();
|
||||
}
|
||||
|
||||
public String getMimeType(String pMessage) {
|
||||
return context.getMimeType(pMessage);
|
||||
}
|
||||
|
||||
public int getMinorVersion() {
|
||||
return context.getMinorVersion();
|
||||
}
|
||||
|
||||
public RequestDispatcher getNamedDispatcher(String pMessage) {
|
||||
return context.getNamedDispatcher(pMessage);
|
||||
}
|
||||
|
||||
public String getRealPath(String pMessage) {
|
||||
return context.getRealPath(pMessage);
|
||||
}
|
||||
|
||||
public RequestDispatcher getRequestDispatcher(String pMessage) {
|
||||
return context.getRequestDispatcher(pMessage);
|
||||
}
|
||||
|
||||
public URL getResource(String pMessage) throws MalformedURLException {
|
||||
return context.getResource(pMessage);
|
||||
}
|
||||
|
||||
public InputStream getResourceAsStream(String pMessage) {
|
||||
return context.getResourceAsStream(pMessage);
|
||||
}
|
||||
|
||||
public Set getResourcePaths(String pMessage) {
|
||||
return context.getResourcePaths(pMessage);
|
||||
}
|
||||
|
||||
public String getServerInfo() {
|
||||
return context.getServerInfo();
|
||||
}
|
||||
|
||||
public Servlet getServlet(String pMessage) throws ServletException {
|
||||
//noinspection deprecation
|
||||
return context.getServlet(pMessage);
|
||||
}
|
||||
|
||||
public String getServletContextName() {
|
||||
return context.getServletContextName();
|
||||
}
|
||||
|
||||
public Enumeration getServletNames() {
|
||||
//noinspection deprecation
|
||||
return context.getServletNames();
|
||||
}
|
||||
|
||||
public Enumeration getServlets() {
|
||||
//noinspection deprecation
|
||||
return context.getServlets();
|
||||
}
|
||||
|
||||
public void removeAttribute(String pMessage) {
|
||||
context.removeAttribute(pMessage);
|
||||
}
|
||||
|
||||
public void setAttribute(String pMessage, Object pExtension) {
|
||||
context.setAttribute(pMessage, pExtension);
|
||||
}
|
||||
}
|
||||
153
sandbox/sandbox-swing/pom.xml
Normal file
153
sandbox/sandbox-swing/pom.xml
Normal file
@@ -0,0 +1,153 @@
|
||||
<?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.sandbox</groupId>
|
||||
<artifactId>sandbox</artifactId>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>sandbox-swing</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Sandbox :: Swing</name>
|
||||
<description>
|
||||
The TwelveMonkeys Swing Sandbox. Experimental stuff.
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<!-- TODO: Make this system independent -->
|
||||
<javafx_home>/Library/JavaFX/Home</javafx_home>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-io</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common-image</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.swing</groupId>
|
||||
<artifactId>swing-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.swing</groupId>
|
||||
<artifactId>swing-application</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- JavaFX libs must be installed as well -->
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-common</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-common.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-io</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-io.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-geom</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-geom.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-ui-commmon</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-ui-common.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-ui-controls</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-ui-controls.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-ui-charts</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-ui-charts.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-ui-desktop</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-ui-desktop.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-ui-swing</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-ui-swing.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-ext-swing</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/javafx-ext-swing.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-xfdloader</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/fxdloader.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx</groupId>
|
||||
<artifactId>javafx-websvc</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/websvc.jar</systemPath>
|
||||
</dependency>
|
||||
<!-- The JavaFX dependencies are taken from the profiles/desktop.properties file-->
|
||||
|
||||
<!-- Extra JavaFX dependencies -->
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx.jmc</groupId>
|
||||
<artifactId>javafx-jmc</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/jmc.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.javafx.scriptapi</groupId>
|
||||
<artifactId>javafx-scriptapi</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${javafx_home}/lib/desktop/script-api.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,207 @@
|
||||
package com.twelvemonkeys.swing.filechooser;
|
||||
|
||||
import com.twelvemonkeys.lang.Platform;
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import javax.swing.filechooser.FileView;
|
||||
import javax.swing.plaf.FileChooserUI;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* FileSystemViews
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: FileSystemViews.java,v 1.0 Jan 14, 2010 3:19:51 PM haraldk Exp$
|
||||
*/
|
||||
public final class FileSystemViews {
|
||||
|
||||
public static FileSystemView getFileSystemView() {
|
||||
if (Platform.os() == Platform.OperatingSystem.MacOS) {
|
||||
return ProxyFileSystemView.instance;
|
||||
}
|
||||
|
||||
return FileSystemView.getFileSystemView();
|
||||
}
|
||||
|
||||
private static class ProxyFileSystemView extends FileSystemView {
|
||||
|
||||
private static final FileSystemView instance = createFSV();
|
||||
|
||||
private static FileSystemView createFSV() {
|
||||
FileSystemView view = FileSystemView.getFileSystemView();
|
||||
|
||||
try {
|
||||
FileChooserUI ui = null;
|
||||
/* NOTE: The following is faster, but does not work reliably, as getSystemTypeDescription will return null...
|
||||
|
||||
// The below is really a lot of hassle to avoid creating a JFileChooser. Maybe not a good idea?
|
||||
String uiClassName = UIManager.getString("FileChooserUI");
|
||||
try {
|
||||
@SuppressWarnings({"unchecked"})
|
||||
Class<FileChooserUI> uiClass = (Class<FileChooserUI>) Class.forName(uiClassName);
|
||||
@SuppressWarnings({"unchecked"})
|
||||
Constructor<FileChooserUI>[] constructors = uiClass.getDeclaredConstructors();
|
||||
for (Constructor constructor : constructors) {
|
||||
if (!constructor.isAccessible()) {
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
|
||||
Class[] parameterTypes = constructor.getParameterTypes();
|
||||
|
||||
// Test the two most likely constructors
|
||||
if (parameterTypes.length == 0) {
|
||||
ui = (FileChooserUI) constructor.newInstance();
|
||||
break;
|
||||
}
|
||||
else if (parameterTypes.length == 1 && parameterTypes[0] == JFileChooser.class) {
|
||||
ui = (FileChooserUI) constructor.newInstance((JFileChooser) null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
|
||||
if (ui == null) {
|
||||
*/
|
||||
// Somewhat slower, but should work even if constructors change
|
||||
ui = new JFileChooser().getUI();
|
||||
// }
|
||||
|
||||
return new ProxyFileSystemView(ui.getFileView(null), view);
|
||||
}
|
||||
catch (Throwable ignore) {
|
||||
}
|
||||
|
||||
// Fall back to default view
|
||||
return view;
|
||||
}
|
||||
|
||||
private final FileView uiView;
|
||||
private final FileSystemView defaultView;
|
||||
|
||||
public ProxyFileSystemView(final FileView pUIView, final FileSystemView pDefaultView) {
|
||||
Validate.notNull(pUIView, "uiView");
|
||||
Validate.notNull(pDefaultView, "defaultFileSystemView");
|
||||
|
||||
uiView = pUIView;
|
||||
defaultView = pDefaultView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isTraversable(File f) {
|
||||
return uiView.isTraversable(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSystemDisplayName(File f) {
|
||||
return uiView.getName(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSystemTypeDescription(File f) {
|
||||
// TODO: Create something that gives a proper description here on the Mac...
|
||||
return uiView.getTypeDescription(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getSystemIcon(File f) {
|
||||
return uiView.getIcon(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRoot(File f) {
|
||||
return defaultView.isRoot(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParent(File folder, File file) {
|
||||
return defaultView.isParent(folder, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getChild(File parent, String fileName) {
|
||||
return defaultView.getChild(parent, fileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFileSystem(File f) {
|
||||
return defaultView.isFileSystem(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHiddenFile(File f) {
|
||||
return defaultView.isHiddenFile(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFileSystemRoot(File dir) {
|
||||
return defaultView.isFileSystemRoot(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDrive(File dir) {
|
||||
return defaultView.isDrive(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFloppyDrive(File dir) {
|
||||
return defaultView.isFloppyDrive(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputerNode(File dir) {
|
||||
return defaultView.isComputerNode(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] getRoots() {
|
||||
return defaultView.getRoots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getHomeDirectory() {
|
||||
return defaultView.getHomeDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDefaultDirectory() {
|
||||
return defaultView.getDefaultDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createFileObject(File dir, String filename) {
|
||||
return defaultView.createFileObject(dir, filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createFileObject(String path) {
|
||||
return defaultView.createFileObject(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] getFiles(File dir, boolean useFileHiding) {
|
||||
return defaultView.getFiles(dir, useFileHiding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getParentDirectory(File dir) {
|
||||
return defaultView.getParentDirectory(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createNewFolder(File containingDir) throws IOException {
|
||||
return defaultView.createNewFolder(containingDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "[" + uiView + ", " + defaultView + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user