All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jaxx.runtime.context.DefaultApplicationContext Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * #%L
 * JAXX :: Runtime
 * %%
 * Copyright (C) 2008 - 2014 Code Lutin, Tony Chemit
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */
package jaxx.runtime.context;

import jaxx.runtime.JAXXContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * The default context to be used for an application.
 * 

* This extends the {@link DefaultJAXXContext} and add a possibility to * auto-instanciate some classes asked via {@link #getContextValue(Class)} and * {@link #getContextValue(Class, String)} methods. *

* To registred a such class, just annotate your class with {@link AutoLoad}. * * @author Tony Chemit - [email protected] * @see DefaultJAXXContext * @since 1.2 */ public class DefaultApplicationContext extends DefaultJAXXContext { /** * A class annotated @AutoLoad is used by context to auto instanciate * the class when required. *

* Note : A such class always have a public default constructor. * * @author Tony Chemit - [email protected] * @version 1.0, 21/02/09 * @since 1.2 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface AutoLoad { //TODO use this to add a method to init String initMethod() default ""; } /** * A class annotated @MethodAccess is used by context to obtain the * value of an entry via a declared method. *

* Note : A such class must have a method called {@link #methodName()} with * a single String parameter. * * @author Tony Chemit - [email protected] * @version 1.0, 21/02/09 * @since 1.2 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MethodAccess { /** * Define a forward to a target class. When the target class will be * asked with method {@link JAXXContext#getContextValue(Class, String)} * it will be delegating to this class. * * @return the forwarded class */ Class target() default Object.class; /** @return the name of the method to access data */ String methodName(); } /** Map of forwarded classes (key) to classes (values). */ protected Map, Class> forwards; /** * Map of entries to watch associated with the property to fires if a * modification was found. */ protected Map, String> entryListened; public DefaultApplicationContext() { forwards = new HashMap, Class>(); pcs = new PropertyChangeSupport(this); } /** Logger */ static private final Log log = LogFactory.getLog(DefaultApplicationContext.class); /** to manage properties modifications */ protected PropertyChangeSupport pcs; @SuppressWarnings({"unchecked"}) @Override public T getContextValue(Class clazz, String name) { Object value; MethodAccess access; Class realClass; if (forwards.containsKey(clazz)) { // this is a forward class realClass = forwards.get(clazz); // always call the forwarder with no name value = getContextValue(realClass, null); if (log.isDebugEnabled()) { log.debug("detect forward from " + clazz + " to " + realClass + " (" + value + ")"); } } else { realClass = clazz; value = super.getContextValue(realClass, name); } //TC-20091007 TODO Make possible use of named autoload entries //(add a parameter on AutoLoad annotation) if (value == null) { AutoLoad anno = clazz.getAnnotation(AutoLoad.class); if (anno == null) { // no annotation, so do nothing return null; } if (name != null) { throw new IllegalArgumentException( "an " + AutoLoad.class.getName() + " can not have " + "a named context but was call with this one : " + name); } value = newInstance(clazz); if (!anno.initMethod().trim().isEmpty()) { // apply method on class newAccess(clazz, value, anno.initMethod().trim()); } if (log.isDebugEnabled()) { log.debug("new instance " + clazz + " : " + value); } // save new instance setContextValue(value, null); } access = realClass.getAnnotation(MethodAccess.class); if (access != null) { if (name == null) { if (!Object.class.equals(access.target())) { // register forward Class targetClass = access.target(); if (!forwards.containsKey(targetClass)) { // register forward forwards.put(targetClass, clazz); if (log.isDebugEnabled()) { log.debug("register forward from " + targetClass + " to " + clazz); } } } } else { // specialized access value = newAccess(realClass, value, access.methodName(), name); } } return (T) value; } @Override public void removeContextValue(Class klass, String name) { Entry, Class> entry; if (name == null && forwards.containsValue(klass)) { // remove forward Iterator, Class>> itr = forwards.entrySet().iterator(); while (itr.hasNext()) { entry = itr.next(); if (entry.getValue().equals(klass)) { itr.remove(); if (log.isDebugEnabled()) { log.debug("removed forward from " + entry.getKey() + " to " + klass); } break; } } } //FIXME should update forwards state JAXXContextEntryDef entryToDel = getEntry(klass, name); Object t = remove0(klass, name); if (log.isDebugEnabled()) { log.debug("removed object = " + t); } if (t != null && entryToDel != null) { // a value was removed // notify listeners fireEntryChanged(entryToDel, t, null); } // super.removeContextValue(klass, name); } @Override public void setContextValue(T o, String name) { // super.setContextValue(o, name); if (name == null && PARENT_CONTEXT_ENTRY.accept2(o.getClass(), null)) { setParentContext((JAXXContext) o); return; } JAXXContextEntryDef entry = getKey(name, o.getClass()); // first remove entry Object oldValue = remove0(o.getClass(), name); if (oldValue != null) { if (log.isDebugEnabled()) { log.debug("remove value " + oldValue.getClass() + " for " + entry); } } // then can put safely data.put(entry, o); if (log.isDebugEnabled()) { log.debug("[" + name + "] set value for entry " + entry); } // firezs fireEntryChanged(entry.getKlass(), name, oldValue, o); } /** * To add a listen modification of the given entry in the context. * * @param entry the entry to listen * @param name the property name to fire if necessary * @param listener the listener to notify if entry has changed * @since 2.0.1 */ public void addPropertyChangeListener(JAXXContextEntryDef entry, String name, PropertyChangeListener listener) { if (entryListened == null) { entryListened = new HashMap, String>(); } entryListened.put(entry, name); if (log.isDebugEnabled()) { log.debug("[" + name + "] for " + entry); } pcs.addPropertyChangeListener(name, listener); } /** * To remove a listen modification of the given entry in the context. * * @param entry the entry to listen * @param name the property name to fire if necessary * @param listener the listener to notify if entry has changed * @since 2.0.1 */ public void removePropertyChangeListener(JAXXContextEntryDef entry, String name, PropertyChangeListener listener) { if (entryListened == null) { entryListened = new HashMap, String>(); } entryListened.remove(entry); pcs.removePropertyChangeListener(name, listener); } public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { pcs.addPropertyChangeListener(propertyName, listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { pcs.removePropertyChangeListener(propertyName, listener); } public synchronized boolean hasListeners(String propertyName) { return pcs.hasListeners(propertyName); } public synchronized PropertyChangeListener[] getPropertyChangeListeners( String propertyName) { return pcs.getPropertyChangeListeners(propertyName); } public synchronized PropertyChangeListener[] getPropertyChangeListeners() { return pcs.getPropertyChangeListeners(); } protected void fireEntryChanged(Class klass, String name, Object oldValue, Object newValue) { // a value was removed if (entryListened != null) { // look if the entry was listened if (log.isTraceEnabled()) { log.trace("data size : " + data.size()); for (Entry, Object> e : data.entrySet()) { log.trace(e.getKey()); } } JAXXContextEntryDef entry2 = getEntry(klass, name); if (log.isDebugEnabled()) { log.debug("[" + name + "] : try to find a changer for " + entry2); } if (entry2 != null) { // entry find directly on this context String propertyName = entryListened.get(entry2); if (log.isTraceEnabled()) { log.trace("registred property name = " + propertyName); } if (propertyName != null) { if (log.isDebugEnabled()) { log.debug("will notify modification on " + entry2); } // fires the removed firePropertyChange(propertyName, oldValue, newValue); } } } } protected void fireEntryChanged(JAXXContextEntryDef entryDef, Object oldValue, Object newValue) { // a value was removed if (entryListened != null) { // look if the entry was listened if (log.isTraceEnabled()) { log.trace("data size : " + data.size()); for (Entry, Object> e : data.entrySet()) { log.trace(e.getKey()); } } // JAXXContextEntryDef entry2 = getEntry(klass, name); // if (log.isDebugEnabled()) { // log.debug("[" + name + "] : try to find a changer for " + entry2); // } if (entryDef != null) { // entry find directly on this context String propertyName = entryListened.get(entryDef); if (log.isTraceEnabled()) { log.trace("registred property name = " + propertyName); } if (propertyName != null) { if (log.isDebugEnabled()) { log.debug("will notify modification on " + entryDef); } // fires the removed firePropertyChange(propertyName, oldValue, newValue); } } } } protected Object newInstance(Class clazz) throws IllegalArgumentException { Object value; Constructor constructor; try { constructor = clazz.getConstructor(); // auto instanciate the class if (constructor == null) { throw new IllegalArgumentException( clazz + " has no public constructor"); } } catch (NoSuchMethodException ex) { throw new IllegalArgumentException(ex); } catch (SecurityException ex) { throw new IllegalArgumentException(ex); } try { value = constructor.newInstance(); } catch (InstantiationException ex) { throw new IllegalArgumentException(ex); } catch (IllegalAccessException ex) { throw new IllegalArgumentException(ex); } catch (InvocationTargetException ex) { throw new IllegalArgumentException(ex); } return value; } protected Object newAccess( Class clazz, Object parent, String methodName, String name) throws IllegalArgumentException { Object value; try { Method m = clazz.getMethod(methodName, String.class); value = m.invoke(parent, name); return value; } catch (NoSuchMethodException ex) { throw new IllegalArgumentException(ex); } catch (SecurityException ex) { throw new IllegalArgumentException(ex); } catch (IllegalAccessException ex) { throw new IllegalArgumentException(ex); } catch (InvocationTargetException ex) { throw new IllegalArgumentException(ex); } } protected Object newAccess( Class clazz, Object parent, String methodName) throws IllegalArgumentException { Object value; try { Method m = clazz.getMethod(methodName); value = m.invoke(parent); return value; } catch (NoSuchMethodException ex) { throw new IllegalArgumentException(ex); } catch (SecurityException ex) { throw new IllegalArgumentException(ex); } catch (IllegalAccessException ex) { throw new IllegalArgumentException(ex); } catch (InvocationTargetException ex) { throw new IllegalArgumentException(ex); } } protected void firePropertyChange(String name, Object oldValue, Object newValue) { pcs.firePropertyChange(name, oldValue, newValue); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy