RIP: Sandbox

This commit is contained in:
Harald Kuhr
2022-01-24 09:01:53 +01:00
parent b76f74e79a
commit 1cd594d113
109 changed files with 0 additions and 23473 deletions

View File

@@ -24,7 +24,6 @@
<module>servlet</module>
<module>imageio</module>
<!--<module>swing</module>-->
<!--<module>sandbox</module>-->
<module>contrib</module>
<module>bom</module>
</modules>

View File

@@ -1,156 +0,0 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.twelvemonkeys.sandbox</groupId>
<artifactId>sandbox</artifactId>
<version>3.1-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.1-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.sandbox</groupId>
<artifactId>sandbox-common</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common-io</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common-lang</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</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.4</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>

View File

@@ -1,58 +0,0 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.twelvemonkeys.sandbox</groupId>
<artifactId>sandbox</artifactId>
<version>3.1-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>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common-lang</artifactId>
<scope>test</scope>
<type>test-jar</type>
</dependency>
</dependencies>
</project>

View File

@@ -1,143 +0,0 @@
/*
* 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.image;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.io.File;
import java.io.IOException;
/**
* AbstractFilter
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: AbstractFilter.java,v 1.0 18.06.12 16:55 haraldk Exp$
*/
public abstract class AbstractFilter implements BufferedImageOp {
public abstract BufferedImage filter(BufferedImage src, BufferedImage dest);
public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
throw new UnsupportedOperationException("Method createCompatibleDestImage not implemented"); // TODO: Implement
}
public Rectangle2D getBounds2D(BufferedImage src) {
return new Rectangle2D.Double(0, 0, src.getWidth(), src.getHeight());
}
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
if (dstPt == null) {
dstPt = new Point2D.Double();
}
dstPt.setLocation(srcPt);
return dstPt;
}
public RenderingHints getRenderingHints() {
return null;
}
protected static void exercise(final String[] args, final BufferedImageOp filter, final Color background) throws IOException {
boolean original = false;
for (String arg : args) {
if (arg.startsWith("-")) {
if (arg.equals("-o") || arg.equals("--original")) {
original = true;
}
continue;
}
final File file = new File(arg);
BufferedImage image = ImageIO.read(file);
if (image.getWidth() > 640) {
image = new ResampleOp(640, Math.round(image.getHeight() * (640f / image.getWidth())), null).filter(image, null);
}
if (!original) {
filter.filter(image, image);
}
final Color bg = original ? Color.BLACK : background;
final BufferedImage img = image;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame(filter.getClass().getSimpleName().replace("Filter", "") + "Test: " + file.getName());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(final WindowEvent e) {
Window[] windows = Window.getWindows();
if (windows == null || windows.length == 0) {
System.exit(0);
}
}
});
frame.getRootPane().getActionMap().put("window-close", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.getWindowAncestor((Component) e.getSource());
window.setVisible(false);
window.dispose();
}
});
frame.getRootPane().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "window-close");
JLabel label = new JLabel(new BufferedImageIcon(img));
if (bg != null) {
label.setOpaque(true);
label.setBackground(bg);
}
label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JScrollPane scrollPane = new JScrollPane(label);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
frame.add(scrollPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}
}

View File

@@ -1,128 +0,0 @@
/*
* 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 javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
/**
* ConvolveTester
*
* @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/image/ConvolveTester.java#1 $
*/
public class ConvolveTester {
// Initial sample timings (avg, 1000 iterations)
// PNG, type 0: JPEG, type 3:
// ZERO_FILL: 5.4 ms 4.6 ms
// NO_OP: 5.4 ms 4.6 ms
// REFLECT: 42.4 ms 24.9 ms
// WRAP: 86.9 ms 29.5 ms
final static int ITERATIONS = 1000;
public static void main(String[] pArgs) throws IOException {
File input = new File(pArgs[0]);
BufferedImage image = ImageIO.read(input);
BufferedImage result = null;
System.out.println("image: " + image);
if (pArgs.length > 1) {
float ammount = Float.parseFloat(pArgs[1]);
int edgeOp = pArgs.length > 2 ? Integer.parseInt(pArgs[2]) : ImageUtil.EDGE_REFLECT;
long start = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
result = sharpen(image, ammount, edgeOp);
}
long end = System.currentTimeMillis();
System.out.println("Time: " + ((end - start) / (double) ITERATIONS) + "ms");
showIt(result, "Sharpened " + ammount + " " + input.getName());
}
else {
showIt(image, "Original " + input.getName());
}
}
public static void showIt(final BufferedImage pImage, final String pTitle) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
JFrame frame = new JFrame(pTitle);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel pane = new JPanel(new BorderLayout());
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImageIcon icon = new BufferedImageIcon(ImageUtil.accelerate(pImage, gc));
JScrollPane scroll = new JScrollPane(new JLabel(icon));
scroll.setBorder(null);
pane.add(scroll);
frame.setContentPane(pane);
frame.pack();
frame.setVisible(true);
}
});
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
static BufferedImage sharpen(BufferedImage pOriginal, final float pAmmount, int pEdgeOp) {
if (pAmmount == 0f) {
return pOriginal;
}
// Create the convolution matrix
float[] data = new float[]{
0.0f, -pAmmount, 0.0f,
-pAmmount, 4f * pAmmount + 1f, -pAmmount,
0.0f, -pAmmount, 0.0f
};
// Do the filtering
return ImageUtil.convolve(pOriginal, new Kernel(3, 3, data), pEdgeOp);
}
}

View File

@@ -1,78 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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);
}

View File

@@ -1,61 +0,0 @@
/*
* 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
);
}
}

View File

@@ -1,182 +0,0 @@
/*
* 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.image;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.RescaleOp;
import java.io.IOException;
import java.util.Random;
/**
* InstaCRTFilter
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: InstaCRTFilter.java,v 1.0 15.06.12 13:24 haraldk Exp$
*/
public class InstaCRTFilter extends AbstractFilter {
// NOTE: This is a PoC, and not good code...
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
if (dest == null) {
dest = createCompatibleDestImage(src, null);
}
// Make grayscale
BufferedImage image = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), getRenderingHints()).filter(src, null);
// Make image faded/too bright
image = new RescaleOp(1.2f, 120f, getRenderingHints()).filter(image, image);
// Blur
image = ImageUtil.blur(image, 2.5f);
Graphics2D g = dest.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.drawImage(image, 0, 0, null);
// Rotate it slightly for a more analogue feeling
double angle = .0055;
g.rotate(angle);
// Apply fake green-ish h-sync line at random position
Random random = new Random();
int lineStart = random.nextInt(image.getHeight() - 80);
int lineHeight = random.nextInt(10) + 20;
g.setComposite(AlphaComposite.SrcOver.derive(.3f));
g.setPaint(new LinearGradientPaint(
0, lineStart, 0, lineStart + lineHeight,
new float[] {0, .3f, .9f, 1},
new Color[] {new Color(0, true), new Color(0x90AF66), new Color(0x99606F33, true), new Color(0, true)}
));
g.fillRect(0, lineStart, image.getWidth(), lineHeight);
// Apply fake large dot-pitch (black lines w/transparency)
g.setComposite(AlphaComposite.SrcOver.derive(.55f));
g.setColor(Color.BLACK);
for (int y = 0; y < image.getHeight(); y += 3) {
g.setStroke(new BasicStroke(random.nextFloat() / 3 + .8f));
g.drawLine(0, y, image.getWidth(), y);
}
// Vignette/border
g.setComposite(AlphaComposite.SrcOver.derive(.75f));
int focus = Math.min(image.getWidth() / 8, image.getHeight() / 8);
g.setPaint(new RadialGradientPaint(
new Point(image.getWidth() / 2, image.getHeight() / 2),
Math.max(image.getWidth(), image.getHeight()) / 1.6f,
new Point(focus, focus),
new float[] {0, .3f, .9f, 1f},
new Color[] {new Color(0x99FFFFFF, true), new Color(0x00FFFFFF, true), new Color(0x0, true), Color.BLACK},
MultipleGradientPaint.CycleMethod.NO_CYCLE
));
g.fillRect(-2, -2, image.getWidth() + 4, image.getHeight() + 4);
g.rotate(-angle);
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
g.setPaint(new RadialGradientPaint(
new Point(image.getWidth() / 2, image.getHeight() / 2),
Math.max(image.getWidth(), image.getHeight()) / 1.65f,
new Point(image.getWidth() / 2, image.getHeight() / 2),
new float[] {0, .85f, 1f},
new Color[] {new Color(0x0, true), new Color(0x0, true), Color.BLACK},
MultipleGradientPaint.CycleMethod.NO_CYCLE
));
g.fillRect(0, 0, image.getWidth(), image.getHeight());
// Highlight
g.setComposite(AlphaComposite.SrcOver.derive(.55f));
g.setPaint(new RadialGradientPaint(
new Point(image.getWidth(), image.getHeight()),
Math.max(image.getWidth(), image.getHeight()) * 1.1f,
new Point(image.getWidth() / 2, image.getHeight() / 2),
new float[] {0, .75f, 1f},
new Color[] {new Color(0x00FFFFFF, true), new Color(0x00FFFFFF, true), Color.WHITE},
MultipleGradientPaint.CycleMethod.NO_CYCLE
));
g.fillRect(0, 0, image.getWidth(), image.getHeight());
}
finally {
g.dispose();
}
// Round corners
BufferedImage foo = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = foo.createGraphics();
try {
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setColor(Color.WHITE);
double angle = -0.04;
g.rotate(angle);
graphics.fillRoundRect(1, 1, image.getWidth() - 2, image.getHeight() - 2, 20, 20);
}
finally {
graphics.dispose();
}
foo = ImageUtil.blur(foo, 4.5f);
// Compose image into rounded corners
graphics = foo.createGraphics();
try {
graphics.setComposite(AlphaComposite.SrcIn);
graphics.drawImage(dest, 0, 0, null);
}
finally {
graphics.dispose();
}
// Draw it all back to dest
g = dest.createGraphics();
try {
g.setComposite(AlphaComposite.SrcOver);
g.setColor(Color.BLACK);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.drawImage(foo, 0, 0, null);
}
finally {
g.dispose();
}
return dest;
}
public static void main(String[] args) throws IOException {
exercise(args, new InstaCRTFilter(), Color.BLACK);
}
}

View File

