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

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

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * #%L
 * JAXX :: Runtime
 * 
 * $Id: DataContext.java 2225 2011-02-19 20:15:00Z tchemit $
 * $HeadURL: https://nuiton.org/svn/jaxx/tags/jaxx-2.8.5/jaxx-runtime/src/main/java/jaxx/runtime/context/DataContext.java $
 * %%
 * Copyright (C) 2008 - 2010 CodeLutin
 * %%
 * 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 jaxx.runtime.JAXXUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;

/**
 * Un contexte de données qui permet l'utilisation des bindings sur les
 * entrées du contexte.
 *
 * @author tchemit 
 * @since 1.3
 */
public abstract class DataContext {

    /** Logger */
    static private Log log = LogFactory.getLog(DataContext.class);

    public static final DataContextEntry[] EMPTY_DATA_CONTEXT_ENTRY_ARRAY =
            new DataContextEntry[0];

    /** le context qui contient les données */
    protected final DefaultJAXXContext delegate;

    /** la definition de l'entree actuallement selectionnee */
    protected DataContextEntry currentEntry;

    /** to manage properties modifications */
    protected final PropertyChangeSupport pcs;

    protected DataContextEntry[] entries;

    protected final String[] DEFAULT_JAXX_PCS;

    public abstract String getContextPath(Object... e);

    public DataContext(String[] DEFAULT_JAXX_PCS,
                       DataContextEntry[] entries) {
        this.DEFAULT_JAXX_PCS = DEFAULT_JAXX_PCS;
        this.entries = entries;
        delegate = new DefaultJAXXContext() {

            @Override
            protected void setParentContext(JAXXContext parentContext) {
                throw new IllegalStateException(
                        "can not use this method for this type of context");
            }

            @Override
            protected JAXXContext getParentContext() {
                return null;
            }

            @Override
            public  void removeContextValue(Class klazz, String name) {
                if (log.isTraceEnabled()) {
                    log.trace(klazz + " - " + name);
                }
                super.removeContextValue(klazz, name);
            }

            @Override
            public  void setContextValue(T o, String name) {
                if (log.isTraceEnabled()) {
                    log.trace(name + " - " + o.getClass());
                }
                super.setContextValue(o, name);
            }
        };
        pcs = new PropertyChangeSupport(this);
    }

    public DefaultJAXXContext getDelegate() {
        return delegate;
    }

    public Iterable> iterateOnAll() {
        return new Iterable>() {

            @Override
            public Iterator> iterator() {
                return new DataContextEntryIterator(entries);
            }
        };
    }

    public Iterable> iterateToLevel(
            final int level) {
        return new Iterable>() {

            @Override
            public Iterator> iterator() {
                return new DataContextEntryIterator(entries, level);
            }
        };
    }

    public Iterable> reverseIterateOnAll() {

        return new Iterable>() {

            @Override
            public Iterator> iterator() {
                return new DataContextEntryIterator(entries, true);
            }
        };
    }

    public DataContextEntry getCurrentEntry() {
        return currentEntry;
    }

    public DataContextEntry getEntry(String path) {
        for (DataContextEntry scope : reverseIterateOnAll()) {
            if (scope.acceptPath(path)) {
                return scope;
            }
        }
        return null;
    }

    public DataContextEntry getEntry(Class type) {
        for (DataContextEntry scope : iterateOnAll()) {
            if (scope.acceptType(type)) {
                return scope;
            }
        }
        return null;
    }

    public  T getContextValue(DataContextEntry entry, String key) {
        String contextKey = getKey(entry, key);
        T result = delegate.getContextValue(entry.getKlass(), contextKey);
        return result;
    }

    public void setContextValue(DataContextEntry entry,
                                Object value,
                                String key) {
        String contextKey = getKey(entry, key);
        delegate.setContextValue(value, contextKey);
    }

    /**
     * @param entry
     * @param klass
     * @param key
     */
    public void removeContextValue(DataContextEntry entry,
                                   Class klass,
                                   String key) {
        String contextKey = getKey(entry, key);
        delegate.removeContextValue(klass, key);
    }

    public void removeContextValue(DataContextEntry entry,
                                   String key) {
        String contextKey = getKey(entry, key);
        delegate.removeContextValue(entry.getKlass(), contextKey);
    }

