openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r439412 - /incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
Date Fri, 01 Sep 2006 18:18:04 GMT
Author: skim
Date: Fri Sep  1 11:18:03 2006
New Revision: 439412

URL: http://svn.apache.org/viewvc?rev=439412&view=rev
Log:
whoops.  forgot interface impl generator

Added:
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
  (with props)

Added: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java?rev=439412&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
(added)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
Fri Sep  1 11:18:03 2006
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2006 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.openjpa.meta;
+
+import java.lang.reflect.Method;
+import java.io.ByteArrayInputStream;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.openjpa.enhance.PCEnhancer;
+import org.apache.openjpa.util.InternalException;
+import org.apache.openjpa.lib.util.Localizer;
+import serp.bytecode.BCClass;
+import serp.bytecode.BCClassLoader;
+import serp.bytecode.BCField;
+import serp.bytecode.BCMethod;
+import serp.bytecode.Code;
+import serp.bytecode.Constants;
+import serp.bytecode.Project;
+
+
+/**
+ * Creates implementations of managed interfaces.  Will throw exceptions
+ * on unknown properties.
+ *
+ * @author Steve Kim
+ */
+class InterfaceImplGenerator {
+    private static final Localizer _loc = Localizer.forPackage
+        (InterfaceImplGenerator.class);
+    private static final String POSTFIX = "openjpaimpl";
+
+    private final MetaDataRepository _repos;
+    private final Map _impls = new WeakHashMap();
+    private final Project _project = new Project();
+    private final BCClassLoader _loader = new BCClassLoader(_project);
+
+    // distinct project / loader for enhanced version of class
+    private final Project _enhProject = new Project();
+    private final BCClassLoader _enhLoader = new BCClassLoader(_enhProject);
+
+    /**
+     * Constructor.  Supply repository.
+     */
+    public InterfaceImplGenerator(MetaDataRepository repos) {
+        _repos = repos;
+    }
+
+    /**
+     * Create a concrete implementation of the given type, possibly
+     * returning a cached version of the class.
+     */
+    public synchronized Class createImpl(ClassMetaData meta) {
+        Class iface = meta.getDescribedType();
+
+        // check cache.
+        Class impl = (Class) _impls.get(iface);
+        if (impl != null)
+            return impl;
+
+        BCClass bc = _project.loadClass(getClassName(meta));
+        bc.declareInterface(iface);
+        ClassMetaData sup = meta.getPCSuperclassMetaData();
+        if (sup != null)
+            bc.setSuperclass(sup.getInterfaceImpl());
+
+        FieldMetaData[] fields = meta.getDeclaredFields();
+        Set methods = new HashSet();
+        for (int i = 0; i < fields.length; i++) 
+            addField(bc, iface, fields[i], methods);
+        invalidateNonBeanMethods(bc, iface, methods);
+
+        // first load the base class as the enhancer requires the class
+        // to be available
+        try {
+            meta.setInterfaceImpl(Class.forName(bc.getName(), true, _loader));
+        } catch (Throwable t) {
+            throw new InternalException(_loc.get("interface-load"), t).
+                setFatal(true);
+        }
+        // copy the BCClass into the enhancer project.
+        bc = _enhProject.loadClass(new ByteArrayInputStream(bc.toByteArray()), 
+            _loader);
+        PCEnhancer enhancer = new PCEnhancer(_repos.getConfiguration(), bc, 
+            meta);
+
+        int result = enhancer.run();
+        if (result != PCEnhancer.ENHANCE_PC)
+            throw new InternalException(_loc.get("interface-badenhance", 
+                iface)).setFatal(true);
+        try{
+            // load the class for real.
+            impl = Class.forName(bc.getName(), true, _enhLoader);
+        } catch (Throwable t) {
+            throw new InternalException(_loc.get("interface-load2"), t).
+                setFatal(true);
+        }
+        // cache the generated impl.
+        _impls.put(iface, impl);
+        return impl;
+    }
+
+    /**
+     * Add bean getters and setters, also recording seen methods
+     * into the given set.
+     */
+    private void addField (BCClass bc, Class iface, FieldMetaData fmd, 
+        Set methods) {
+        String name = fmd.getName();
+        Class type = fmd.getDeclaredType();
+        BCField field = bc.declareField(name, type);
+        field.setAccessFlags(Constants.ACCESS_PRIVATE);
+
+        // getter
+        name = StringUtils.capitalize(name);
+        String prefix = isGetter(iface, fmd) ? "get" : "is";
+        BCMethod meth = bc.declareMethod(prefix + name, type, null);
+        meth.makePublic();
+        Code code = meth.getCode(true);
+        code.aload().setThis();
+        code.getfield().setField(field);
+        code.xreturn().setType(type);
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+        methods.add(getMethodSafe(iface, meth.getName(), null));
+
+        // setter
+        meth = bc.declareMethod("set" + name, void.class, new Class[]{type});
+        meth.makePublic();
+        code = meth.getCode(true);
+        code.aload().setThis();
+        code.xload().setParam(0).setType(type);
+        code.putfield().setField(field);
+        code.vreturn();
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+        methods.add(getMethodSafe(iface, meth.getName(), type));
+    }
+
+    /**
+     * Invalidate methods on the interface which are not managed.
+     */
+    private void invalidateNonBeanMethods(BCClass bc, Class iface, 
+        Set methods) {
+        Method[] meths = iface.getDeclaredMethods();
+        BCMethod meth;
+        Code code;
+        Class type = _repos.getMetaDataFactory().getDefaults().
+            getUnimplementedExceptionType();
+        for (int i = 0; i < meths.length; i++) {
+            if (methods.contains(meths[i]))
+                continue;
+            meth = bc.declareMethod(meths[i].getName(), 
+                meths[i].getReturnType(), meths[i].getParameterTypes());
+            meth.makePublic();
+            code = meth.getCode(true);
+            code.anew().setType(type);
+            code.dup();
+            code.invokespecial().setMethod(type, "<init>", void.class, null);
+            code.athrow();
+            code.calculateMaxLocals();
+            code.calculateMaxStack();
+        }
+    }
+
+    /**
+     * Return a unique class name.
+     */
+    protected final String getClassName(ClassMetaData meta) {
+        Class iface = meta.getDescribedType();
+        return iface.getName() + "$" + System.identityHashCode(iface) + POSTFIX;
+    }
+
+    /**
+     * Convenience method to return the given method / arg.
+     */
+    private static Method getMethodSafe(Class iface, String name, Class arg) {
+        try {
+            return iface.getDeclaredMethod(name, arg == null ? null :
+                new Class[]{arg});
+        } catch (NoSuchMethodException e) {
+            throw new InternalException (_loc.get ("interface-mismatch", name));
+        }
+    }
+
+    private static boolean isGetter(Class iface, FieldMetaData fmd) {
+        if (fmd.getType() != boolean.class && fmd.getType() != Boolean.class)
+            return true;
+        try {
+            Method meth = iface.getDeclaredMethod("is" + StringUtils.capitalize
+                (fmd.getName()), null);
+            return meth == null;
+        } catch (NoSuchMethodException e) {}
+        return true;
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java
------------------------------------------------------------------------------
    svn:executable = *



Mime
View raw message