@@ -1,201 +0,0 @@
/*
* 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.image;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.IOException;
import java.util.Random;
/**
* InstaLomoFilter
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: InstaLomoFilter.java,v 1.0 15.06.12 13:24 haraldk Exp$
*/
public class InstaLomoFilter extends AbstractFilter {
final private Random random = new Random();
// NOTE: This is a PoC, and not good code...
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
if (dest == null) {
dest = createCompatibleDestImage(src, null);
}
// Make image faded/washed out/red-ish
// DARK WARM
float[] scales = new float[] { 2.2f, 2.0f, 1.55f};
float[] offsets = new float[] {-20.0f, -90.0f, -110.0f};
// BRIGHT NATURAL
// float[] scales = new float[] { 1.1f, .9f, .7f};
// float[] offsets = new float[] {20, 30, 80};
// Faded, old-style
// float[] scales = new float[] { 1.1f, .7f, .3f};
// float[] offsets = new float[] {20, 30, 80};
// float[] scales = new float[] { 1.2f, .4f, .4f};
// float[] offsets = new float[] {0, 120, 120};
// BRIGHT WARM
// float[] scales = new float[] {1.1f, .8f, 1.6f};
// float[] offsets = new float[] {60, 70, -80};
BufferedImage image = new RescaleOp(scales, offsets, getRenderingHints()).filter(src, null);
// Blur
image = ImageUtil.blur(image, 2.5f);
Graphics2D g = dest.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.drawImage(image, 0, 0, null);
// Rotate it slightly for a more analogue feeling
double angle = .0055;
g.rotate(angle);
// Scratches
g.setComposite(AlphaComposite.SrcOver.derive(.025f));
for (int i = 0; i < 100; i++) {
g.setColor(random.nextBoolean() ? Color.WHITE : Color.BLACK);
g.setStroke(new BasicStroke(random.nextFloat() * 2f));
int x = random.nextInt(image.getWidth());
int off = random.nextInt(100);
for (int j = random.nextInt(3); j > 0; j--) {
g.drawLine(x + j, 0, x + off - 50 + j, image.getHeight());
}
}
// Vignette/border
g.setComposite(AlphaComposite.SrcOver.derive(.75f));
int focus = Math.min(image.getWidth() / 8, image.getHeight() / 8);
g.setPaint(new RadialGradientPaint(
new Point(image.getWidth() / 2, image.getHeight() / 2),
Math.max(image.getWidth(), image.getHeight()) / 1.6f,
new Point(focus, focus),
new float[] {0, .3f, .9f, 1f},
new Color[] {new Color(0x99FFFFFF, true), new Color(0x00FFFFFF, true), new Color(0x0, true), Color.BLACK},
MultipleGradientPaint.CycleMethod.NO_CYCLE
));
g.fillRect(-2, -2, image.getWidth() + 4, image.getHeight() + 4);
g.rotate(-angle);
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
g.setPaint(new RadialGradientPaint(
new Point(image.getWidth() / 2, image.getHeight() / 2),
Math.max(image.getWidth(), image.getHeight()) / 1.65f,
new Point(image.getWidth() / 2, image.getHeight() / 2),
new float[] {0, .85f, 1f},
new Color[] {new Color(0x0, true), new Color(0x0, true), Color.BLACK},
MultipleGradientPaint.CycleMethod.NO_CYCLE
));
g.fillRect(0, 0, image.getWidth(), image.getHeight());
// Highlight
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
g.setPaint(new RadialGradientPaint(
new Point(image.getWidth(), image.getHeight()),
Math.max(image.getWidth(), image.getHeight()) * 1.1f,
new Point(image.getWidth() / 2, image.getHeight() / 2),
new float[] {0, .75f, 1f},
new Color[] {new Color(0x00FFFFFF, true), new Color(0x00FFFFFF, true), Color.PINK},
MultipleGradientPaint.CycleMethod.NO_CYCLE
));
g.fillRect(0, 0, image.getWidth(), image.getHeight());
}
finally {
g.dispose();
}
// Noise
NoiseFilter noise = new NoiseFilter();
noise.setAmount(10);
noise.setDensity(2);
dest = noise.filter(dest, dest);
// Round corners
BufferedImage foo = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = foo.createGraphics();
try {
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setColor(Color.WHITE);
double angle = (random.nextDouble() * .01) - .005;
graphics.rotate(angle);
graphics.fillRoundRect(4, 4, image.getWidth() - 8, image.getHeight() - 8, 20, 20);
}
finally {
graphics.dispose();
}
noise.setAmount(20);
noise.setDensity(1);
noise.setMonochrome(true);
foo = noise.filter(foo, foo);
foo = ImageUtil.blur(foo, 4.5f);
// Compose image into rounded corners
graphics = foo.createGraphics();
try {
graphics.setComposite(AlphaComposite.SrcIn);
graphics.drawImage(dest, 0, 0, null);
}
finally {
graphics.dispose();
}
// Draw it all back to dest
g = dest.createGraphics();
try {
if (dest.getTransparency() != Transparency.OPAQUE) {
g.setComposite(AlphaComposite.Clear);
}
g.setColor(Color.WHITE);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.setComposite(AlphaComposite.SrcOver);
g.drawImage(foo, 0, 0, null);
}
finally {
g.dispose();
}
return dest;
}
public static void main(String[] args) throws IOException {
exercise(args, new InstaLomoFilter(), Color.WHITE);
}
}

View File

@@ -1,150 +0,0 @@
/*
* 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.image;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.IOException;
import java.util.Random;
/**
* InstaLomoFilter
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: InstaLomoFilter.java,v 1.0 15.06.12 13:24 haraldk Exp$
*/
public class InstaSepiaFilter extends AbstractFilter {
final private Random random = new Random();
// NOTE: This is a PoC, and not good code...
@Override
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
if (dest == null) {
dest = createCompatibleDestImage(src, null);
}
BufferedImage image = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), getRenderingHints()).filter(src, dest);
Graphics2D g2d = dest.createGraphics();
try {
g2d.drawImage(image, 0, 0, null);
}
finally {
g2d.dispose();
}
// Blur
image = ImageUtil.blur(image, 2.5f);
Graphics2D g = dest.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.drawImage(image, 0, 0, null);
// Rotate it slightly for a more analogue feeling
double angle = -.0055;
g.rotate(angle);
// Vignette/border
g.setComposite(AlphaComposite.SrcOver.derive(.35f));
g.setPaint(new RadialGradientPaint(
new Point(image.getWidth() / 2, image.getHeight() / 2),
Math.max(image.getWidth(), image.getHeight()) / 1.65f,
new Point(image.getWidth() / 2, image.getHeight() / 2),
new float[] {0, .85f, 1f},
new Color[] {new Color(0x0, true), new Color(0x0, true), Color.BLACK},
MultipleGradientPaint.CycleMethod.NO_CYCLE
));
g.fillRect(0, 0, image.getWidth(), image.getHeight());
}
finally {
g.dispose();
}
// Round corners
BufferedImage foo = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = foo.createGraphics();
try {
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setColor(Color.WHITE);
double angle = (random.nextDouble() * .01) - .005;
graphics.rotate(angle);
graphics.fillRoundRect(4, 4, image.getWidth() - 8, image.getHeight() - 8, 20, 20);
}
finally {
graphics.dispose();
}
// Noise
NoiseFilter noise = new NoiseFilter();
noise.setAmount(20);
noise.setDensity(1);
noise.setMonochrome(true);
foo = noise.filter(foo, foo);
foo = ImageUtil.blur(foo, 4.5f);
// Compose image into rounded corners
graphics = foo.createGraphics();
try {
graphics.setComposite(AlphaComposite.SrcIn);
graphics.drawImage(dest, 0, 0, null);
}
finally {
graphics.dispose();
}
float[] scales = new float[] {1, 1, 1, 1};
float[] offsets = new float[] {80, 40, 0, 0};
foo = new RescaleOp(scales, offsets, getRenderingHints()).filter(foo, foo);
// Draw it all back to dest
g = dest.createGraphics();
try {
g.setComposite(AlphaComposite.SrcOver);
g.setColor(Color.WHITE);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.drawImage(foo, 0, 0, null);
}
finally {
g.dispose();
}
return dest;
}
public static void main(String[] args) throws IOException {
exercise(args, new InstaSepiaFilter(), null);
}
}

View File

@@ -1,174 +0,0 @@
/*
* 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);
}
}
}

View File

@@ -1,325 +0,0 @@
/*
* 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 javax.imageio.ImageTypeSpecifier;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.UndeclaredThrowableException;
/**
* 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 :-/
// - Might be possible (but slow) to copy parts to memory and do CCOp on these copies
private static final boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.image.mapped.debug"));
/* Constants for DirectColorModel masks, from BufferedImage. */
private static final int DCM_RED_MASK = 0x00ff0000;
private static final int DCM_GREEN_MASK = 0x0000ff00;
private static final int DCM_BLUE_MASK = 0x000000ff;
private static final int DCM_ALPHA_MASK = 0xff000000;
private static final int DCM_565_RED_MASK = 0xf800;
private static final int DCM_565_GRN_MASK = 0x07E0;
private static final int DCM_565_BLU_MASK = 0x001F;
private static final int DCM_555_RED_MASK = 0x7C00;
private static final int DCM_555_GRN_MASK = 0x03E0;
private static final int DCM_555_BLU_MASK = 0x001F;
private static final int DCM_BGR_RED_MASK = 0x0000ff;
private static final int DCM_BGR_GRN_MASK = 0x00ff00;
private static final int DCM_BGR_BLU_MASK = 0xff0000;
static final RasterFactory RASTER_FACTORY = createRasterFactory();
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 {
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, RASTER_FACTORY.createRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
}
/**
* <p>
* Returns the {@code BufferedImage} image type that is compatible with the data in {@code image}.
* This method will return <em>compatible</em> types, even if {@code BufferedImage.getType()} returns
* {@code BufferedImage.TYPE_CUSTOM}.
* </p>
* <p>
* This method is defined to work so that, for any valid {@code BufferedImage} <em>type</em>
* (except {@code BufferedImage.TYPE_CUSTOM}), the following is {@code true}:
* <br/>
* {@code getCompatibleBufferedImageType(createCompatibleMappedImage(w, h, type)) == type}
* </p>
* <p>
* If no standard type is compatible with the image data, {@code BufferedImage.TYPE_CUSTOM} is returned.
* </p>
*
* @param image the image to test, may not be {@code null}.
*
* @return the {@code BufferedImage} type.
*
* @throws java.lang.IllegalArgumentException if {@code image} is {@code null}.
*
* @see java.awt.image.BufferedImage#getType()
*/
public static int getCompatibleBufferedImageType(final BufferedImage image) {
Validate.notNull(image, "image");
WritableRaster raster = image.getRaster();
SampleModel sm = raster.getSampleModel();
int numBands = raster.getNumBands();
ColorModel cm = image.getColorModel();
ColorSpace cs = cm.getColorSpace();
boolean isAlphaPre = cm.isAlphaPremultiplied();
int csType = cs.getType();
int dataType = raster.getDataBuffer().getDataType();
if (csType != ColorSpace.TYPE_RGB) {
if (csType == ColorSpace.TYPE_GRAY && cm instanceof ComponentColorModel) {
if (sm instanceof ComponentSampleModel && ((ComponentSampleModel) sm).getPixelStride() != numBands) {
return BufferedImage.TYPE_CUSTOM;
}
else if (dataType == DataBuffer.TYPE_BYTE && raster.getNumBands() == 1 &&
cm.getComponentSize(0) == 8 && ((ComponentSampleModel) sm).getPixelStride() == 1) {
return BufferedImage.TYPE_BYTE_GRAY;
}
else if (dataType == DataBuffer.TYPE_USHORT && raster.getNumBands() == 1 &&
cm.getComponentSize(0) == 16 && ((ComponentSampleModel) sm).getPixelStride() == 1) {
return BufferedImage.TYPE_USHORT_GRAY;
}
}
else {
return BufferedImage.TYPE_CUSTOM;
}
}
if ((dataType == DataBuffer.TYPE_INT) && (numBands == 3 || numBands == 4)) {
// Check if the raster params and the color model are correct
int pixSize = cm.getPixelSize();
if (cm instanceof DirectColorModel && sm.getNumDataElements() == 1 && (pixSize == 32 || pixSize == 24)) {
// Now check on the DirectColorModel params
DirectColorModel dcm = (DirectColorModel) cm;
int rmask = dcm.getRedMask();
int gmask = dcm.getGreenMask();
int bmask = dcm.getBlueMask();
if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK && bmask == DCM_BLUE_MASK) {
if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
return isAlphaPre ? BufferedImage.TYPE_INT_ARGB_PRE : BufferedImage.TYPE_INT_ARGB;
}
else if (!dcm.hasAlpha()) {
// No Alpha
return BufferedImage.TYPE_INT_RGB;
}
}
else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK && bmask == DCM_BGR_BLU_MASK) {
if (!dcm.hasAlpha()) {
return BufferedImage.TYPE_INT_BGR;
}
}
}
}
else if ((cm instanceof IndexColorModel) && (numBands == 1) && (!cm.hasAlpha() || !isAlphaPre)) {
IndexColorModel icm = (IndexColorModel) cm;
int pixSize = icm.getPixelSize();
if (dataType == DataBuffer.TYPE_BYTE && sm instanceof MultiPixelPackedSampleModel) {
return BufferedImage.TYPE_BYTE_BINARY;
}
if (dataType == DataBuffer.TYPE_BYTE && sm instanceof ComponentSampleModel) {
ComponentSampleModel csm = (ComponentSampleModel) sm;
if (csm.getPixelStride() == 1 && pixSize <= 8) {
return BufferedImage.TYPE_BYTE_INDEXED;
}
}
}
else if ((dataType == DataBuffer.TYPE_USHORT) &&
(cm instanceof DirectColorModel) && (numBands == 3) && !cm.hasAlpha()) {
DirectColorModel dcm = (DirectColorModel) cm;
if (dcm.getRedMask() == DCM_565_RED_MASK &&
dcm.getGreenMask() == DCM_565_GRN_MASK && dcm.getBlueMask() == DCM_565_BLU_MASK) {
return BufferedImage.TYPE_USHORT_565_RGB;
}
else if (dcm.getRedMask() == DCM_555_RED_MASK &&
dcm.getGreenMask() == DCM_555_GRN_MASK && dcm.getBlueMask() == DCM_555_BLU_MASK) {
return BufferedImage.TYPE_USHORT_555_RGB;
}
}
else if (dataType == DataBuffer.TYPE_BYTE && cm instanceof ComponentColorModel &&
raster.getSampleModel() instanceof PixelInterleavedSampleModel && (numBands == 3 || numBands == 4)) {
ComponentColorModel ccm = (ComponentColorModel) cm;
PixelInterleavedSampleModel csm = (PixelInterleavedSampleModel) raster.getSampleModel();
int[] offs = csm.getBandOffsets();
int[] nBits = ccm.getComponentSize();
boolean is8bit = true;
for (int i = 0; i < numBands; i++) {
if (nBits[i] != 8) {
is8bit = false;
break;
}
}
if (is8bit && csm.getPixelStride() == numBands &&
offs[0] == numBands - 1 && offs[1] == numBands - 2 && offs[2] == numBands - 3) {
if (numBands == 3 && !ccm.hasAlpha()) {
return BufferedImage.TYPE_3BYTE_BGR;
}
else if (offs[3] == 0 && ccm.hasAlpha()) {
return isAlphaPre ? BufferedImage.TYPE_4BYTE_ABGR_PRE : BufferedImage.TYPE_4BYTE_ABGR;
}
}
}
return BufferedImage.TYPE_CUSTOM;
}
private static RasterFactory createRasterFactory() {
try {
// Try to instantiate, will throw LinkageError if it fails
return new SunRasterFactory();
}
catch (LinkageError e) {
if (DEBUG) {
e.printStackTrace();
}
System.err.println("Could not instantiate SunWritableRaster, falling back to GenericWritableRaster.");
}
// Fall back
return new GenericRasterFactory();
}
static interface RasterFactory {
WritableRaster createRaster(SampleModel model, DataBuffer buffer, Point origin);
}
/**
* Generic implementation that should work for any JRE, and creates a custom subclass of {@link WritableRaster}.
*/
static final class GenericRasterFactory implements RasterFactory {
public WritableRaster createRaster(final SampleModel model, final DataBuffer buffer, final Point origin) {
return new GenericWritableRaster(model, buffer, origin);
}
}
/**
* Sun/Oracle JRE-specific implementation that creates {@code sun.awt.image.SunWritableRaster}.
* Callers must catch {@link LinkageError}.
*/
static final class SunRasterFactory implements RasterFactory {
final private Constructor<WritableRaster> factoryMethod = getFactoryMethod();
@SuppressWarnings("unchecked")
private static Constructor<WritableRaster> getFactoryMethod() {
try {
Class<?> cls = Class.forName("sun.awt.image.SunWritableRaster");
if (Modifier.isAbstract(cls.getModifiers())) {
throw new IncompatibleClassChangeError("sun.awt.image.SunWritableRaster has become abstract and can't be instantiated");
}
return (Constructor<WritableRaster>) cls.getConstructor(SampleModel.class, DataBuffer.class, Point.class);
}
catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(e.getMessage());
}
catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
public WritableRaster createRaster(final SampleModel model, final DataBuffer buffer, final Point origin) {
try {
return factoryMethod.newInstance(model, buffer, origin);
}
catch (InstantiationException e) {
throw new Error("Could not create SunWritableRaster: ", e); // Should never happen, as we test for abstract class
}
catch (IllegalAccessException e) {
throw new Error("Could not create SunWritableRaster: ", e); // Should never happen, only public constructors are reflected
}
catch (InvocationTargetException e) {
// Unwrap to allow normal exception flow
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
else if (cause instanceof Error) {
throw (Error) cause;
}
throw new UndeclaredThrowableException(cause);
}
}
}
}