    @SuppressWarnings("unchecked")
    public void updateSelectedData(String path,
                                   Object data,
                                   UpdateDataContext updator) {

        if (log.isDebugEnabled()) {
            log.debug("-----------------------------------------------------" +
                      "-----------");
        }
        if (currentEntry != null) {

            if (log.isDebugEnabled()) {
                log.debug("remove from old entry " + currentEntry);
            }
            for (DataContextEntry s : currentEntry) {
                if (log.isDebugEnabled()) {
                    log.debug("remove entry " + s);
                }
                updator.onRemovingData(this, s);
            }
        }

        currentEntry = getEntry(path);

        if (log.isDebugEnabled()) {
            log.debug("new entry " + currentEntry + " for path " + path);
        }

        if (currentEntry != null) {

            for (DataContextEntry s :
                    iterateToLevel(currentEntry.getLevel())) {

                if (log.isDebugEnabled()) {
                    log.debug("add entry " + s);
                }
                updator.onAddingData(this, s, path);
            }
        }
    }

    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();
    }

    public void removeJaxxPropertyChangeListener() {
        PropertyChangeListener[] toRemove =
                JAXXUtil.findJaxxPropertyChangeListener(
                        DEFAULT_JAXX_PCS, getPropertyChangeListeners());
        if (toRemove == null || toRemove.length == 0) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("before remove : " + getPropertyChangeListeners().length);
            log.debug("toRemove : " + toRemove.length);
        }
        for (PropertyChangeListener listener : toRemove) {
            removePropertyChangeListener(listener);
        }
        if (log.isDebugEnabled()) {
            log.debug("after remove : " + getPropertyChangeListeners().length);
        }
    }

    protected void firePropertyChange(String name,
                                      Object oldValue,
                                      Object newValue) {
        pcs.firePropertyChange(name, oldValue, newValue);
    }

    protected String getKey(DataContextEntry entry, String key) {
        String result = null;
        if (key != null) {
            result = entry.hashCode() + "#" + key;
        }
        return result;
    }

    public void close() throws Exception {
        clear();

        // suppression des ecouteurs

        for (PropertyChangeListener l : getPropertyChangeListeners()) {
            removePropertyChangeListener(l);
        }
    }

    public void clear() {
        delegate.clear();
    }

    public static abstract class DataContextEntry implements Iterable> {

        private final int level;

        private final DataContextEntry previous;

        private final DataContextEntry[] parents;

        private Class klass;

        public DataContextEntry(Class klass, DataContextEntry previous) {
            this.previous = previous;
            level = previous.level + 1;
            this.klass = klass;
            parents = new DataContextEntry[level];
            int i = level;
            while (i > 0) {
                parents[--i] = previous;
                previous = previous.previous;
            }
        }

        public DataContextEntry(Class klass) {
            level = 0;
            this.klass = klass;
            previous = null;
            parents = EMPTY_DATA_CONTEXT_ENTRY_ARRAY;
        }

        public Class getKlass() {
            return klass;
        }

        public int getLevel() {
            return level;
        }

        public DataContextEntry[] getParents() {
            return parents;
        }

        public abstract Pattern getPattern();

        public abstract String getContextPath(Object... args);

        public boolean acceptPath(String path) {
            return getPattern().matcher(path).matches();
        }

        public boolean acceptType(Class type) {
            return klass.isAssignableFrom(type);
        }

        @Override
        public Iterator> iterator() {
            int length = parents.length;
            DataContextEntry[] t = new DataContextEntry[length + 1];
            System.arraycopy(parents, 0, t, 0, length);
            t[length] = this;
            return new DataContextEntryIterator(t, true);
        }

        @Override
        public String toString() {
            return super.toString() + "";
        }
    }

    public interface UpdateDataContext {

        void onRemovingData(D context, DataContextEntry entry);

        void onAddingData(D context, DataContextEntry entry, String path);
    }

    public static class DataContextEntryIterator implements Iterator> {

        protected final DataContextEntry[] datas;

        protected final boolean reverse;

        protected final int level;

        protected int index;

        public DataContextEntryIterator(DataContextEntry[] datas) {
            this(datas, false, -1);
        }

        public DataContextEntryIterator(DataContextEntry[] datas,
                                        int level) {
            this(datas, false, level);
        }

        public DataContextEntryIterator(DataContextEntry[] datas,
                                        boolean reverse) {
            this(datas, reverse, -1);
        }

        DataContextEntryIterator(DataContextEntry[] datas,
                                 boolean reverse,
                                 int level) {
            this.datas = datas;
            this.reverse = reverse;
            if (reverse) {
                index = datas.length;
            } else {
                index = -1;
            }
            this.level = level;
        }

        @Override
        public boolean hasNext() {
            if (reverse) {
                return index > 0;
            } else {
                return index + 1 < datas.length &&
                       (level == -1 || datas[index + 1].getLevel() <= level);
            }
        }

        @Override
        public DataContextEntry next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            if (reverse) {
                index--;
            } else {
                index++;
            }
            return datas[index];
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy