jaxx.runtime.context.DataContext Maven / Gradle / Ivy
/*
* #%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 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 Tony Chemit - [email protected]
* @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 extends DataContextEntry>> iterateOnAll() {
return new Iterable>() {
@Override
public Iterator> iterator() {
return new DataContextEntryIterator(entries);
}
};
}
public Iterable extends DataContextEntry>> iterateToLevel(
final int level) {
return new Iterable>() {
@Override
public Iterator> iterator() {
return new DataContextEntryIterator(entries, level);
}
};
}
public Iterable extends DataContextEntry>> 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