View File

@@ -1,228 +0,0 @@
/*
* 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.
*/
/*
Copyright 2006 Jerry Huxtable
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.twelvemonkeys.image;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.Random;
/**
* NoiseFilter
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: NoiseFilter.java,v 1.0 15.06.12 22:59 haraldk Exp$
*/
public class NoiseFilter extends AbstractFilter {
/**
* Gaussian distribution for the noise.
*/
public final static int GAUSSIAN = 0;
/**
* Uniform distribution for the noise.
*/
public final static int UNIFORM = 1;
private int amount = 25;
private int distribution = UNIFORM;
private boolean monochrome = false;
private float density = 1;
private Random randomNumbers = new Random();
public NoiseFilter() {
}
/**
* Set the amount of effect.
*
* @param amount the amount
* @min-value 0
* @max-value 1
* @see #getAmount
*/
public void setAmount(int amount) {
this.amount = amount;
}
/**
* Get the amount of noise.
*
* @return the amount
* @see #setAmount
*/
public int getAmount() {
return amount;
}
/**
* Set the distribution of the noise.
*
* @param distribution the distribution
* @see #getDistribution
*/
public void setDistribution(int distribution) {
this.distribution = distribution;
}
/**
* Get the distribution of the noise.
*
* @return the distribution
* @see #setDistribution
*/
public int getDistribution() {
return distribution;
}
/**
* Set whether to use monochrome noise.
*
* @param monochrome true for monochrome noise
* @see #getMonochrome
*/
public void setMonochrome(boolean monochrome) {
this.monochrome = monochrome;
}
/**
* Get whether to use monochrome noise.
*
* @return true for monochrome noise
* @see #setMonochrome
*/
public boolean getMonochrome() {
return monochrome;
}
/**
* Set the density of the noise.
*
* @param density the density
* @see #getDensity
*/
public void setDensity(float density) {
this.density = density;
}
/**
* Get the density of the noise.
*
* @return the density
* @see #setDensity
*/
public float getDensity() {
return density;
}
private int random() {
return (int) (((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2 * randomNumbers.nextFloat() - 1)) * amount);
}
private static int clamp(int x) {
if (x < 0) {
return 0;
}
else if (x > 0xff) {
return 0xff;
}
return x;
}
public int filterRGB(int x, int y, int rgb) {
if (randomNumbers.nextFloat() <= density) {
int a = rgb & 0xff000000;
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
if (monochrome) {
int n = random();
r = clamp(r + n);
g = clamp(g + n);
b = clamp(b + n);
}
else {
r = clamp(r + random());
g = clamp(g + random());
b = clamp(b + random());
}
return a | (r << 16) | (g << 8) | b;
}
return rgb;
}
public BufferedImage filter(BufferedImage src, BufferedImage dst) {
int width = src.getWidth();
int height = src.getHeight();
int type = src.getType();
WritableRaster srcRaster = src.getRaster();
if (dst == null) {
dst = createCompatibleDestImage(src, null);
}
WritableRaster dstRaster = dst.getRaster();
int[] inPixels = new int[width];
for (int y = 0; y < height; y++) {
// We try to avoid calling getRGB on images as it causes them to become unmanaged, causing horrible performance problems.
if (type == BufferedImage.TYPE_INT_ARGB) {
srcRaster.getDataElements(0, y, width, 1, inPixels);
for (int x = 0; x < width; x++) {
inPixels[x] = filterRGB(x, y, inPixels[x]);
}
dstRaster.setDataElements(0, y, width, 1, inPixels);
}
else {
src.getRGB(0, y, width, 1, inPixels, 0, width);
for (int x = 0; x < width; x++) {
inPixels[x] = filterRGB(x, y, inPixels[x]);
}
dst.setRGB(0, y, width, 1, inPixels, 0, width);
}
}
return dst;
}
}

View File

@@ -1,163 +0,0 @@
/*
* 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 javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
/**
* SubsampleTester
*
* @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/image/SubsampleTester.java#1 $
*/
public class SubsampleTester {
// Initial testing shows we need at least 9 pixels (sampleFactor == 3) to make a good looking image..
// Also, using Lanczos is much better than (and allmost as fast as) halving using AffineTransform
// - But I guess those numbers depend on the data type of the input image...
public static void main(String[] pArgs) throws IOException {
// To/from larger than or equal to 4x4
//ImageUtil.createResampled(new BufferedImage(5, 5, BufferedImage.TYPE_INT_ARGB), 4, 4, BufferedImage.SCALE_SMOOTH);
//ImageUtil.createResampled(new BufferedImage(4, 4, BufferedImage.TYPE_INT_ARGB), 5, 5, BufferedImage.SCALE_SMOOTH);
// To/from smaller than or equal to 4x4 with fast scale
//ImageUtil.createResampled(new BufferedImage(3, 3, BufferedImage.TYPE_INT_ARGB), 10, 10, BufferedImage.SCALE_FAST);
//ImageUtil.createResampled(new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB), 3, 3, BufferedImage.SCALE_FAST);
// To/from smaller than or equal to 4x4 with default scale
//ImageUtil.createResampled(new BufferedImage(3, 3, BufferedImage.TYPE_INT_ARGB), 10, 10, BufferedImage.SCALE_DEFAULT);
//ImageUtil.createResampled(new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB), 3, 3, BufferedImage.SCALE_DEFAULT);
// To/from smaller than or equal to 4x4 with smooth scale
try {
ImageUtil.createResampled(new BufferedImage(3, 3, BufferedImage.TYPE_INT_ARGB), 10, 10, BufferedImage.SCALE_SMOOTH);
}
catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
//try {
// ImageUtil.createResampled(new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB), 3, 3, BufferedImage.SCALE_SMOOTH);
//}
//catch (IndexOutOfBoundsException e) {
// e.printStackTrace();
// return;
//}
File input = new File(pArgs[0]);
ImageInputStream stream = ImageIO.createImageInputStream(input);
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if (readers.hasNext()) {
if (stream == null) {
return;
}
ImageReader reader = readers.next();
reader.setInput(stream);
ImageReadParam param = reader.getDefaultReadParam();
for (int i = 0; i < 25; i++) {
//readImage(pArgs, reader, param);
}
long start = System.currentTimeMillis();
BufferedImage image = readImage(pArgs, reader, param);
long end = System.currentTimeMillis();
System.out.println("elapsed time: " + (end - start) + " ms");
int subX = param.getSourceXSubsampling();
int subY = param.getSourceYSubsampling();
System.out.println("image: " + image);
//ImageIO.write(image, "png", new File(input.getParentFile(), input.getName().replace('.', '_') + "_new.png"));
ConvolveTester.showIt(image, input.getName() + (subX > 1 || subY > 1 ? " (subsampled " + subX + " by " + subY + ")" : ""));
}
else {
System.err.println("No reader found for input: " + input.getAbsolutePath());
}
}
private static BufferedImage readImage(final String[] pArgs, final ImageReader pReader, final ImageReadParam pParam) throws IOException {
double sampleFactor; // Minimum number of samples (in each dimension) pr pixel in output
int width = pArgs.length > 1 ? Integer.parseInt(pArgs[1]) : 300;
int height = pArgs.length > 2 ? Integer.parseInt(pArgs[2]) : 200;
if (pArgs.length > 3 && (sampleFactor = Double.parseDouble(pArgs[3])) > 0) {
int originalWidth = pReader.getWidth(0);
int originalHeight = pReader.getHeight(0);
System.out.println("originalWidth: " + originalWidth);
System.out.println("originalHeight: " + originalHeight);
int subX = (int) Math.max(originalWidth / (double) (width * sampleFactor), 1.0);
int subY = (int) Math.max(originalHeight / (double) (height * sampleFactor), 1.0);
if (subX > 1 || subY > 1) {
System.out.println("subX: " + subX);
System.out.println("subY: " + subY);
pParam.setSourceSubsampling(subX, subY, subX > 1 ? subX / 2 : 0, subY > 1 ? subY / 2 : 0);
}
}
BufferedImage image = pReader.read(0, pParam);
System.out.println("image: " + image);
int algorithm = BufferedImage.SCALE_DEFAULT;
if (pArgs.length > 4) {
if ("smooth".equals(pArgs[4].toLowerCase())) {
algorithm = BufferedImage.SCALE_SMOOTH;
}
else if ("fast".equals(pArgs[4].toLowerCase())) {
algorithm = BufferedImage.SCALE_FAST;
}
}
if (image.getWidth() != width || image.getHeight() != height) {
image = ImageUtil.createScaled(image, width, height, algorithm);
}
return image;
}
}

View File

