/* * This code is distributed under The GNU Lesser General Public License (LGPLv3) * Please visit GNU site for LGPLv3 http://www.gnu.org/copyleft/lesser.html * * Copyright Denis Pavlov 2009 * Web: http://www.genericdtoassembler.org * SVN: https://svn.code.sf.net/p/geda-genericdto/code/trunk/ * SVN (mirror): http://geda-genericdto.googlecode.com/svn/trunk/ */ package com.inspiresoftware.lib.dto.geda.assembler; import com.inspiresoftware.lib.dto.geda.assembler.extension.DataReader; import com.inspiresoftware.lib.dto.geda.assembler.extension.DataWriter; import com.inspiresoftware.lib.dto.geda.assembler.extension.MethodSynthesizer; import com.inspiresoftware.lib.dto.geda.exception.GeDAException; import com.inspiresoftware.lib.dto.geda.exception.GeDARuntimeException; import com.inspiresoftware.lib.dto.geda.exception.InspectionPropertyNotFoundException; import com.inspiresoftware.lib.dto.geda.exception.UnableToCreateInstanceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.beans.PropertyDescriptor; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Proxy for method synthesizer implementation. * * @author denispavlov * @since 1.1.2 * */ class MethodSynthesizerProxy implements MethodSynthesizer { private static final String DEFAULT = "javassist"; private static final Logger LOG = LoggerFactory.getLogger(MethodSynthesizerProxy.class); private static final Map<String, String> FACTORY = new HashMap<String, String>(); static { FACTORY.put("javassist", "com.inspiresoftware.lib.dto.geda.assembler.extension.impl.JavassistMethodSynthesizer"); FACTORY.put("suntools", "com.inspiresoftware.lib.dto.geda.assembler.extension.impl.SunJavaToolsMethodSynthesizer"); FACTORY.put("reflection", "com.inspiresoftware.lib.dto.geda.assembler.extension.impl.ReflectionMethodSynthesizer"); FACTORY.put("bcel", "com.inspiresoftware.lib.dto.geda.assembler.extension.impl.BCELMethodSynthesizer"); } private final Lock lock = new ReentrantLock(); private String synthesizerImpl = FACTORY.get(DEFAULT); private MethodSynthesizer synthesizer; private final Reference<ClassLoader> clRef; /** * Configurable instance. * * @param classLoader class loader namespace */ public MethodSynthesizerProxy(final ClassLoader classLoader) { clRef = new SoftReference<ClassLoader>(classLoader); } /** * Pre-configured instance. * * @param classLoader class loader namespace * @param value synthesizer instance * * @throws UnableToCreateInstanceException when instance cannot be configured */ public MethodSynthesizerProxy(final ClassLoader classLoader, final Object value) throws UnableToCreateInstanceException { this(classLoader); if (value instanceof String) { final String[] configs = ((String) value).split(";"); final String syn = configs[0]; final MethodSynthesizer synth = lazyGet(classLoader, syn); for (int i = 1; i < configs.length; i++) { final String config = configs[i]; final String name = config.substring(0, config.indexOf('=')); final String val = config.substring(name.length() + 1); try { synth.configure(name, val); } catch (GeDAException geda) { throw new UnableToCreateInstanceException(synth.getClass().getCanonicalName(), "Unable to configure with: " + value, geda); } } } else { lazyGet(classLoader, value); } } /** * @return keys for tests. */ static Collection<String> getAvailableSynthesizers() { return FACTORY.keySet(); } /** * @return default key for testing. */ static String getDefaultImpl() { return FACTORY.get(DEFAULT); } /** * @return instance retrieval for test */ MethodSynthesizer getSynthesizer() { return synthesizer; } @SuppressWarnings("unchecked") private MethodSynthesizer lazyGet(final ClassLoader classLoader, final Object value) throws UnableToCreateInstanceException { if (this.synthesizer == null) { try { lock.lock(); if (this.synthesizer == null) { if (value == null) { // default impl final Class clazz = Class.forName(this.synthesizerImpl); this.synthesizer = (MethodSynthesizer) clazz.getConstructor(ClassLoader.class).newInstance(classLoader); } else { if (value instanceof MethodSynthesizer) { this.synthesizer = (MethodSynthesizer) value; this.synthesizerImpl = value.getClass().getCanonicalName(); } else if (value instanceof String) { final String newImpl = FACTORY.get(value); if (newImpl != null) { this.synthesizerImpl = newImpl; } else { this.synthesizerImpl = value.toString(); } final Class clazz = Class.forName(this.synthesizerImpl); this.synthesizer = (MethodSynthesizer) clazz.getConstructor(ClassLoader.class).newInstance(classLoader); } else { throw new UnableToCreateInstanceException("MethodSynthesizer", "Unable to create [" + value + "] implementation: " + "configuration not recognizer (Must be either: " + "MethodSynthesizer instance, or full class name as string, " + "or one of the following markers: " + new ArrayList<String>(FACTORY.keySet()).toString() + ")", null); } } } } catch (UnableToCreateInstanceException rethrow) { throw rethrow; } catch (Exception exp) { throw new UnableToCreateInstanceException("MethodSynthesizer", "Unable to create [" + this.synthesizerImpl + "] implementation: " + exp.getMessage(), exp); } finally { lock.unlock(); } if (this.clRef != null) { this.clRef.clear(); // release class loader as soon as we do not need it anymore. } } else if (value != null) { LOG.warn("Synthesizer is already set to: {}, configuration [{}] ignored", this.synthesizer.getClass().getCanonicalName(), value); } return this.synthesizer; } /** {@inheritDoc} */ public DataReader synthesizeReader(final PropertyDescriptor descriptor) throws InspectionPropertyNotFoundException, UnableToCreateInstanceException, GeDARuntimeException { final MethodSynthesizer syn = lazyGet(clRef.get(), null); return syn.synthesizeReader(descriptor); } /** {@inheritDoc} */ public DataWriter synthesizeWriter(final PropertyDescriptor descriptor) throws InspectionPropertyNotFoundException, UnableToCreateInstanceException, GeDARuntimeException { final MethodSynthesizer syn = lazyGet(clRef.get(), null); return syn.synthesizeWriter(descriptor); } /** {@inheritDoc} */ public boolean configure(final String configuration, final Object value) throws GeDAException { final MethodSynthesizer syn; if ("synthesizerImpl".equals(configuration)) { syn = lazyGet(clRef.get(), value); return true; } else { syn = lazyGet(clRef.get(), null); } return syn.configure(configuration, value); } /** * @return {@link MethodSynthesizerProxy#synthesizerImpl} - full class name. */ @Override public String toString() { return synthesizerImpl; } /** {@inheritDoc} */ @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || synthesizer == null) { return false; } if (getClass() != o.getClass()) { // match proxy against source return (o instanceof MethodSynthesizer) && synthesizer.equals(o); } return synthesizer.equals(((MethodSynthesizerProxy) o).synthesizer); } /** {@inheritDoc} */ @Override public int hashCode() { return synthesizer != null ? synthesizer.hashCode() : super.hashCode(); } /** {@inheritDoc} */ public void releaseResources() { if (synthesizer != null) { synthesizer.releaseResources(); } clRef.clear(); } }