[ARIES-1405] Only use blueprint service proxies
git-svn-id: https://svn.apache.org/repos/asf/aries/trunk/jpa@1703414 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jpa-blueprint/pom.xml b/jpa-blueprint/pom.xml
index d55a0a8..7ba9dbb 100644
--- a/jpa-blueprint/pom.xml
+++ b/jpa-blueprint/pom.xml
@@ -31,11 +31,7 @@
<packaging>bundle</packaging>
<dependencies>
- <dependency>
- <groupId>org.apache.aries.jpa</groupId>
- <artifactId>org.apache.aries.jpa.api</artifactId>
- <version>${project.version}</version>
- </dependency>
+
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jpa_2.0_spec</artifactId>
diff --git a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/AnnotationScanner.java b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/AnnotationScanner.java
index a874097..18d4a9c 100644
--- a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/AnnotationScanner.java
+++ b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/AnnotationScanner.java
@@ -1,48 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.aries.jpa.blueprint.impl;
+import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.PersistenceContext;
-import javax.persistence.PersistenceUnit;
-
-import org.apache.aries.jpa.supplier.EmSupplier;
-
public class AnnotationScanner {
- private final List<Class<?>> managedJpaClasses;
-
- public AnnotationScanner() {
- managedJpaClasses = Arrays.asList(EntityManagerFactory.class, EntityManager.class, EmSupplier.class);
- }
-
- public List<AccessibleObject> getJpaAnnotatedMembers(Class<?> c) {
+
+ public List<AccessibleObject> getJpaAnnotatedMembers(Class<?> c, Class<? extends Annotation> annotation) {
final List<AccessibleObject> jpaAnnotated = new ArrayList<AccessibleObject>();
Class<?> cl = c;
if (c != Object.class) {
while (cl != Object.class) {
for (Field field : cl.getDeclaredFields()) {
- if (field.getAnnotation(PersistenceContext.class) != null
- || field.getAnnotation(PersistenceUnit.class) != null) {
+ if (field.isAnnotationPresent(annotation)) {
+ field.setAccessible(true);
jpaAnnotated.add(field);
}
}
for (Method method : cl.getDeclaredMethods()) {
- if (method.getAnnotation(PersistenceContext.class) != null
- || method.getAnnotation(PersistenceUnit.class) != null) {
-
- Class<?>[] pType = method.getParameterTypes();
- if (method.getName().startsWith("set") && pType.length == 1
- && managedJpaClasses.contains(pType[0])) {
- jpaAnnotated.add(method);
- }
+ if ((method.isAnnotationPresent(annotation)) && method.getName().startsWith("set") && method.getParameterTypes().length == 1) {
+ jpaAnnotated.add(method);
}
}
@@ -52,4 +52,27 @@
return jpaAnnotated;
}
+
+ public String getName(AccessibleObject member) {
+ if (member instanceof Field) {
+ return ((Field)member).getName();
+ } else if (member instanceof Method) {
+ Method method = (Method)member;
+ String name = method.getName();
+ if (!name.startsWith("set")) {
+ return null;
+ }
+ return name. substring(3, 4).toLowerCase() + name.substring(4);
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public Class<?> getType(AccessibleObject member) {
+ if (member instanceof Field) {
+ return ((Field)member).getType();
+ } else if (member instanceof Method) {
+ return ((Method)member).getParameterTypes()[0];
+ }
+ throw new IllegalArgumentException();
+ }
}
diff --git a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaComponentProcessor.java b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaComponentProcessor.java
index 30e091a..b8fbb4b 100644
--- a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaComponentProcessor.java
+++ b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaComponentProcessor.java
@@ -1,16 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.aries.jpa.blueprint.impl;
import static org.osgi.service.jpa.EntityManagerFactoryBuilder.JPA_UNIT_NAME;
import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
@@ -22,10 +38,8 @@
import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
import org.apache.aries.blueprint.mutable.MutableRefMetadata;
import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
-import org.apache.aries.jpa.blueprint.supplier.impl.ServiceProxy;
-import org.apache.aries.jpa.supplier.EmSupplier;
import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
+import org.osgi.service.blueprint.container.BlueprintContainer;
import org.osgi.service.blueprint.reflect.ComponentMetadata;
import org.osgi.service.blueprint.reflect.ReferenceMetadata;
import org.osgi.service.coordinator.Coordinator;
@@ -33,6 +47,7 @@
import org.slf4j.LoggerFactory;
public class JpaComponentProcessor implements ComponentDefinitionRegistryProcessor {
+ private static final String JPA_COORDINATOR = "jpa_Coordinator";
private static final Logger LOGGER = LoggerFactory.getLogger(JpaComponentProcessor.class);
private AnnotationScanner annotationScanner;
private ParserContext pc;
@@ -47,111 +62,83 @@
@Override
public void process(ComponentDefinitionRegistry cdr) {
- PassThroughMetadata bundleMeta = (PassThroughMetadata)cdr.getComponentDefinition("blueprintBundle");
- Bundle bundle = (Bundle)bundleMeta.getObject();
-
+ BlueprintContainer container = getComponent(cdr, "blueprintContainer");
+ Bundle bundle = getComponent(cdr, "blueprintBundle");
+ cdr.registerComponentDefinition(createServiceRef(JPA_COORDINATOR, Coordinator.class));
+
Set<String> components = new HashSet<>(cdr.getComponentDefinitionNames());
for (String component : components) {
ComponentMetadata compDef = cdr.getComponentDefinition(component);
if (compDef instanceof MutableBeanMetadata && !((MutableBeanMetadata)compDef).isProcessor()) {
- handleComponent((MutableBeanMetadata)compDef, bundle, cdr);
+ handleComponent((MutableBeanMetadata)compDef, bundle, cdr, container);
}
}
- System.out.println(cdr.getComponentDefinitionNames());
}
- private void handleComponent(MutableBeanMetadata compDef, Bundle bundle, ComponentDefinitionRegistry cdr) {
+ private void handleComponent(MutableBeanMetadata compDef, Bundle bundle, ComponentDefinitionRegistry cdr, BlueprintContainer container) {
+ final String compName = compDef.getId();
if (compDef.getClassName() == null) {
LOGGER.warn("No classname for " + compDef.getId());
return;
}
- String compName = compDef.getId();
Class<?> compClass;
try {
compClass = bundle.loadClass(compDef.getClassName());
- } catch (ClassNotFoundException e) {
+ } catch (final ClassNotFoundException e) {
throw new IllegalArgumentException("Bean class not found " + compDef.getClassName());
}
- BundleContext context = bundle.getBundleContext();
compDef.setFieldInjection(true);
- List<AccessibleObject> jpaAnnotatedMembers = annotationScanner.getJpaAnnotatedMembers(compClass);
- for (AccessibleObject member : jpaAnnotatedMembers) {
- member.setAccessible(true);
- String propName = getName(member);
-
+ List<AccessibleObject> pcMembers = annotationScanner.getJpaAnnotatedMembers(compClass, PersistenceContext.class);
+ for (AccessibleObject member : pcMembers) {
PersistenceContext pcAnn = member.getAnnotation(PersistenceContext.class);
- if (pcAnn != null) {
- LOGGER.info("Adding jpa interceptor for bean {}, prop {} with class {}", compName, propName, compClass);
- Class<?> iface = getType(member);
- if (iface != null) {
- MutableRefMetadata emRef = getServiceRef(cdr, pcAnn.unitName(), iface);
- compDef.addProperty(propName, emRef);
-
- Interceptor interceptor = createInterceptor(context, pcAnn);
- cdr.registerInterceptorWithComponent(compDef, interceptor);
-
- }
- }
-
- PersistenceUnit puAnn = member.getAnnotation(PersistenceUnit.class);
- if (puAnn != null) {
- LOGGER.info("Adding emf proxy for bean {}, prop {} with class {}", compName, propName, compClass);
- MutableRefMetadata emfRef = getServiceRef(cdr, puAnn.unitName(), EntityManagerFactory.class);
- compDef.addProperty(propName, emfRef);
- }
+ String propName = annotationScanner.getName(member);
+ Class<?> iface = annotationScanner.getType(member);
+ LOGGER.debug("Injecting {} into prop {} of bean {} with class {}", iface.getSimpleName(), propName, compName, compClass);
+ MutableRefMetadata ref = getServiceRef(cdr, pcAnn.unitName(), iface);
+ compDef.addProperty(propName, ref);
+
+ MutableRefMetadata emRef = getServiceRef(cdr, pcAnn.unitName(), EntityManager.class);
+ Interceptor interceptor = new JpaInterceptor(container, JPA_COORDINATOR, emRef.getComponentId());
+ cdr.registerInterceptorWithComponent(compDef, interceptor);
+ }
+
+ List<AccessibleObject> puMembers = annotationScanner.getJpaAnnotatedMembers(compClass, PersistenceUnit.class);
+ for (AccessibleObject member : puMembers) {
+ PersistenceUnit puAnn = member.getAnnotation(PersistenceUnit.class);
+ String propName = annotationScanner.getName(member);
+ Class<?> iface = annotationScanner.getType(member);
+ LOGGER.debug("Injecting {} into prop {} of bean {} with class {}", iface.getSimpleName(), propName, compName, compClass);
+ MutableRefMetadata ref = getServiceRef(cdr, puAnn.unitName(), iface);
+ compDef.addProperty(propName, ref);
}
}
private MutableRefMetadata getServiceRef(ComponentDefinitionRegistry cdr, String unitName, Class<?> iface) {
ComponentMetadata serviceRef = cdr.getComponentDefinition(getId(unitName, iface));
if (serviceRef == null) {
- serviceRef = createServiceRef(unitName, iface);
+ serviceRef = createJPAServiceRef(unitName, iface);
cdr.registerComponentDefinition(serviceRef);
- } else {
- LOGGER.info("Using already registered ref " + serviceRef.getId());
}
MutableRefMetadata ref = pc.createMetadata(MutableRefMetadata.class);
ref.setComponentId(serviceRef.getId());
return ref;
}
-
-
-
- private Interceptor createInterceptor(BundleContext context, PersistenceContext pcAnn) {
- String filter = getFilter(EmSupplier.class, pcAnn.unitName());
- EmSupplier supplierProxy = ServiceProxy.create(context, EmSupplier.class, filter);
- Coordinator coordinator = ServiceProxy.create(context, Coordinator.class);
- Interceptor interceptor = new JpaInterceptor(supplierProxy, coordinator);
- return interceptor;
- }
-
- private String getName(AccessibleObject member) {
- if (member instanceof Field) {
- return ((Field)member).getName();
- } else if (member instanceof Method) {
- Method method = (Method)member;
- String name = method.getName();
- if (!name.startsWith("set")) {
- return null;
- }
- return name. substring(3, 4).toLowerCase() + name.substring(4);
- }
- return null;
- }
- private Class<?> getType(AccessibleObject member) {
- if (member instanceof Field) {
- return ((Field)member).getType();
- } else if (member instanceof Method) {
- Method method = (Method)member;
- return method.getParameterTypes()[0];
- }
- return null;
+ @SuppressWarnings("unchecked")
+ ComponentMetadata createServiceRef(String id, Class<?> iface) {
+ final MutableReferenceMetadata refMeta = pc.createMetadata(MutableReferenceMetadata.class);
+ refMeta.setActivation(getDefaultActivation(pc));
+ refMeta.setAvailability(ReferenceMetadata.AVAILABILITY_MANDATORY);
+ refMeta.setRuntimeInterface(iface);
+ refMeta.setTimeout(Integer.parseInt(pc.getDefaultTimeout()));
+ refMeta.setDependsOn((List<String>)Collections.EMPTY_LIST);
+ refMeta.setId(id);
+ return refMeta;
}
@SuppressWarnings("unchecked")
- ComponentMetadata createServiceRef(String unitName, Class<?> iface) {
+ ComponentMetadata createJPAServiceRef(String unitName, Class<?> iface) {
final MutableReferenceMetadata refMeta = pc.createMetadata(MutableReferenceMetadata.class);
refMeta.setActivation(getDefaultActivation(pc));
refMeta.setAvailability(ReferenceMetadata.AVAILABILITY_MANDATORY);
@@ -164,7 +151,7 @@
}
public String getId(String unitName, Class<?> iface) {
- return unitName + "_" + iface.getSimpleName();
+ return unitName + "-" + iface.getSimpleName();
}
private int getDefaultActivation(ParserContext ctx) {
@@ -172,7 +159,9 @@
? ReferenceMetadata.ACTIVATION_EAGER : ReferenceMetadata.ACTIVATION_LAZY;
}
- private String getFilter(Class<?> clazz, String unitName) {
- return String.format("(&(objectClass=%s)(%s=%s))", clazz.getName(), JPA_UNIT_NAME, unitName);
+ @SuppressWarnings("unchecked")
+ private <T>T getComponent(ComponentDefinitionRegistry cdr, String id) {
+ return (T)((PassThroughMetadata) cdr.getComponentDefinition(id)).getObject();
}
+
}
diff --git a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaInterceptor.java b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaInterceptor.java
index 36b94f2..c5c0f62 100644
--- a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaInterceptor.java
+++ b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/impl/JpaInterceptor.java
@@ -24,7 +24,7 @@
import javax.persistence.spi.PersistenceUnitTransactionType;
import org.apache.aries.blueprint.Interceptor;
-import org.apache.aries.jpa.supplier.EmSupplier;
+import org.osgi.service.blueprint.container.BlueprintContainer;
import org.osgi.service.blueprint.reflect.ComponentMetadata;
import org.osgi.service.coordinator.Coordination;
import org.osgi.service.coordinator.Coordinator;
@@ -33,13 +33,17 @@
public class JpaInterceptor implements Interceptor {
private static Logger LOG = LoggerFactory.getLogger(JpaInterceptor.class);
- EmSupplier emSupplier;
+ EntityManager em;
private Boolean cachedIsResourceLocal;
private Coordinator coordinator;
+ private BlueprintContainer container;
+ private String coordinatorId;
+ private String emId;
- public JpaInterceptor(EmSupplier emSupplier, Coordinator coordinator) {
- this.emSupplier = emSupplier;
- this.coordinator = coordinator;
+ public JpaInterceptor(BlueprintContainer container, String coordinatorId, String emId) {
+ this.container = container;
+ this.coordinatorId = coordinatorId;
+ this.emId = emId;
}
public int getRank() {
@@ -47,10 +51,12 @@
}
public Object preCall(ComponentMetadata cm, Method m, Object... parameters) throws Throwable {
+ if (coordinator == null) {
+ initServices();
+ }
try {
LOG.debug("PreCall for bean {}, method {}", cm.getId(), m.getName());
Coordination coordination = coordinator.begin("jpa", 0);
- final EntityManager em = emSupplier.get();
boolean weControlTx = isResourceLocal(em) && !em.getTransaction().isActive();
if (weControlTx) {
coordination.addParticipant(new ResourceLocalTransactionParticipant(em));
@@ -62,6 +68,11 @@
}
}
+ private void initServices() {
+ coordinator = (Coordinator)container.getComponentInstance(coordinatorId);
+ em = (EntityManager)container.getComponentInstance(emId);
+ }
+
public void postCallWithException(ComponentMetadata cm, Method m, Throwable ex, Object preCallToken) {
LOG.debug("PostCallWithException for bean {}, method {}", cm.getId(), m.getName(), ex);
if (preCallToken != null) {
diff --git a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/supplier/impl/EmProxy.java b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/supplier/impl/EmProxy.java
deleted file mode 100644
index 87d5207..0000000
--- a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/supplier/impl/EmProxy.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 WARRANTIESOR 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.aries.jpa.blueprint.supplier.impl;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-import javax.persistence.EntityManager;
-
-import org.apache.aries.jpa.supplier.EmSupplier;
-
-public class EmProxy implements InvocationHandler {
- EmSupplier emSupplier;
-
- public EmProxy(EmSupplier emSupplier) {
- this.emSupplier = emSupplier;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- EntityManager em = emSupplier.get();
- if (em == null) {
- throw new IllegalStateException("EntityManager not available. Make sure you run in an @Transactional method");
- }
- return method.invoke(em, args);
- }
-
- public static EntityManager create(final EmSupplier emSupplier) {
- ClassLoader loader = EntityManager.class.getClassLoader();
- Class<?>[] ifAr = {
- EntityManager.class
- };
- return (EntityManager)Proxy.newProxyInstance(loader, ifAr, new EmProxy(emSupplier));
- }
-
-}
diff --git a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/supplier/impl/ServiceProxy.java b/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/supplier/impl/ServiceProxy.java
deleted file mode 100644
index d49e427..0000000
--- a/jpa-blueprint/src/main/java/org/apache/aries/jpa/blueprint/supplier/impl/ServiceProxy.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 WARRANTIESOR 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.aries.jpa.blueprint.supplier.impl;
-
-import java.io.Closeable;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.blueprint.container.ServiceUnavailableException;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class ServiceProxy implements InvocationHandler {
- private static final int SERVICE_TIMEOUT = 120000;
-
- @SuppressWarnings("rawtypes")
- private ServiceTracker tracker;
-
- private String filterS;
-
- public ServiceProxy(BundleContext context, String filterS) {
- this.filterS = filterS;
- tracker = new ServiceTracker<>(context, createFilter(filterS), null);
- tracker.open();
- }
-
- private Filter createFilter(String filterS) {
- try {
- return filterS == null ? null : FrameworkUtil.createFilter(filterS);
- } catch (InvalidSyntaxException e) {
- throw new IllegalStateException(e);
- }
- }
-
- private Object getService() {
- try {
- Object serviceO = tracker.waitForService(SERVICE_TIMEOUT);
- if (serviceO == null) {
- throw new ServiceUnavailableException("No matching service found after timeout of " + SERVICE_TIMEOUT + " ms", filterS);
- }
- return serviceO;
- } catch (InterruptedException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if ("close".equals(method.getName())) {
- tracker.close();
- return null;
- }
- try {
- return method.invoke(getService(), args);
- } catch (IllegalArgumentException e) {
- throw new IllegalStateException(e);
- } catch (InvocationTargetException e) {
- throw new IllegalStateException(e);
- }
- }
-
- public static <T> T create(BundleContext context, Class<T> iface) {
- return (T) create(context, iface, getFilter(iface));
- }
-
- private static String getFilter(Class<?> clazz) {
- return String.format("(objectClass=%s)", clazz.getName());
- }
-
- @SuppressWarnings("unchecked")
- public static <T> T create(BundleContext context, Class<T> iface, String filter) {
- ClassLoader cl = iface.getClassLoader();
- Class<?>[] ifAr = new Class[] { Closeable.class, iface };
- return (T) Proxy.newProxyInstance(cl, ifAr, new ServiceProxy(context, filter));
- }
-}