@@ -1,524 +0,0 @@
/*
* 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;
}

View File

@@ -1,64 +0,0 @@
/*
* 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");
}
}
}

View File

@@ -1,57 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,87 +0,0 @@
package com.twelvemonkeys.io;
import com.twelvemonkeys.lang.Validate;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
/**
* An {@code InputStream} that reads bytes from a {@code String}.
*
* This class properly converts characters into bytes using a {@code Charset},
* unlike the deprecated {@link java.io.StringBufferInputStream}.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: StringInputStream.java,v 1.0 03.09.13 10:19 haraldk Exp$
*/
public final class StringInputStream extends InputStream {
private final CharBuffer chars;
private final CharsetEncoder encoder;
private final ByteBuffer buffer;
public StringInputStream(final String string, final Charset charset) {
this(Validate.notNull(string, "string"), 0, string.length(), charset);
}
public StringInputStream(final String string, int offset, int length, final Charset charset) {
chars = CharBuffer.wrap(Validate.notNull(string, "string"), offset, offset + length);
encoder = Validate.notNull(charset, "charset").newEncoder();
buffer = ByteBuffer.allocate(256);
buffer.flip();
}
private boolean fillBuffer() {
buffer.clear();
encoder.encode(chars, buffer, chars.hasRemaining()); // TODO: Do we have to care about the result?
buffer.flip();
return buffer.hasRemaining();
}
private boolean ensureBuffer() {
return buffer.hasRemaining() || (chars.hasRemaining() && fillBuffer());
}
@Override
public int read() throws IOException {
if (!ensureBuffer()) {
return -1;
}
return buffer.get() & 0xff;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (!ensureBuffer()) {
return -1;
}
int count = Math.min(buffer.remaining(), len);
buffer.get(b, off, count);
return count;
}
@Override
public long skip(long len) throws IOException {
if (!ensureBuffer()) {
return -1;
}
int count = (int) Math.min(buffer.remaining(), len);
int position = buffer.position();
buffer.position(position + count);
return count;
}
@Override
public int available() throws IOException {
return buffer.remaining();
}
}

View File

