/* * Copyright (c) 2009, 2010, James Leigh 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 of the openrdf.org 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 net.enilink.composition.properties.sparql; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; import net.enilink.composition.annotations.Iri; import net.enilink.composition.asm.BehaviourClassNode; import net.enilink.composition.asm.BehaviourMethodProcessor; import net.enilink.composition.asm.ExtendedMethod; import net.enilink.composition.asm.Types; import net.enilink.composition.asm.util.BehaviourMethodGenerator; import net.enilink.composition.asm.util.MethodNodeGenerator; import net.enilink.composition.exceptions.BehaviourException; import net.enilink.composition.properties.PropertyMapper; import com.google.inject.Inject; import net.enilink.komma.core.IEntityManager; /** * Generate a behaviour for {@link Sparql} annotated methods. * */ public class SparqlBehaviourMethodProcessor implements BehaviourMethodProcessor, Opcodes, Types { public static Type MANAGER_TYPE = Type.getType(IEntityManager.class); public static org.objectweb.asm.commons.Method GET_MANAGER = new org.objectweb.asm.commons.Method( "getContext", Type.getMethodDescriptor(MANAGER_TYPE, new Type[0])); @Inject private PropertyMapper propertyMapper; @Override public boolean implementsMethod(Class<?> targetClass, Method method) { return method.isAnnotationPresent(Sparql.class) && Modifier.isAbstract(method.getModifiers()); } @Override public boolean appliesTo(BehaviourClassNode classNode, ExtendedMethod method) { return method.getOverriddenMethod().isAnnotationPresent(Sparql.class) && method.instructions.size() == 0; } @SuppressWarnings("unchecked") @Override public void initialize(BehaviourClassNode classNode) throws Exception { FieldNode contextField = new FieldNode(Opcodes.ACC_PRIVATE, "context", MANAGER_TYPE.getDescriptor(), null, null); contextField.visitAnnotation(Type.getDescriptor(Inject.class), true); classNode.fields.add(contextField); MethodNode mn = new MethodNode(ACC_PRIVATE, GET_MANAGER.getName(), GET_MANAGER.getDescriptor(), null, null); MethodNodeGenerator gen = new MethodNodeGenerator(mn); gen.loadThis(); gen.getField(classNode.getType(), "context", MANAGER_TYPE); gen.returnValue(); gen.endMethod(); classNode.methods.add(mn); } @Override public void process(BehaviourClassNode classNode, ExtendedMethod method) throws Exception { BehaviourMethodGenerator gen = new BehaviourMethodGenerator(method); String sparql = method.getOverriddenMethod() .getAnnotation(Sparql.class).value(); String base; if (method.getOverriddenMethod().getDeclaringClass() .isAnnotationPresent(Iri.class)) { base = method.getOverriddenMethod().getDeclaringClass() .getAnnotation(Iri.class).value(); } else { base = "java:" + method.getOverriddenMethod().getDeclaringClass() .getName(); } Label tryLabel = gen.mark(); // try SPARQLQueryOptimizer oqo = new SPARQLQueryOptimizer(); oqo.implementQuery(sparql, base, propertyMapper, method.getOverriddenMethod(), gen); // catch (RuntimeException e) { // throw e; // } Label catchLabel = gen.mark(); Type runtimeException = Type.getType(RuntimeException.class); gen.catchException(tryLabel, catchLabel, runtimeException); gen.throwException(); // catch (Exception e) { // throw new BehaviourException(e); // } gen.catchException(tryLabel, catchLabel, Type.getType(Exception.class)); int exceptionVar = gen.newLocal(Type.getType(Exception.class)); gen.storeLocal(exceptionVar); Type behaviourException = Type.getType(BehaviourException.class); gen.newInstance(behaviourException); gen.dup(); gen.loadLocal(exceptionVar); gen.invokeConstructor(behaviourException, org.objectweb.asm.commons.Method .getMethod("void <init>(Throwable)")); gen.throwException(); } }