| /* |
| * Copyright 2005 The Apache Software Foundation. |
| * |
| * 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 org.apache.jdo.test; |
| |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.ObjectInputStream; |
| import java.lang.reflect.Constructor; |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| |
| import javax.jdo.PersistenceManager; |
| import javax.jdo.Transaction; |
| import javax.jdo.spi.PersistenceCapable; |
| |
| import org.apache.jdo.pc.PCPoint; |
| import org.apache.jdo.test.util.AbstractTest; |
| import org.apache.jdo.test.util.JDORITestRunner; |
| |
| /** |
| * Tests that we can insert, fetch, and get extent of instances of 2 distinct |
| * classes which have the same name. For this test, they are both |
| * org.apache.jdo.pc.PCPoint, but one of them has 2 coordinates and the |
| * other has 3. We use our own ClassLoader to be able to load them both in |
| * the same JVM. |
| * |
| * @author Dave Brigstor |
| */ |
| public class Test_FSUID2 extends AbstractTest { |
| /** Maps class names to classes. */ |
| // This is only for use byt FSUIDLoader, but inner classes cannot have |
| // static members, so here it is. |
| private static final HashMap cache = new HashMap(); |
| |
| /** Name of the jarfile property. */ |
| private static final String JARFILE_PROPERTY = "fsuidjar"; |
| |
| /** Default jarfile name, used if property is undefined. */ |
| private static final String DEFAULT_JARFILE = "fsuid2.jar"; |
| |
| /** Name of the jar file for class loading. */ |
| private String jarfile; |
| |
| /** Reflection constructor instance for 3D point class. */ |
| private Constructor p3Constructor; |
| |
| /** */ |
| public static void main(String args[]) { |
| JDORITestRunner.run(Test_FSUID2.class); |
| } |
| |
| /** */ |
| public Test_FSUID2() { |
| super(); |
| jarfile = System.getProperty(JARFILE_PROPERTY, DEFAULT_JARFILE); |
| } |
| |
| /** */ |
| public void test() throws Exception { |
| insertObjects(); |
| writeOIDs(); |
| readObjects(); |
| } |
| |
| /** |
| * Create and store instances of PCPoint whose classes are loaded from |
| * different class loaders and have different structure (and hence |
| * different FOStoreSchemaUID's). |
| */ |
| protected void insertObjects() throws Exception { |
| PersistenceManager pm = null; |
| Transaction tx = null; |
| |
| try { |
| if (debug) logger.debug("\nINSERT"); |
| |
| pm = pmf.getPersistenceManager(); |
| tx = pm.currentTransaction(); |
| tx.begin(); |
| |
| // Get loader for and load class of 3-D point. |
| p3Constructor = get3DPointConstructor(); |
| |
| Object inserted1[] = new Object[numInsert]; |
| Object inserted2[] = new Object[numInsert]; |
| for (int i = 0; i < numInsert; i++) { |
| // create 2D point |
| Object pc = new PCPoint(i, new Integer(i)); |
| if (debug) |
| logger.debug("cl " + i + " " + pc.getClass().getClassLoader()); |
| pm.makePersistent(pc); |
| inserted1[i] = pc; |
| |
| // create 3D point |
| pc = (PersistenceCapable)p3Constructor.newInstance( |
| new Object[] { |
| new Integer(i), new Integer(i), new Float(1.0 * i)}); |
| if (debug) |
| logger.debug("cl " + i + " " + pc.getClass().getClassLoader()); |
| pm.makePersistent(pc); |
| inserted2[i] = pc; |
| } |
| |
| tx.commit(); |
| |
| for (int i = 0; i < numInsert; i++) { |
| announce("inserted ", inserted1[i]); |
| announce("inserted ", inserted2[i]); |
| } |
| |
| if (debug) logger.debug("inserted " + insertedCount + " objects"); |
| } |
| finally { |
| if (tx != null && tx.isActive()) |
| tx.rollback(); |
| if (pm != null && !pm.isClosed()) |
| pm.close(); |
| } |
| } |
| |
| /** |
| * Loads and verifies the pc instances specified by the stored oids. |
| */ |
| protected void readObjects() throws Exception { |
| PersistenceManager pm = pmf.getPersistenceManager(); |
| Transaction tx = pm.currentTransaction(); |
| try { |
| ObjectInputStream in = getOIDFileInputStream(); |
| tx.begin(); |
| try { |
| int count = 0; |
| while (true) { |
| Object oid = in.readObject(); |
| Object pc = pm.getObjectById(oid, true); |
| if (debug) logger.debug("fetching: " + oid + " -> " + pc); |
| // The first numInsert instances are supposed to be |
| // 2D points and the next are supposed to be 3D points. |
| if (count < numInsert) |
| verify2DPoint(count, pc); |
| else |
| verify3DPoint(count - numInsert, pc); |
| count++; |
| } |
| } |
| catch (EOFException ex) { |
| // OK |
| } |
| tx.commit(); |
| } |
| finally { |
| if (tx != null && tx.isActive()) |
| tx.rollback(); |
| if (pm != null && !pm.isClosed()) |
| pm.close(); |
| } |
| } |
| |
| /** */ |
| private void verify2DPoint(int i, Object pc) { |
| Object expected = new PCPoint(i, new Integer(i)); |
| assertEquals("Wrong 2D point instance", expected, pc); |
| } |
| |
| /** */ |
| private void verify3DPoint(int i, Object pc) throws Exception { |
| Object expected = p3Constructor.newInstance(new Object[] { |
| new Integer(i), new Integer(i), new Float(1.0 * i)}); |
| assertEquals("Wrong 2D point instance", expected, pc); |
| } |
| |
| /** */ |
| protected int getDefaultInsert() |
| { |
| return 4; |
| } |
| |
| private Constructor get3DPointConstructor() throws Exception { |
| try { |
| return (Constructor)AccessController.doPrivileged( |
| new PrivilegedExceptionAction () { |
| public Object run () throws Exception { |
| FSUIDLoader l = new FSUIDLoader(jarfile); |
| Class p3Class = l.loadClass("org.apache.jdo.pc.PCPoint", true); |
| return p3Class.getDeclaredConstructor( |
| new Class[] { int.class, Integer.class, float.class }); |
| }}); |
| } |
| catch (PrivilegedActionException ex) { |
| // unwrap FileNotFoundException |
| throw ex.getException(); |
| } |
| } |
| |
| /** |
| * Expects to load classes from within a specified jar file. |
| */ |
| class FSUIDLoader extends ClassLoader { |
| /** Name of the jar file for class loading. */ |
| private final String filename; |
| |
| FSUIDLoader(String filename) { |
| this.filename = filename; |
| } |
| |
| public InputStream getResourceAsStream(String name) { |
| if (!name.startsWith("org/apache/jdo/pc")) { |
| return getSystemResourceAsStream(name); |
| } |
| |
| try { |
| JarFile jarFile = getJarFile(); |
| JarEntry entry = jarFile.getJarEntry(name); |
| if (entry != null) { |
| return jarFile.getInputStream(entry); |
| } |
| } |
| catch (IOException ex) { |
| ex.printStackTrace(); |
| } |
| return null; |
| } |
| |
| public synchronized Class loadClass(String name, boolean resolve) |
| throws ClassNotFoundException { |
| |
| Class c = (Class)cache.get(name); |
| |
| try { |
| if (null == c && ! name.startsWith("org.apache.jdo.pc")) { |
| try { |
| c = findSystemClass(name); |
| } catch (ClassNotFoundException ex) { |
| ; |
| } catch (NoClassDefFoundError ex) { |
| ; |
| } |
| } |
| |
| if (null == c) { |
| byte b[] = loadClassData(name); |
| if (null == b) { |
| throw new NoClassDefFoundError(name); |
| } |
| c = defineClass(name, b, 0, b.length); |
| cache.put(name, c); |
| } |
| if (resolve) { |
| resolveClass(c); |
| } |
| } catch (NoClassDefFoundError ex) { |
| throw new ClassNotFoundException("loadClass " + name, ex); |
| } |
| return c; |
| } |
| |
| private byte[] loadClassData(String name) |
| throws ClassNotFoundException { |
| byte rc[] = null; |
| |
| // Class names in jar files have file separators...I hope they're |
| // the same on Un*x and Windows. |
| name = name.replace('.', '/') + ".class"; |
| try { |
| JarFile jf = getJarFile(); |
| for (Enumeration e = jf.entries(); e.hasMoreElements();) { |
| JarEntry je = (JarEntry)e.nextElement(); |
| if (name.equals(je.getName())) { |
| InputStream is = jf.getInputStream(je); |
| int avail = is.available(); |
| if (-1 != avail) { |
| int size = avail; |
| rc = new byte[size]; |
| int off = 0; |
| int count = 0; |
| while (size > 0) { |
| count = is.read(rc, off, size); |
| if (count <= 0) { |
| is.close(); |
| break; |
| } |
| off += count; |
| size -= count; |
| } |
| if (off != avail) { |
| throw new IOException( |
| "failed to read complete class " + name); |
| } |
| } |
| break; |
| } |
| } |
| } catch (IOException ex) { |
| ex.printStackTrace(); |
| throw new ClassNotFoundException("loadClassData " + name, ex); |
| } |
| return rc; |
| } |
| |
| private JarFile getJarFile() throws IOException { |
| try { |
| return (JarFile)AccessController.doPrivileged( |
| new PrivilegedExceptionAction () { |
| public Object run () throws IOException { |
| return new JarFile(filename); |
| }}); |
| } |
| catch (PrivilegedActionException ex) { |
| // unwrap FileNotFoundException |
| throw (IOException)ex.getException(); |
| } |
| } |
| |
| } |
| |
| } |