@@ -1,90 +0,0 @@
/*
* 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;
import java.nio.ByteBuffer;
import java.util.zip.Deflater;
/**
* {@code Encoder} implementation for standard DEFLATE encoding.
* <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/DeflateEncoder.java#2 $
*
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
* @see Deflater
* @see InflateDecoder
* @see java.util.zip.DeflaterOutputStream
*/
final class DeflateEncoder implements Encoder {
private final Deflater deflater;
private final byte[] buffer = new byte[1024];
public DeflateEncoder() {
this(new Deflater(Deflater.DEFAULT_COMPRESSION, true)); // TODO: Should we use "no wrap"?
}
public DeflateEncoder(final Deflater pDeflater) {
if (pDeflater == null) {
throw new IllegalArgumentException("deflater == null");
}
deflater = pDeflater;
}
public void encode(final OutputStream stream, ByteBuffer buffer)
throws IOException
{
System.out.println("DeflateEncoder.encode");
deflater.setInput(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
flushInputToStream(stream);
}
private void flushInputToStream(final OutputStream pStream) throws IOException {
System.out.println("DeflateEncoder.flushInputToStream");
if (deflater.needsInput()) {
System.out.println("Foo");
}
while (!deflater.needsInput()) {
int deflated = deflater.deflate(buffer, 0, buffer.length);
pStream.write(buffer, 0, deflated);
System.out.println("flushed " + deflated);
}
}
// public void flush() {
// deflater.finish();
// }
}

View File

@@ -1,110 +0,0 @@
/*
* 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.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
/**
* {@code Decoder} implementation for standard DEFLATE encoding.
* <p/>
*
* @see <a href="http://tools.ietf.org/html/rfc1951">RFC 1951</a>
*
* @see Inflater
* @see DeflateEncoder
* @see java.util.zip.InflaterInputStream
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/InflateDecoder.java#2 $
*/
final class InflateDecoder implements Decoder {
private final Inflater inflater;
private final byte[] buffer;
/**
* Creates an {@code InflateDecoder}
*
*/
public InflateDecoder() {
this(new Inflater(true));
}
/**
* Creates an {@code InflateDecoder}
*
* @param pInflater the inflater instance to use
*/
public InflateDecoder(final Inflater pInflater) {
if (pInflater == null) {
throw new IllegalArgumentException("inflater == null");
}
inflater = pInflater;
buffer = new byte[1024];
}
public int decode(final InputStream stream, final ByteBuffer buffer) throws IOException {
try {
int decoded;
while ((decoded = inflater.inflate(buffer.array(), buffer.arrayOffset(), buffer.capacity())) == 0) {
if (inflater.finished() || inflater.needsDictionary()) {
return 0;
}
if (inflater.needsInput()) {
fill(stream);
}
}
return decoded;
}
catch (DataFormatException e) {
String message = e.getMessage();
throw new DecodeException(message != null ? message : "Invalid ZLIB data format", e);
}
}
private void fill(final InputStream pStream) throws IOException {
int available = pStream.read(buffer, 0, buffer.length);
if (available == -1) {
throw new EOFException("Unexpected end of ZLIB stream");
}
inflater.setInput(buffer, 0, available);
}
}

View File

@@ -1,468 +0,0 @@
/*
* 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());
}
}
}

View File

@@ -1,89 +0,0 @@
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);
}
}

View File

@@ -1,138 +0,0 @@
/*
* 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;
/**
* The class MathUtil contains methods for performing basic numeric operations
* such as the elementary exponential, logarithm, square root, and
* trigonometric functions.
*
* @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/MathUtil.java#1 $
*/
public final class MathUtil {
/** */
private MathUtil() {
}
/**
* Returns the natural logarithm (base <I>e</I>) of a double value.
* Equivalent to {@code java.lang.Math.log}, just with a proper name.
*
* @param pArg a number greater than 0.0.
* @return the value ln {@code pArg}, the natural logarithm of
* {@code pArg}.
*
* @see java.lang.Math#log(double)
*/
public static double ln(final double pArg) {
return Math.log(pArg);
}
/**
* Returns the base 10 logarithm of a double value.
*
* @param pArg a number greater than 0.0.
* @return the value log {@code pArg}, the base 10 logarithm of
* {@code pArg}.
*/
public static double log(final double pArg) {
return Math.log10(pArg);
}
private final static double LN_2 = Math.log(2);
/**
* Returns the base 2 logarithm of a double value.
*
* @param pArg a number greater than 0.0.
* @return the value log<SUB>2</SUB> {@code pArg}, the base 2
* logarithm of {@code pArg}.
*/
public static double log2(final double pArg) {
return Math.log(pArg) / LN_2;
}
/**
* Returns the base <i>N</i> logarithm of a double value, for a given base
* <i>N</i>.
*
* @param pArg a number greater than 0.0.
* @param pBase a number greater than 0.0.
*
* @return the value log<SUB>pBase</SUB> {@code pArg}, the base
* {@code pBase} logarithm of {@code pArg}.
*/
public static double log(final double pArg, final double pBase) {
return Math.log(pArg) / Math.log(pBase);
}
/**
* A replacement for {@code Math.abs}, that never returns negative values.
* {@code Math.abs(long)} does this for {@code Long.MIN_VALUE}.
*
* @see Math#abs(long)
* @see Long#MIN_VALUE
*
* @param pNumber a number
* @return the absolute value of {@code pNumber}
*
* @throws ArithmeticException if {@code pNumber == Long.MIN_VALUE}
*/
public static long abs(final long pNumber) {
if (pNumber == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow: 9223372036854775808");
}
return (pNumber < 0) ? -pNumber : pNumber;
}
/**
* A replacement for {@code Math.abs}, that never returns negative values.
* {@code Math.abs(int)} does this for {@code Integer.MIN_VALUE}.
*
* @see Math#abs(int)
* @see Integer#MIN_VALUE
*
* @param pNumber a number
* @return the absolute value of {@code pNumber}
*
* @throws ArithmeticException if {@code pNumber == Integer.MIN_VALUE}
*/
public static int abs(final int pNumber) {
if (pNumber == Integer.MIN_VALUE) {
throw new ArithmeticException("int overflow: 2147483648");
}
return (pNumber < 0) ? -pNumber : pNumber;
}
}

View File

@@ -1,55 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,401 +0,0 @@
/*
* 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 com.twelvemonkeys.io.FileUtil;
import com.twelvemonkeys.util.FilterIterator;
import com.twelvemonkeys.util.service.ServiceRegistry;
import java.io.*;
import java.util.Collections;
import java.util.Iterator;
/**
* NativeLoader
* <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/NativeLoader.java#2 $
*/
final class NativeLoader {
// TODO: Considerations:
// - Rename all libs like the current code, to <library>.(so|dll|dylib)?
// - Keep library filename from jar, and rather store a separate
// properties-file with the library->library-file mappings?
// - As all invocations are with library file name, we could probably skip
// both renaming and properties-file altogether...
// TODO: The real trick here, is how to load the correct library for the
// current platform...
// - Change String pResource to String[] pResources?
// - NativeResource class, that has a list of multiple resources?
// NativeResource(Map<String, String>) os->native lib mapping
// TODO: Consider exposing the method from SystemUtil
// TODO: How about a SPI based solution?!
// public interface com.twelvemonkeys.lang.NativeResourceProvider
//
// imlementations return a pointer to the correct resource for a given (by
// this class) OS.
//
// String getResourceName(...)
//
// See http://tolstoy.com/samizdat/sysprops.html
// System properties:
// "os.name"
// Windows, Linux, Solaris/SunOS,
// Mac OS/Mac OS X/Rhapsody (aka Mac OS X Server)
// General Unix (AIX, Digital Unix, FreeBSD, HP-UX, Irix)
// OS/2
// "os.arch"
// Windows: x86
// Linux: x86, i386, i686, x86_64, ia64,
// Solaris: sparc, sparcv9, x86
// Mac OS: PowerPC, ppc, i386
// AIX: x86, ppc
// Digital Unix: alpha
// FreeBSD: x86, sparc
// HP-UX: PA-RISC
// Irix: mips
// OS/2: x86
// "os.version"
// Windows: 4.0 -> NT/95, 5.0 -> 2000, 5.1 -> XP (don't care about old versions, CE etc)
// Mac OS: 8.0, 8.1, 10.0 -> OS X, 10.x.x -> OS X, 5.6 -> Rhapsody (!)
//
// Normalize os.name, os.arch and os.version?!
///** Normalized operating system constant */
//static final OperatingSystem OS_NAME = normalizeOperatingSystem();
//
///** Normalized system architecture constant */
//static final Architecture OS_ARCHITECTURE = normalizeArchitecture();
//
///** Unormalized operating system version constant (for completeness) */
//static final String OS_VERSION = System.getProperty("os.version");
static final NativeResourceRegistry sRegistry = new NativeResourceRegistry();
private NativeLoader() {
}
/*
private static Architecture normalizeArchitecture() {
String arch = System.getProperty("os.arch");
if (arch == null) {
throw new IllegalStateException("System property \"os.arch\" == null");
}
arch = arch.toLowerCase();
if (OS_NAME == OperatingSystem.Windows
&& (arch.startsWith("x86") || arch.startsWith("i386"))) {
return Architecture.X86;
// TODO: 64 bit
}
else if (OS_NAME == OperatingSystem.Linux) {
if (arch.startsWith("x86") || arch.startsWith("i386")) {
return Architecture.I386;
}
else if (arch.startsWith("i686")) {
return Architecture.I686;
}
// TODO: More Linux options?
// TODO: 64 bit
}
else if (OS_NAME == OperatingSystem.MacOS) {
if (arch.startsWith("power") || arch.startsWith("ppc")) {
return Architecture.PPC;
}
else if (arch.startsWith("i386")) {
return Architecture.I386;
}
}
else if (OS_NAME == OperatingSystem.Solaris) {
if (arch.startsWith("sparc")) {
return Architecture.SPARC;
}
if (arch.startsWith("x86")) {
// TODO: Should we use i386 as Linux and Mac does?
return Architecture.X86;
}
// TODO: 64 bit
}
return Architecture.Unknown;
}
*/
/*
private static OperatingSystem normalizeOperatingSystem() {
String os = System.getProperty("os.name");
if (os == null) {
throw new IllegalStateException("System property \"os.name\" == null");
}
os = os.toLowerCase();
if (os.startsWith("windows")) {
return OperatingSystem.Windows;
}
else if (os.startsWith("linux")) {
return OperatingSystem.Linux;
}
else if (os.startsWith("mac os")) {
return OperatingSystem.MacOS;
}
else if (os.startsWith("solaris") || os.startsWith("sunos")) {
return OperatingSystem.Solaris;
}
return OperatingSystem.Unknown;
}
*/
// TODO: We could actually have more than one resource for each lib...
private static String getResourceFor(String pLibrary) {
Iterator<NativeResourceSPI> providers = sRegistry.providers(pLibrary);
while (providers.hasNext()) {
NativeResourceSPI resourceSPI = providers.next();
try {
return resourceSPI.getClassPathResource(Platform.get());
}
catch (Throwable t) {
// Dergister and try next
sRegistry.deregister(resourceSPI);
}
}
return null;
}
/**
* Loads a native library.
*
* @param pLibrary name of the library
*
* @throws UnsatisfiedLinkError
*/
public static void loadLibrary(String pLibrary) {
loadLibrary0(pLibrary, null, null);
}
/**
* Loads a native library.
*
* @param pLibrary name of the library
* @param pLoader the class loader to use
*
* @throws UnsatisfiedLinkError
*/
public static void loadLibrary(String pLibrary, ClassLoader pLoader) {
loadLibrary0(pLibrary, null, pLoader);
}
/**
* Loads a native library.
*
* @param pLibrary name of the library
* @param pResource name of the resource
* @param pLoader the class loader to use
*
* @throws UnsatisfiedLinkError
*/
static void loadLibrary0(String pLibrary, String pResource, ClassLoader pLoader) {
if (pLibrary == null) {
throw new IllegalArgumentException("library == null");
}
// Try loading normal way
UnsatisfiedLinkError unsatisfied;
try {
System.loadLibrary(pLibrary);
return;
}
catch (UnsatisfiedLinkError err) {
// Ignore
unsatisfied = err;
}
final ClassLoader loader = pLoader != null ? pLoader : Thread.currentThread().getContextClassLoader();
final String resource = pResource != null ? pResource : getResourceFor(pLibrary);
// TODO: resource may be null, and that MIGHT be okay, IFF the resource
// is allready unpacked to the user dir... However, we then need another
// way to resolve the library extension...
// Right now we just fail in a predictable way (no NPE)!
if (resource == null) {
throw unsatisfied;
}
// Default to load/store from user.home
File dir = new File(System.getProperty("user.home") + "/.twelvemonkeys/lib");
dir.mkdirs();
//File libraryFile = new File(dir.getAbsolutePath(), pLibrary + LIBRARY_EXTENSION);
File libraryFile = new File(dir.getAbsolutePath(), pLibrary + "." + FileUtil.getExtension(resource));
if (!libraryFile.exists()) {
try {
extractToUserDir(resource, libraryFile, loader);
}
catch (IOException ioe) {
UnsatisfiedLinkError err = new UnsatisfiedLinkError("Unable to extract resource to dir: " + libraryFile.getAbsolutePath());
err.initCause(ioe);
throw err;
}
}
// Try to load the library from the file we just wrote
System.load(libraryFile.getAbsolutePath());
}
private static void extractToUserDir(String pResource, File pLibraryFile, ClassLoader pLoader) throws IOException {
// Get resource from classpath
InputStream in = pLoader.getResourceAsStream(pResource);
if (in == null) {
throw new FileNotFoundException("Unable to locate classpath resource: " + pResource);
}
// Write to file in user dir
FileOutputStream fileOut = null;
try {
fileOut = new FileOutputStream(pLibraryFile);
byte[] tmp = new byte[1024];
// copy the contents of our resource out to the destination
// dir 1K at a time. 1K may seem arbitrary at first, but today
// is a Tuesday, so it makes perfect sense.
int bytesRead = in.read(tmp);
while (bytesRead != -1) {
fileOut.write(tmp, 0, bytesRead);
bytesRead = in.read(tmp);
}
}
finally {
FileUtil.close(fileOut);
FileUtil.close(in);
}
}
// TODO: Validate OS names?
// Windows
// Linux
// Solaris
// Mac OS (OSX+)
// Generic Unix?
// Others?
// TODO: OSes that support different architectures might require different
// resources for each architecture.. Need a namespace/flavour system
// TODO: 32 bit/64 bit issues?
// Eg: Windows, Windows/32, Windows/64, Windows/Intel/64?
// Solaris/Sparc, Solaris/Intel/64
// MacOS/PowerPC, MacOS/Intel
/*
public static class NativeResource {
private Map mMap;
public NativeResource(String[] pOSNames, String[] pReourceNames) {
if (pOSNames == null) {
throw new IllegalArgumentException("osNames == null");
}
if (pReourceNames == null) {
throw new IllegalArgumentException("resourceNames == null");
}
if (pOSNames.length != pReourceNames.length) {
throw new IllegalArgumentException("osNames.length != resourceNames.length");
}
Map map = new HashMap();
for (int i = 0; i < pOSNames.length; i++) {
map.put(pOSNames[i], pReourceNames[i]);
}
mMap = Collections.unmodifiableMap(map);
}
public NativeResource(Map pMap) {
if (pMap == null) {
throw new IllegalArgumentException("map == null");
}
Map map = new HashMap(pMap);
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
if (!(entry.getKey() instanceof String && entry.getValue() instanceof String)) {
throw new IllegalArgumentException("map contains non-string entries: " + entry);
}
}
mMap = Collections.unmodifiableMap(map);
}
protected NativeResource() {
}
public final String resourceForCurrentOS() {
throw new UnsupportedOperationException();
}
protected String getResourceName(String pOSName) {
return (String) mMap.get(pOSName);
}
}
*/
private static class NativeResourceRegistry extends ServiceRegistry {
public NativeResourceRegistry() {
super(Collections.singletonList(NativeResourceSPI.class).iterator());
registerApplicationClasspathSPIs();
}
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 name;
NameFilter(String pName) {
if (pName == null) {
throw new IllegalArgumentException("name == null");
}
name = pName;
}
public boolean accept(NativeResourceSPI pElement) {
return name.equals(pElement.getResourceName());
}
}
}

View File

@@ -1,99 +0,0 @@
/*
* 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);
}

View File

@@ -1,45 +0,0 @@
/*
* 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.net;
import java.net.*;
/**
* Interface for filtering Authenticator requests, used by the
* SimpleAuthenticator.
*
* @see SimpleAuthenticator
* @see java.net.Authenticator
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version 1.0
*/
public interface AuthenticatorFilter {
public boolean accept(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme);
}

View File

@@ -1,143 +0,0 @@
/*
* 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.net;
import com.twelvemonkeys.io.*;
import com.twelvemonkeys.io.enc.Base64Decoder;
import com.twelvemonkeys.io.enc.DecoderStream;
import java.io.*;
/**
* This class does BASE64 encoding (and decoding).
*
* @author unascribed
* @author last modified by $Author: haku $
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/BASE64.java#1 $
* @deprecated Use {@link com.twelvemonkeys.io.enc.Base64Encoder}/{@link Base64Decoder} instead
*/
class BASE64 {
/**
* This array maps the characters to their 6 bit values
*/
private final static char[] PEM_ARRAY = {
//0 1 2 3 4 5 6 7
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
'4', '5', '6', '7', '8', '9', '+', '/' // 7
};
/**
* Encodes the input data using the standard base64 encoding scheme.
*
* @param pData the bytes to encode to base64
* @return a string with base64 encoded data
*/
public static String encode(byte[] pData) {
int offset = 0;
int len;
StringBuilder buf = new StringBuilder();
while ((pData.length - offset) > 0) {
byte a, b, c;
if ((pData.length - offset) > 2) {
len = 3;
}
else {
len = pData.length - offset;
}
switch (len) {
case 1:
a = pData[offset];
b = 0;
buf.append(PEM_ARRAY[(a >>> 2) & 0x3F]);
buf.append(PEM_ARRAY[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
buf.append('=');
buf.append('=');
offset++;
break;
case 2:
a = pData[offset];
b = pData[offset + 1];
c = 0;
buf.append(PEM_ARRAY[(a >>> 2) & 0x3F]);
buf.append(PEM_ARRAY[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
buf.append(PEM_ARRAY[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
buf.append('=');
offset += offset + 2; // ???
break;
default:
a = pData[offset];
b = pData[offset + 1];
c = pData[offset + 2];
buf.append(PEM_ARRAY[(a >>> 2) & 0x3F]);
buf.append(PEM_ARRAY[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
buf.append(PEM_ARRAY[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
buf.append(PEM_ARRAY[c & 0x3F]);
offset = offset + 3;
break;
}
}
return buf.toString();
}
public static byte[] decode(String pData) throws IOException {
InputStream in = new DecoderStream(new ByteArrayInputStream(pData.getBytes()), new Base64Decoder());
ByteArrayOutputStream bytes = new FastByteArrayOutputStream(pData.length() * 3);
FileUtil.copy(in, bytes);
return bytes.toByteArray();
}
//private final static sun.misc.BASE64Decoder DECODER = new sun.misc.BASE64Decoder();
public static void main(String[] pArgs) throws IOException {
if (pArgs.length == 1) {
System.out.println(encode(pArgs[0].getBytes()));
}
else
if (pArgs.length == 2 && ("-d".equals(pArgs[0]) || "--decode".equals(pArgs[0])))
{
System.out.println(new String(decode(pArgs[1])));
}
else {
System.err.println("BASE64 [ -d | --decode ] arg");
System.err.println("Encodes or decodes a given string");
System.exit(5);
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* 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.net;
import java.net.*;
/**
* Interface fro PasswordAuthenticators used by SimpleAuthenticator.
*
* @see SimpleAuthenticator
* @see java.net.Authenticator
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*
* @version 1.0
*/
public interface PasswordAuthenticator {
public PasswordAuthentication requestPasswordAuthentication(InetAddress addr, int port, String protocol, String prompt, String scheme);
}

View File

@@ -1,270 +0,0 @@
/*
* 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.net;
import com.twelvemonkeys.lang.Validate;
import java.net.Authenticator;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* A simple Authenticator implementation.
* Singleton class, obtain reference through the static
* {@code getInstance} method.
* <p/>
* <EM>After swearing, sweating, pulling my hair, banging my head repeatedly
* into the walls and reading the java.net.Authenticator API documentation
* once more, an idea came to my mind. This is the result. I hope you find it
* useful. -- Harald K.</EM>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version 1.0
* @see java.net.Authenticator
*/
public class SimpleAuthenticator extends Authenticator {
/** The reference to the single instance of this class. */
private static SimpleAuthenticator sInstance = null;
/** Keeps track of the state of this class. */
private static boolean sInitialized = false;
// These are used for the identification hack.
private final static String MAGIC = "magic";
private final static int FOURTYTWO = 42;
/** Basic authentication scheme. */
public final static String BASIC = "Basic";
/** The hastable that keeps track of the PasswordAuthentications. */
protected Map<AuthKey, PasswordAuthentication> passwordAuthentications = null;
/** The hastable that keeps track of the Authenticators. */
protected Map<PasswordAuthenticator, AuthenticatorFilter> authenticators = null;
/** Creates a SimpleAuthenticator. */
private SimpleAuthenticator() {
passwordAuthentications = new HashMap<AuthKey, PasswordAuthentication>();
authenticators = new HashMap<PasswordAuthenticator, AuthenticatorFilter>();
}
/**
* Gets the SimpleAuthenticator instance and registers it through the
* Authenticator.setDefault(). If there is no current instance
* of the SimpleAuthenticator in the VM, one is created. This method will
* try to figure out if the setDefault() succeeded (a hack), and will
* return null if it was not able to register the instance as default.
*
* @return The single instance of this class, or null, if another
* Authenticator is allready registered as default.
*/
public static synchronized SimpleAuthenticator getInstance() {
if (!sInitialized) {
// Create an instance
sInstance = new SimpleAuthenticator();
// Try to set default (this may quietly fail...)
Authenticator.setDefault(sInstance);
// A hack to figure out if we really did set the authenticator
PasswordAuthentication pa = Authenticator.requestPasswordAuthentication(null, FOURTYTWO, null, null, MAGIC);
// If this test returns false, we didn't succeed, so we set the
// instance back to null.
if (pa == null || !MAGIC.equals(pa.getUserName()) || !("" + FOURTYTWO).equals(new String(pa.getPassword()))) {
sInstance = null;
}
// Done
sInitialized = true;
}
return sInstance;
}
/**
* Gets the PasswordAuthentication for the request. Called when password
* authorization is needed.
*
* @return The PasswordAuthentication collected from the user, or null if
* none is provided.
*/
protected PasswordAuthentication getPasswordAuthentication() {
// Don't worry, this is just a hack to figure out if we were able
// to set this Authenticator through the setDefault method.
if (!sInitialized && MAGIC.equals(getRequestingScheme()) && getRequestingPort() == FOURTYTWO) {
return new PasswordAuthentication(MAGIC, ("" + FOURTYTWO).toCharArray());
}
/*
System.err.println("getPasswordAuthentication");
System.err.println(getRequestingSite());
System.err.println(getRequestingPort());
System.err.println(getRequestingProtocol());
System.err.println(getRequestingPrompt());
System.err.println(getRequestingScheme());
*/
// TODO:
// Look for a more specific PasswordAuthenticatior before using
// Default:
//
// if (...)
// return pa.requestPasswordAuthentication(getRequestingSite(),
// getRequestingPort(),
// getRequestingProtocol(),
// getRequestingPrompt(),
// getRequestingScheme());
return passwordAuthentications.get(new AuthKey(getRequestingSite(),
getRequestingPort(),
getRequestingProtocol(),
getRequestingPrompt(),
getRequestingScheme()));
}
/** Registers a PasswordAuthentication with a given URL address. */
public PasswordAuthentication registerPasswordAuthentication(URL pURL, PasswordAuthentication pPA) {
return registerPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL),
pURL.getPort(),
pURL.getProtocol(),
null, // Prompt/Realm
BASIC,
pPA);
}
/** Registers a PasswordAuthentication with a given net address. */
public PasswordAuthentication registerPasswordAuthentication(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme, PasswordAuthentication pPA) {
/*
System.err.println("registerPasswordAuthentication");
System.err.println(pAddress);
System.err.println(pPort);
System.err.println(pProtocol);
System.err.println(pPrompt);
System.err.println(pScheme);
*/
return passwordAuthentications.put(new AuthKey(pAddress, pPort, pProtocol, pPrompt, pScheme), pPA);
}
/** Unregisters a PasswordAuthentication with a given URL address. */
public PasswordAuthentication unregisterPasswordAuthentication(URL pURL) {
return unregisterPasswordAuthentication(NetUtil.createInetAddressFromURL(pURL), pURL.getPort(), pURL.getProtocol(), null, BASIC);
}
/** Unregisters a PasswordAuthentication with a given net address. */
public PasswordAuthentication unregisterPasswordAuthentication(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme) {
return passwordAuthentications.remove(new AuthKey(pAddress, pPort, pProtocol, pPrompt, pScheme));
}
/**
* TODO: Registers a PasswordAuthenticator that can answer authentication
* requests.
*
* @see PasswordAuthenticator
*/
public void registerPasswordAuthenticator(PasswordAuthenticator pPA, AuthenticatorFilter pFilter) {
authenticators.put(pPA, pFilter);
}
/**
* TODO: Unregisters a PasswordAuthenticator that can answer authentication
* requests.
*
* @see PasswordAuthenticator
*/
public void unregisterPasswordAuthenticator(PasswordAuthenticator pPA) {
authenticators.remove(pPA);
}
}
/**
* Utility class, used for caching the PasswordAuthentication objects.
* Everything but address may be null
*/
class AuthKey {
// TODO: Move this class to sandbox?
InetAddress address = null;
int port = -1;
String protocol = null;
String prompt = null;
String scheme = null;
AuthKey(InetAddress pAddress, int pPort, String pProtocol, String pPrompt, String pScheme) {
Validate.notNull(pAddress, "address");
address = pAddress;
port = pPort;
protocol = pProtocol;
prompt = pPrompt;
scheme = pScheme;
// System.out.println("Created: " + this);
}
/** Creates a string representation of this object. */
public String toString() {
return "AuthKey[" + address + ":" + port + "/" + protocol + " \"" + prompt + "\" (" + scheme + ")]";
}
public boolean equals(Object pObj) {
return (pObj instanceof AuthKey && equals((AuthKey) pObj));
}
// Ahem.. Breaks the rule from Object.equals(Object):
// It is transitive: for any reference values x, y, and z, if x.equals(y)
// returns true and y.equals(z) returns true, then x.equals(z)
// should return true.
public boolean equals(AuthKey pKey) {
// Maybe allow nulls, and still be equal?
return (address.equals(pKey.address)
&& (port == -1
|| pKey.port == -1
|| port == pKey.port)
&& (protocol == null
|| pKey.protocol == null
|| protocol.equals(pKey.protocol))
&& (prompt == null
|| pKey.prompt == null
|| prompt.equals(pKey.prompt))
&& (scheme == null
|| pKey.scheme == null
|| scheme.equalsIgnoreCase(pKey.scheme)));
}
public int hashCode() {
// There won't be too many pr address, will it? ;-)
return address.hashCode();
}
}

View File

@@ -1,247 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,126 +0,0 @@
/*
* 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
}
}

View File

@@ -1,70 +0,0 @@
/*
* 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();
}

View File

@@ -1,173 +0,0 @@
/*
* 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/";
}
}
}

View File

@@ -1,673 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,276 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,663 +0,0 @@
/*
* 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);
}
}
}
}

View File

@@ -1,879 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,396 +0,0 @@
/*
* 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);
}
}
}

View File

@@ -1,12 +0,0 @@
<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>

View File

@@ -1,92 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,52 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,78 +0,0 @@
/*
* 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();
}
}

View File

@@ -1,52 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,51 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,456 +0,0 @@
/*
* 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);
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,334 +0,0 @@
/*
* 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.io.FileUtil;
import java.io.*;
import java.util.*;
import static com.twelvemonkeys.lang.Validate.notNull;
/**
* 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<K extends Serializable, V extends Serializable> extends AbstractMap<K, V>{
public static final FileFilter DIRECTORIES = new FileFilter() {
public boolean accept(File file) {
return file.isDirectory();
}
@Override
public String toString() {
return "[All folders]";
}
};
private static final String INDEX = ".index";
private final File root;
private final Map<K, UUID> index = new LinkedHashMap<K, UUID>();
private boolean mutable = true;
// Idea 2.0:
// - Create directory per hashCode
// - Create file per object in that directory
// - Name file after serialized form of key? Base64?
// - Special case for String/Integer/Long etc?
// - Or create index file in directory with serialized objects + name (uuid) of file
// TODO: Consider single index file? Or a few? In root directory instead of each directory
// Consider a RAF/FileChannel approach instead of streams - how do we discard portions of a RAF?
// - Need to keep track of used/unused parts of file, scan for gaps etc...?
// - Need to periodically truncate and re-build the index (always as startup, then at every N puts/removes?)
/*public */PersistentMap(String id) {
this(new File(FileUtil.getTempDirFile(), id));
}
public PersistentMap(File root) {
this.root = notNull(root);
init();
}
private void init() {
if (!root.exists() && !root.mkdirs()) {
throw new IllegalStateException(String.format("'%s' does not exist/could not be created", root.getAbsolutePath()));
}
else if (!root.isDirectory()) {
throw new IllegalStateException(String.format("'%s' exists but is not a directory", root.getAbsolutePath()));
}
if (!root.canRead()) {
throw new IllegalStateException(String.format("'%s' is not readable", root.getAbsolutePath()));
}
if (!root.canWrite()) {
mutable = false;
}
FileUtil.visitFiles(root, DIRECTORIES, new Visitor<File>() {
public void visit(File dir) {
// - Read .index file
// - Add entries to index
ObjectInputStream input = null;
try {
input = new ObjectInputStream(new FileInputStream(new File(dir, INDEX)));
while (true) {
@SuppressWarnings({"unchecked"})
K key = (K) input.readObject();
String fileName = (String) input.readObject();
index.put(key, UUID.fromString(fileName));
}
}
catch (EOFException eof) {
// break here
}
catch (IOException e) {
throw new RuntimeException(e);
}
catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
finally {
FileUtil.close(input);
}
}
});
}
@Override
public Set<Entry<K, V>> entrySet() {
return new AbstractSet<Entry<K, V>>() {
@Override
public Iterator<Entry<K, V>> iterator() {
return new Iterator<Entry<K, V>>() {
Iterator<Entry<K, UUID>> indexIter = index.entrySet().iterator();
public boolean hasNext() {
return indexIter.hasNext();
}
public Entry<K, V> next() {
return new Entry<K, V>() {
final Entry<K, UUID> entry = indexIter.next();
public K getKey() {
return entry.getKey();
}
public V getValue() {
K key = entry.getKey();
int hash = key != null ? key.hashCode() : 0;
return readVal(hash, entry.getValue());
}
public V setValue(V value) {
K key = entry.getKey();
int hash = key != null ? key.hashCode() : 0;
return writeVal(key, hash, entry.getValue(), value, getValue());
}
};
}
public void remove() {
indexIter.remove();
}
};
}
@Override
public int size() {
return index.size();
}
};
}
@Override
public int size() {
return index.size();
}
@Override
public V put(K key, V value) {
V oldVal = null;
UUID uuid = index.get(key);
int hash = key != null ? key.hashCode() : 0;
if (uuid != null) {
oldVal = readVal(hash, uuid);
}
return writeVal(key, hash, uuid, value, oldVal);
}
private V writeVal(K key, int hash, UUID uuid, V value, V oldVal) {
if (!mutable) {
throw new UnsupportedOperationException();
}
File bucket = new File(root, hashToFileName(hash));
if (!bucket.exists() && !bucket.mkdirs()) {
throw new IllegalStateException(String.format("Could not create bucket '%s'", bucket));
}
if (uuid == null) {
// No uuid means new entry
uuid = UUID.randomUUID();
File idx = new File(bucket, INDEX);
ObjectOutputStream output = null;
try {
output = new ObjectOutputStream(new FileOutputStream(idx, true));
output.writeObject(key);
output.writeObject(uuid.toString());
index.put(key, uuid);
}
catch (IOException e) {
throw new RuntimeException(e);
}
finally {
FileUtil.close(output);
}
}
File entry = new File(bucket, uuid.toString());
if (value != null) {
ObjectOutputStream output = null;
try {
output = new ObjectOutputStream(new FileOutputStream(entry));
output.writeObject(value);
}
catch (IOException e) {
throw new RuntimeException(e);
}
finally {
FileUtil.close(output);
}
}
else if (entry.exists()) {
if (!entry.delete()) {
throw new IllegalStateException(String.format("'%s' could not be deleted", entry));
}
}
return oldVal;
}
private String hashToFileName(int hash) {
return Integer.toString(hash, 16);
}
@Override
public V get(Object key) {
UUID uuid = index.get(key);
if (uuid != null) {
int hash = key != null ? key.hashCode() : 0;
return readVal(hash, uuid);
}
return null;
}
private V readVal(final int hash, final UUID uuid) {
File bucket = new File(root, hashToFileName(hash));
File entry = new File(bucket, uuid.toString());
if (entry.exists()) {
ObjectInputStream input = null;
try {
input = new ObjectInputStream(new FileInputStream(entry));
//noinspection unchecked
return (V) input.readObject();
}
catch (IOException e) {
throw new RuntimeException(e);
}
catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
finally {
FileUtil.close(input);
}
}
return null;
}
@Override
public V remove(Object key) {
// TODO!!!
return super.remove(key);
}
// TODO: Should override size, put, get, remove, containsKey and containsValue
}
/*
Memory mapped file?
Delta sync?
Persistent format
Header
File ID 4-8 bytes
Size (entries)
PersistentEntry pointer array block (PersistentEntry 0)
Size (bytes)
Next entry pointer block address (0 if last)
PersistentEntry 1 address/offset + key
...
PersistentEntry n address/offset + key
PersistentEntry 1
Size (bytes)?
Serialized value or pointer array block
...
PersistentEntry n
Size (bytes)?
Serialized value or pointer array block
*/

View File

@@ -1,53 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,80 +0,0 @@
/*
* 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();
}

View File

@@ -1,51 +0,0 @@
/*
* 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);
}

View File

@@ -1,207 +0,0 @@
/*
* 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);
}
}
}
}

View File

@@ -1,52 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,320 +0,0 @@
/*
* 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();
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,410 +0,0 @@
/*
* 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;
}
}
}

View File

@@ -1,398 +0,0 @@
/*
* 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.regex;
import com.twelvemonkeys.util.DebugUtil;
import java.io.PrintStream;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* This class parses arbitrary strings against a wildcard string mask provided.
* The wildcard characters are '*' and '?'.
* <p>
* The string masks provided are treated as case sensitive.<br>
* Null-valued string masks as well as null valued strings to be parsed, will lead to rejection.
*
* <p><hr style="height=1"><p>
*
* This task is performed based on regular expression techniques.
* The possibilities of string generation with the well-known wildcard characters stated above,
* represent a subset of the possibilities of string generation with regular expressions.<br>
* The '*' corresponds to ([Union of all characters in the alphabet])*<br>
* The '?' corresponds to ([Union of all characters in the alphabet])<br>
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<small>These expressions are not suited for textual representation at all, I must say. Is there any math tags included in HTML?</small>
*
* <p>
*
* This class uses the Regexp package from Apache's Jakarta Project, links below.
*
* <p><hr style="height=1"><p>
*
* Examples of usage:<br>
* This example will return "Accepted!".
* <pre>
* REWildcardStringParser parser = new REWildcardStringParser("*_28????.jp*");
* if (parser.parseString("gupu_280915.jpg")) {
* System.out.println("Accepted!");
* } else {
* System.out.println("Not accepted!");
* }
* </pre>
*
* <p><hr style="height=1"><p>
*
* @author <a href="mailto:eirik.torske@iconmedialab.no">Eirik Torske</a>
* @see <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a>
* @see <a href="http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html">{@code org.apache.regexp.RE}</a>
* @see com.twelvemonkeys.util.regex.WildcardStringParser
*
* @todo Rewrite to use this regex package, and not Jakarta directly!
*/
public class REWildcardStringParser /*extends EntityObject*/ {
// Constants
/** 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', '\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 */
public static final char FREE_RANGE_CHARACTER = '*';
/** Field FREE_PASS_CHARACTER */
public static final char FREE_PASS_CHARACTER = '?';
// Members
Pattern mRegexpParser;
String mStringMask;
boolean mInitialized = false;
int mTotalNumberOfStringsParsed;
boolean mDebugging;
PrintStream out;
// Properties
// Constructors
/**
* Creates a wildcard string parser.
* <p>
* @param pStringMask the wildcard string mask.
*/
public REWildcardStringParser(final String pStringMask) {
this(pStringMask, false);
}
/**
* Creates a wildcard string parser.
* <p>
* @param pStringMask the wildcard string mask.
* @param pDebugging {@code true} will cause debug messages to be emitted to {@code System.out}.
*/
public REWildcardStringParser(final String pStringMask, final boolean pDebugging) {
this(pStringMask, pDebugging, System.out);
}
/**
* Creates a wildcard string parser.
* <p>
* @param pStringMask the wildcard string mask.
* @param pDebugging {@code true} will cause debug messages to be emitted.
* @param pDebuggingPrintStream the {@code java.io.PrintStream} to which the debug messages will be emitted.
*/
public REWildcardStringParser(final String pStringMask, final boolean pDebugging, final PrintStream pDebuggingPrintStream) {
this.mStringMask = pStringMask;
this.mDebugging = pDebugging;
this.out = pDebuggingPrintStream;
mInitialized = buildRegexpParser();
}
// Methods
/**
* Converts wildcard string mask to regular expression.
* This method should reside in som utility class, but I don't know how proprietary the regular expression format is...
* @return the corresponding regular expression or {@code null} if an error occurred.
*/
private String convertWildcardExpressionToRegularExpression(final String pWildcardExpression) {
if (pWildcardExpression == null) {
if (mDebugging) {
out.println(DebugUtil.getPrefixDebugMessage(this) + "wildcard expression is null - also returning null as regexp!");
}
return null;
}
StringBuilder regexpBuffer = new StringBuilder();
boolean convertingError = false;
for (int i = 0; i < pWildcardExpression.length(); i++) {
if (convertingError) {
return null;
}
// Free-range character '*'
char stringMaskChar = pWildcardExpression.charAt(i);
if (isFreeRangeCharacter(stringMaskChar)) {
regexpBuffer.append("(([a-<2D>A-<2D>0-9]|.|_|-)*)");
}
// Free-pass character '?'
else if (isFreePassCharacter(stringMaskChar)) {
regexpBuffer.append("([a-<2D>A_<41>0-9]|.|_|-)");
}
// Valid characters
else if (isInAlphabet(stringMaskChar)) {
regexpBuffer.append(stringMaskChar);
}
// Invalid character - aborting
else {
if (mDebugging) {
out.println(DebugUtil.getPrefixDebugMessage(this)
+ "one or more characters in string mask are not legal characters - returning null as regexp!");
}
convertingError = true;
}
}
return regexpBuffer.toString();
}
/**
* Builds the regexp parser.
*/
private boolean buildRegexpParser() {
// Convert wildcard string mask to regular expression
String regexp = convertWildcardExpressionToRegularExpression(mStringMask);
if (regexp == null) {
out.println(DebugUtil.getPrefixErrorMessage(this)
+ "irregularity in regexp conversion - now not able to parse any strings, all strings will be rejected!");
return false;
}
// Instantiate a regular expression parser
try {
mRegexpParser = Pattern.compile(regexp);
}
catch (PatternSyntaxException e) {
if (mDebugging) {
out.println(DebugUtil.getPrefixErrorMessage(this) + "RESyntaxException \"" + e.getMessage()
+ "\" caught - now not able to parse any strings, all strings will be rejected!");
}
if (mDebugging) {
e.printStackTrace(System.err);
}
return false;
}
if (mDebugging) {
out.println(DebugUtil.getPrefixDebugMessage(this) + "regular expression parser from regular expression " + regexp
+ " extracted from wildcard string mask " + mStringMask + ".");
}
return true;
}
/**
* Simple check of the string to be parsed.
*/
private boolean checkStringToBeParsed(final String pStringToBeParsed) {
// Check for nullness
if (pStringToBeParsed == null) {
if (mDebugging) {
out.println(DebugUtil.getPrefixDebugMessage(this) + "string to be parsed is null - rejection!");
}
return false;
}
// Check if valid character (element in alphabet)
for (int i = 0; i < pStringToBeParsed.length(); i++) {
if (!isInAlphabet(pStringToBeParsed.charAt(i))) {
if (mDebugging) {
out.println(DebugUtil.getPrefixDebugMessage(this)
+ "one or more characters in string to be parsed are not legal characters - rejection!");
}
return false;
}
}
return true;
}
/**
* Tests if a certain character is a valid character in the alphabet that is applying for this automaton.
*/
public static boolean isInAlphabet(final char pCharToCheck) {
for (int i = 0; i < ALPHABET.length; i++) {
if (pCharToCheck == ALPHABET[i]) {
return true;
}
}
return false;
}
/**
* Tests if a certain character is the designated "free-range" character ('*').
*/
public static boolean isFreeRangeCharacter(final char pCharToCheck) {
return pCharToCheck == FREE_RANGE_CHARACTER;
}
/**
* Tests if a certain character is the designated "free-pass" character ('?').
*/
public static boolean isFreePassCharacter(final char pCharToCheck) {
return pCharToCheck == FREE_PASS_CHARACTER;
}
/**
* Tests if a certain character is a wildcard character ('*' or '?').
*/
public static boolean isWildcardCharacter(final char pCharToCheck) {
return ((isFreeRangeCharacter(pCharToCheck)) || (isFreePassCharacter(pCharToCheck)));
}
/**
* Gets the string mask that was used when building the parser atomaton.
* <p>
* @return the string mask used for building the parser automaton.
*/
public String getStringMask() {
return mStringMask;
}
/**
* Parses a string.
* <p>
*
* @param pStringToBeParsed
* @return {@code true} if and only if the string are accepted by the parser.
*/
public boolean parseString(final String pStringToBeParsed) {
if (mDebugging) {
out.println();
}
if (mDebugging) {
out.println(DebugUtil.getPrefixDebugMessage(this) + "parsing \"" + pStringToBeParsed + "\"...");
}
// Update statistics
mTotalNumberOfStringsParsed++;
// Check string to be parsed
if (!checkStringToBeParsed(pStringToBeParsed)) {
return false;
}
// Perform parsing and return accetance/rejection flag
if (mInitialized) {
return mRegexpParser.matcher(pStringToBeParsed).matches();
} else {
out.println(DebugUtil.getPrefixErrorMessage(this) + "trying to use non-initialized parser - string rejected!");
}
return false;
}
/*
* Overriding mandatory methods from EntityObject's.
*/
/**
* Method toString
*
*
* @return
*
*/
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append(DebugUtil.getClassName(this));
buffer.append(": String mask ");
buffer.append(mStringMask);
buffer.append("\n");
return buffer.toString();
}
// Just taking the lazy, easy and dangerous way out
/**
* Method equals
*
*
* @param pObject
*
* @return
*
*/
public boolean equals(Object pObject) {
if (pObject instanceof REWildcardStringParser) {
REWildcardStringParser externalParser = (REWildcardStringParser) pObject;
return (externalParser.mStringMask == this.mStringMask);
}
return ((Object) this).equals(pObject);
}
// Just taking the lazy, easy and dangerous way out
/**
* Method hashCode
*
*
* @return
*
*/
public int hashCode() {
return ((Object) this).hashCode();
}
protected Object clone() throws CloneNotSupportedException {
return new REWildcardStringParser(mStringMask);
}
// Just taking the lazy, easy and dangerous way out
protected void finalize() throws Throwable {}
}
/*--- Formatted in Sun Java Convention Style on ma, des 1, '03 ---*/
/*------ Formatted by Jindent 3.23 Basic 1.0 --- http://www.jindent.de ------*/

View File

@@ -1,55 +0,0 @@
/*
* 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.xml;
import java.io.Reader;
import java.io.IOException;
/**
* XMLReader
*
* @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/xml/XMLReader.java#1 $
*/
public class XMLReader extends Reader {
// TODO:
// Create a reader backed by a pushback(?) inputstream
// Check for Unicode byte order marks
// Otherwise, use <?xml ... encoding="..."?> pi
// Or.. Just snatch the code form ROME.. ;-)
public void close() throws IOException {
throw new UnsupportedOperationException("Method close not implemented");// TODO: Implement
}
public int read(char cbuf[], int off, int len) throws IOException {
throw new UnsupportedOperationException("Method read not implemented");// TODO: Implement
}
}

View File

@@ -1,26 +0,0 @@
package com.twelvemonkeys.image;
import org.junit.Test;
import java.awt.image.BufferedImage;
import static com.twelvemonkeys.image.MappedImageFactory.createCompatibleMappedImage;
import static com.twelvemonkeys.image.MappedImageFactory.getCompatibleBufferedImageType;
import static org.junit.Assert.assertEquals;
public class MappedImageFactoryTest {
@Test
public void testGetCompatibleBufferedImageTypeFromBufferedImage() throws Exception {
for (int type = BufferedImage.TYPE_INT_RGB; type <= BufferedImage.TYPE_BYTE_INDEXED; type++) { // 1 - 13
assertEquals(type, getCompatibleBufferedImageType(new BufferedImage(1, 1, type)));
}
}
@Test
public void testGetCompatibleBufferedImageType() throws Exception {
for (int type = BufferedImage.TYPE_INT_RGB; type <= BufferedImage.TYPE_BYTE_INDEXED; type++) { // 1 - 13
assertEquals(type, getCompatibleBufferedImageType(createCompatibleMappedImage(1, 1, type)));
}
}
}

View File

@@ -1,126 +0,0 @@
package com.twelvemonkeys.io;
import org.junit.Test;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import static org.junit.Assert.*;
/**
* StringInputStreamTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: StringInputStreamTest.java,v 1.0 03.09.13 10:40 haraldk Exp$
*/
public class StringInputStreamTest {
static final Charset UTF8 = Charset.forName("UTF-8");
static final String LONG_STRING = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id est lobortis, elementum nisi id, mollis urna. Morbi lorem nulla, vehicula ut ultricies ut, blandit sit amet metus. Praesent ut urna et arcu commodo tempus. Aenean dapibus commodo ligula, non vehicula leo dictum a. Aenean at leo ut eros hendrerit pellentesque. Phasellus sagittis arcu non faucibus faucibus. Sed volutpat vulputate metus sed consequat. Aenean auctor sapien sit amet erat dictum laoreet. Nullam libero felis, rutrum scelerisque elit eu, porta mollis nisi. Vestibulum vel ultricies turpis, vel dignissim arcu.\n" +
"Ut convallis erat et dapibus feugiat. Pellentesque eu dictum ligula, et interdum nibh. Sed rutrum justo a leo faucibus eleifend. Proin est justo, porttitor vel nulla egestas, faucibus scelerisque lacus. Vivamus sit amet gravida nibh. Praesent odio diam, ornare vitae mi nec, pretium ultrices tellus. Pellentesque vitae felis consequat mauris lacinia condimentum in ut nibh. In odio quam, laoreet luctus velit vel, suscipit mollis leo. Etiam justo nulla, posuere et massa non, pretium vehicula diam. Sed porta molestie mauris quis condimentum. Sed quis gravida ipsum, eget porttitor felis. Vivamus volutpat velit vitae dolor convallis, nec malesuada est porttitor. Proin sed purus vel leo pretium suscipit. Morbi ut nibh quis tortor vehicula porttitor non sit amet lorem. Proin tempor vel sem sit amet accumsan.\n" +
"Cras vulputate orci a lorem luctus, vel egestas leo porttitor. Duis venenatis odio et mauris molestie rutrum. Mauris gravida volutpat odio at consequat. Mauris eros purus, bibendum in vulputate vitae, laoreet quis libero. Quisque lacinia, neque sed semper fringilla, elit dolor sagittis est, nec tincidunt ipsum risus ut sem. Maecenas consectetur aliquam augue. Etiam neque mi, euismod eget metus quis, molestie lacinia odio. Sed eget sollicitudin metus. Phasellus facilisis augue et sem facilisis, consequat mollis augue ultricies.\n" +
"Vivamus in porta massa. Sed eget lorem non lectus viverra pretium. Curabitur convallis posuere est vestibulum vulputate. Maecenas placerat risus ut dui hendrerit, sed suscipit magna tincidunt. Etiam ut mattis dolor, quis dictum velit. Donec ut dui sit amet libero convallis euismod. Phasellus dapibus dolor in nibh volutpat, eu scelerisque neque tempus. Maecenas a rhoncus velit. Etiam sollicitudin, leo non euismod vehicula, lectus risus aliquet metus, quis cursus purus orci non turpis. Nulla vel enim tortor. Quisque nec mi vulputate, convallis orci vel, suscipit nibh. Sed sed tellus id elit commodo laoreet ut euismod ligula. Mauris suscipit commodo interdum. Phasellus scelerisque arcu nec nibh porta, et semper massa rutrum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.\n" +
"Praesent cursus, sapien ut venenatis malesuada, turpis nulla venenatis velit, nec tristique leo turpis auctor purus. Curabitur non porta urna. Sed vitae felis massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus scelerisque id dolor nec fermentum. Etiam suscipit tincidunt odio, sed molestie elit fringilla in. Phasellus nec euismod lacus. Suspendisse bibendum vulputate viverra. Fusce mollis pharetra imperdiet. Phasellus tortor eros, rhoncus volutpat diam in, scelerisque viverra felis. Ut ornare urna commodo, pretium mauris eget, eleifend ipsum.";
static final String SHORT_STRING = "Java";
@Test
public void testReadShortString() throws IOException {
StringInputStream stream = new StringInputStream(SHORT_STRING, UTF8);
byte[] value = SHORT_STRING.getBytes(UTF8);
for (int i = 0; i < value.length; i++) {
int read = stream.read();
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
}
assertEquals(-1, stream.read());
}
@Test
public void testReadSubString() throws IOException {
StringInputStream stream = new StringInputStream("foo bar xyzzy", 4, 3, UTF8);
byte[] value = "bar".getBytes(UTF8);
for (int i = 0; i < value.length; i++) {
int read = stream.read();
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
}
assertEquals(-1, stream.read());
}
@Test
public void testReadNonAsciiString() throws IOException {
String string = "\u00c6\u00d8\u00c5\u00e6\u00f8\u00e5\u00e1\u00e9\u00c0\u00c8\u00fc\u00dc\u00df";
StringInputStream stream = new StringInputStream(string, UTF8);
byte[] value = string.getBytes(UTF8);
for (int i = 0; i < value.length; i++) {
int read = stream.read();
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
}
assertEquals(-1, stream.read());
}
@Test
public void testReadLongString() throws IOException {
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
byte[] value = LONG_STRING.getBytes(UTF8);
for (int i = 0; i < value.length; i++) {
int read = stream.read();
assertEquals(String.format("Wrong value at offset %s: '%s' != '%s'", i, String.valueOf((char) value[i]), String.valueOf((char) (byte) read)), value[i] &0xff, read);
}
assertEquals(-1, stream.read());
}
@Test
public void testReadArrayLongString() throws IOException {
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
byte[] value = LONG_STRING.getBytes(UTF8);
byte[] buffer = new byte[17];
int count;
for (int i = 0; i < value.length; i += count) {
count = stream.read(buffer);
assertArrayEquals(String.format("Wrong value at offset %s", i), Arrays.copyOfRange(value, i, i + count), Arrays.copyOfRange(buffer, 0, count));
}
assertEquals(-1, stream.read());
}
@Test
public void testReadArraySkipLongString() throws IOException {
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
byte[] value = LONG_STRING.getBytes(UTF8);
byte[] buffer = new byte[17];
int count;
for (int i = 0; i < value.length; i += count) {
if (i % 2 == 0) {
count = (int) stream.skip(buffer.length);
}
else {
count = stream.read(buffer);
assertArrayEquals(String.format("Wrong value at offset %s", i), Arrays.copyOfRange(value, i, i + count), Arrays.copyOfRange(buffer, 0, count));
}
}
assertEquals(-1, stream.read());
}
/*@Test
public */void testPerformance() throws IOException {
for (int i = 0; i < 100000; i++) {
StringInputStream stream = new StringInputStream(LONG_STRING, UTF8);
while(stream.read() != -1) {
stream.available();
}
}
}
}

View File

@@ -1,18 +0,0 @@
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();
}
}

View File

@@ -1,18 +0,0 @@
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();
}
}

View File

@@ -1,246 +0,0 @@
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) {
}
}
}

View File

@@ -1,99 +0,0 @@
/*
* 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);
}
}
}

View File

@@ -1,578 +0,0 @@
/*
* 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;
}
}
}

View File

@@ -1,419 +0,0 @@
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());
}
}

View File

@@ -1,137 +0,0 @@
/*
* 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));
}
}
}
}

View File

@@ -1,86 +0,0 @@
<?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.1-SNAPSHOT</version>
</parent>
<artifactId>sandbox-imageio</artifactId>
<packaging>jar</packaging>
<name>TwelveMonkeys :: Sandbox :: ImageIO</name>
<description>
The TwelveMonkeys ImageIO Sandbox. New 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.sandbox</groupId>
<artifactId>sandbox-common</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common-io</artifactId>
<scope>test</scope>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common-lang</artifactId>
<scope>test</scope>
<type>test-jar</type>
</dependency>
</dependencies>
</project>

View File

@@ -1,65 +0,0 @@
package com.twelvemonkeys.imageio.stream;
import com.twelvemonkeys.io.StringInputStream;
import com.twelvemonkeys.io.enc.Base64Decoder;
import com.twelvemonkeys.io.enc.DecoderStream;
import javax.imageio.spi.ImageInputStreamSpi;
import javax.imageio.stream.FileCacheImageInputStream;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Locale;
/**
* Base64DataURLImageInputStreamSpi
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: Base64DataURLImageInputStreamSpi.java,v 1.0 03.09.13 09:35 haraldk Exp$
*/
public class Base64DataURLImageInputStreamSpi extends ImageInputStreamSpi {
// This is generally a bad idea, because:
// - It is bound to String.class, and not all strings are base64 encoded data URLs.
// - It's better to just create a decoder stream from the base64 stream, and use what's already in ImageIO....
public Base64DataURLImageInputStreamSpi() {
super("TwelveMonkeys", "0.1-BETA", String.class);
}
@Override
public ImageInputStream createInputStreamInstance(final Object input, final boolean useCache, final File cacheDir) throws IOException {
String string = (String) input;
InputStream stream = createStreamFromBase64(string);
return useCache && cacheDir != null ? new FileCacheImageInputStream(stream, cacheDir) : new MemoryCacheImageInputStream(stream);
}
private InputStream createStreamFromBase64(String string) {
if (!string.startsWith("data:")) {
throw new IllegalArgumentException(String.format("Not a data URL: %s", string));
}
int index = string.indexOf(';');
if (index < 0 || !string.regionMatches(index + 1, "base64,", 0, "base64,".length())) {
throw new IllegalArgumentException(String.format("Not base64 encoded: %s", string));
}
int offset = index + "base64,".length() + 1;
return new DecoderStream(new StringInputStream(string.substring(offset), Charset.forName("UTF-8")), new Base64Decoder());
}
@Override
public boolean canUseCacheFile() {
return true;
}
@Override
public String getDescription(Locale locale) {
return "Service provider that instantiates a FileCacheImageInputStream or MemoryCacheImageInputStream from a Base64 encoded data string";
}
}

View File

@@ -1,84 +0,0 @@
<?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.1-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>
</dependencies>
</project>

View File

@@ -1,336 +0,0 @@
/*
* 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
* &lt;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" /&gt;
*
* @example
* &lt;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" /&gt;
*
* @example
* &lt;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" /&gt;
*
* @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;
}
}

View File

@@ -1,76 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,42 +0,0 @@
/*
* 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;
}

View File

@@ -1,26 +0,0 @@
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);
}
}

View File

@@ -1,41 +0,0 @@
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);
}
}

View File

@@ -1,9 +0,0 @@
/**
* 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;

View File

@@ -1,214 +0,0 @@
/*
* 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();
}
}

View File

@@ -1,183 +0,0 @@
/*
* 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/.
* &copy; 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);
}
}

View File

@@ -1,102 +0,0 @@
/*
* 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/.
* &copy; 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));
}
}

View File

@@ -1,220 +0,0 @@
/*
* 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();
}
}

View File

@@ -1,129 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,47 +0,0 @@
/*
* 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;
}
}

View File

@@ -1,148 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,38 +0,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.
*/
/**
* 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;

View File

@@ -1,4 +0,0 @@
/**
* JSP support.
*/
package com.twelvemonkeys.servlet.jsp;

View File

@@ -1,39 +0,0 @@
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;
}

View File

@@ -1,235 +0,0 @@
/*
* 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>
* &lt;c:totable firstRowIsHeader="true" delimiter=";"&gt;
* header A;header B
* data 1A; data 1B
* data 2A; data 2B
* &lt;/c:totable&gt;
* </PRE>
*
* The output (source) will look like this:
* <PRE>
* &lt;TABLE&gt;
* &lt;TR&gt;
* &lt;TH&gt;header A&lt;/TH&gt;&lt;TH&gt;header B&lt;/TH&gt;
* &lt;/TR&gt;
* &lt;TR&gt;
* &lt;TD&gt;data 1A&lt;/TD&gt;&lt;TD&gt;data 1B&lt;/TD&gt;
* &lt;/TR&gt;
* &lt;TR&gt;
* &lt;TD&gt;data 2A&lt;/TD&gt;&lt;TD&gt;data 2B&lt;/TD&gt;
* &lt;/TR&gt;
* &lt;/TABLE&gt;
* </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);
}
}
}

View File

@@ -1,290 +0,0 @@
/*
* 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("&lt;");
}
else if (token.equals(">")) {
pOut.print("&gt;");
}
else if (token.equals("&")) {
pOut.print("&amp;");
}
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);
}
}

View File

@@ -1,163 +0,0 @@
/*
* 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);
}

View File

@@ -1,293 +0,0 @@
/*
* 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("&lt;");
}
else if (token.equals(">")) {
pOut.print("&gt;");
}
else if (token.equals("&")) {
pOut.print("&amp;");
}
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);
}
}

View File

@@ -1,20 +0,0 @@
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),
};
}
}

View File

@@ -1,49 +0,0 @@
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;
}
}

View File

@@ -1,87 +0,0 @@
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);
}
}

Some files were not shown because too many files have changed in this diff Show More