/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.foundation.dkv; import java.text.Collator; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.Hashtable; import java.util.Random; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.foundation.DataModification; import org.openflexo.foundation.FlexoObservable; import org.openflexo.foundation.FlexoObserver; import org.openflexo.foundation.Inspectors; import org.openflexo.foundation.dkv.dm.DKVDataModification; import org.openflexo.foundation.dkv.dm.KeyAdded; import org.openflexo.foundation.dkv.dm.KeyRemoved; import org.openflexo.foundation.dkv.dm.LanguageAdded; import org.openflexo.foundation.dkv.dm.LanguageRemoved; import org.openflexo.foundation.utils.FlexoIndexManager; import org.openflexo.foundation.xml.FlexoDKVModelBuilder; import org.openflexo.inspector.InspectableObject; import org.openflexo.logging.FlexoLogger; /** * @author gpolet * */ public class Domain extends DKVObject implements FlexoObserver, InspectableObject { private static final Logger logger = FlexoLogger.getLogger(Domain.class.getPackage().getName()); Vector<Key> keys; ValueHashtable<String, Value> values; private KeyList keyList; private ValueList valueList; public Domain(FlexoDKVModelBuilder builder) { this(builder.dkvModel); initializeDeserialization(builder); } /** * */ public Domain(DKVModel dkv) { super(dkv); keys = new Vector<Key>(); values = new ValueHashtable<String, Value>(); keyList = new KeyList(dkv); valueList = new ValueList(dkv); } /** * Overrides finalizeDeserialization * * @see org.openflexo.foundation.FlexoXMLSerializableObject#finalizeDeserialization(java.lang.Object) */ @Override public void finalizeDeserialization(Object builder) { dkvModel.addObserver(this); Enumeration en = dkvModel.getLanguages().elements(); while (en.hasMoreElements()) { Language lg = (Language) en.nextElement(); lg.addObserver(this); } super.finalizeDeserialization(builder); } @Override final public void delete() { setChanged(); notifyObservers(new DomainDeleted(this)); getDkvModel().deleteObserver(this); getDkvModel().removeFromDomains(this); super.delete(); deleteObservers(); } @Override public void undelete() { super.undelete(); getDkvModel().addObserver(this); getDkvModel().addToDomains(this); } public boolean isKeyNameLegal(String keyName) throws DuplicateDKVObjectException, EmptyStringException { if (keyName == null) { throw new NullPointerException(); } if (keyName.trim().length() == 0) { throw new EmptyStringException(); } Enumeration<Key> en = keys.elements(); while (en.hasMoreElements()) { Key key = en.nextElement(); if (key.getName().equals(keyName)) { throw new DuplicateDKVObjectException(key); } } return true; } public Key addKeyNamed(String keyName) throws EmptyStringException, DuplicateDKVObjectException { if (keyName == null) { throw new NullPointerException(); } if (keyName.trim().length() == 0) { throw new EmptyStringException(); } if (getKeyNamed(keyName) != null) { throw new DuplicateDKVObjectException(getKeyNamed(keyName)); } Key key = new Key(getDkvModel(), this); key.setName(keyName); addToKeys(key); return key; } public void addToKeys(Key key) { if (keys.contains(key)) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Attempt to insert twice the same key."); } return; } Enumeration en = getDkvModel().getLanguages().elements(); while (en.hasMoreElements()) { Language lg = (Language) en.nextElement(); Value v = new Value(getDkvModel(), key, lg); values.put(v.getFullyQualifiedName(), v); } keys.add(key); key.setDomain(this); key.addObserver(this); setChanged(); KeyAdded ka = new KeyAdded(key); notifyObservers(ka); getKeyList().setChanged(); getKeyList().notifyObservers(ka); getValueList().setChanged(); getValueList().notifyObservers(ka); } public void removeFromKeys(Key key) { if (!keys.contains(key)) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Attempt to remove a key that can not be found: " + key.getName()); } return; } keys.remove(key); FlexoIndexManager.reIndexObjectOfArray(getKeys().toArray(new Key[0])); Enumeration en = getDkvModel().getLanguages().elements(); while (en.hasMoreElements()) { Language lg = (Language) en.nextElement(); values.remove(lg.getName() + "." + key.getName()); } key.deleteObserver(this); setChanged(); KeyRemoved kr = new KeyRemoved(key); notifyObservers(kr); getKeyList().setChanged(); getKeyList().notifyObservers(kr); getValueList().setChanged(); getValueList().notifyObservers(kr); } public void removeValueWithKey(String valueFullyQualifiedName) { values.remove(valueFullyQualifiedName); } public Value getValue(Key key, Language lg) { return values.get(lg.getName() + "." + key.getName()); } public Key getKeyNamed(String name) { Enumeration<Key> en = keys.elements(); while (en.hasMoreElements()) { Key key = en.nextElement(); if (key.getName().equals(name)) { return key; } } return null; } /** * Not used for now. * */ private void registerValuesObserving() { if (this.values != null) { Enumeration en = values.elements(); while (en.hasMoreElements()) { Value v = (Value) en.nextElement(); v.addObserver(this); } } } private void unregisterValuesObserving() { if (this.values != null) { Enumeration en = values.elements(); while (en.hasMoreElements()) { Value v = (Value) en.nextElement(); v.deleteObserver(this); } } } public void setValue(Value value) { if (value != null) { values.put(value.getFullyQualifiedName(), value); } } public void setValueForKey(Value v, String fullyQualifiedName) { values.put(fullyQualifiedName, v); } /** * Overrides getFullyQualifiedName * * @see org.openflexo.foundation.FlexoModelObject#getFullyQualifiedName() */ @Override public String getFullyQualifiedName() { return "DOMAIN." + name; } @Override public DKVModel getDkvModel() { return dkvModel; } public void setDkvModel(DKVModel dkvModel) { if (this.dkvModel != null) { this.dkvModel.deleteObserver(this); } this.dkvModel = dkvModel; if (dkvModel != null) { this.dkvModel.addObserver(this); } } public Vector<Key> getKeys() { return keys; } public void setKeys(Vector<Key> keys) { this.keys = keys; } public Object[] getSortedKeys() { if (keys.size() == 0) { return new Object[0]; } Object[] o = new Object[keys.size()]; int i = 0; Enumeration<Key> en = keys.elements(); while (en.hasMoreElements()) { o[i++] = en.nextElement(); } Arrays.sort(o, (Comparator) o[0]); return o; } public Hashtable<String, Value> getValues() { return values; } public void setValues(Hashtable<String, Value> values) { unregisterValuesObserving(); this.values = new ValueHashtable<String, Value>(values); } /** * Overrides update * * @see org.openflexo.foundation.FlexoObserver#update(org.openflexo.foundation.FlexoObservable, * org.openflexo.foundation.DataModification) */ @Override public void update(FlexoObservable observable, DataModification dataModification) { if (dataModification instanceof LanguageRemoved) { Language lg = (Language) ((LanguageRemoved) dataModification).oldValue(); Enumeration<Key> en = getKeys().elements(); while (en.hasMoreElements()) { Key key = en.nextElement(); Value removed = values.remove(lg.getName() + "." + key.getName()); key.notifyValueRemoved(removed); } getValueList().setChanged(); getValueList().notifyObservers(dataModification); } else if (dataModification instanceof LanguageAdded) { Language lg = (Language) ((LanguageAdded) dataModification).newValue(); Enumeration<Key> en = keys.elements(); while (en.hasMoreElements()) { Key key = en.nextElement(); Value v = new Value(getDkvModel(), key, lg); values.put(v.getFullyQualifiedName(), v); key.notifyValueAdded(v); } getValueList().setChanged(); getValueList().notifyObservers(dataModification); } else if (dataModification instanceof DKVDataModification && ((DKVDataModification) dataModification).propertyName().equals("value")) { setChanged(); notifyObservers(dataModification); } } public Object[] getSortedValues() { Object[] values = new Object[keys.size() * getDkvModel().getLanguages().size()]; Object[] keys = getSortedKeys(); Enumeration en = getDkvModel().getLanguages().elements(); int j = 0; while (en.hasMoreElements()) { Language lg = (Language) en.nextElement(); for (int i = 0; i < keys.length; i++) { values[j++] = getValue((Key) keys[i], lg); } } return values; } /** * Overrides getInspectorName * * @see org.openflexo.inspector.InspectableObject#getInspectorName() */ @Override public String getInspectorName() { return Inspectors.IE.DOMAIN_INSPECTOR; } public class KeyList extends DKVObject { /** * @param dl */ public KeyList(DKVModel dl) { super(dl); } public Object[] getKeyList() { return getSortedKeys(); } public Object elementAt(int index) { return getKeyList()[index]; } /** * Overrides getFullyQualifiedName * * @see org.openflexo.foundation.FlexoModelObject#getFullyQualifiedName() */ @Override public String getFullyQualifiedName() { return getName() + ".KEYLIST"; } /** * @param name * @throws DuplicateDKVObjectException * @throws EmptyStringException */ public void addKeyNamed(String name) throws EmptyStringException, DuplicateDKVObjectException { Domain.this.addKeyNamed(name); } /** * Overrides getClassNameKey * * @see org.openflexo.foundation.FlexoModelObject#getClassNameKey() */ @Override public String getClassNameKey() { return "dkv_key_list"; } public Domain getDomain() { return Domain.this; } /** * Overrides isDeleteAble * * @see org.openflexo.foundation.dkv.DKVObject#isDeleteAble() */ @Override public boolean isDeleteAble() { return false; } @Override public void undelete() { } @Override public Vector getAllEmbeddedValidableObjects() { return keys; } } public class ValueList extends DKVObject { /** * @param dl */ public ValueList(DKVModel dl) { super(dl); } public Object[] getValues() { return Domain.this.getSortedValues(); } /** * Overrides getFullyQualifiedName * * @see org.openflexo.foundation.FlexoModelObject#getFullyQualifiedName() */ @Override public String getFullyQualifiedName() { return getName() + ".VALUELIST"; } /** * Overrides getClassNameKey * * @see org.openflexo.foundation.FlexoModelObject#getClassNameKey() */ @Override public String getClassNameKey() { return "dkv_value_list"; } /** * Overrides isDeleteAble * * @see org.openflexo.foundation.dkv.DKVObject#isDeleteAble() */ @Override public boolean isDeleteAble() { return false; } @Override public void undelete() { } @Override public Vector getAllEmbeddedValidableObjects() { Vector reply = new Vector(); reply.addAll(values.values()); return reply; } } public KeyList getKeyList() { return keyList; } public ValueList getValueList() { return valueList; } public class ValueHashtable<K, V> extends Hashtable<K, V> { /** * Calling this method will automatically add observers to all Values of the Hashtable */ public ValueHashtable(Hashtable<K, V> h) { super(h); } /** * */ public ValueHashtable() { super(); } /** * Overrides put * * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object) */ @Override public synchronized V put(K key, V value) { ((Value) value).addObserver(Domain.this); return super.put(key, value); } /** * Overrides remove * * @see java.util.Hashtable#remove(java.lang.Object) */ @Override public synchronized V remove(Object key) { V o = super.remove(key); ((Value) o).deleteObserver(Domain.this); return o; } @Override public synchronized Enumeration keys() { if (isSerializing()) { // Order keys in this case Vector<String> orderedKeys = new Vector<String>(); for (Enumeration en = super.keys(); en.hasMoreElements();) { orderedKeys.add((String) en.nextElement()); } Collections.sort(orderedKeys, new Comparator<String>() { @Override public int compare(String o1, String o2) { return Collator.getInstance().compare(o1, o2); } }); return orderedKeys.elements(); } return super.keys(); } } /** * Overrides getClassNameKey * * @see org.openflexo.foundation.FlexoModelObject#getClassNameKey() */ @Override public String getClassNameKey() { return "dkv_domain"; } /** * Overrides isDeleteAble * * @see org.openflexo.foundation.dkv.DKVObject#isDeleteAble() */ @Override public boolean isDeleteAble() { return true; } public String randomValue() { int r = new Random().nextInt(keys.size()); return getValue((Key) getKeyList().getKeyList()[r], getDkvModel().getLanguages().get(0)).getDisplayString(); } public void putValueForLanguage(Key key, String value, Language language) { Value val = getValue(key, language); if (val == null) { val = new Value(getDkvModel(), key, language); setValue(val); key.notifyValueAdded(val); } val.setValue(value); } public Vector<Language> getLanguages() { return getDkvModel().getLanguages(); } @Override public Vector getAllEmbeddedValidableObjects() { Vector reply = new Vector(); reply.addAll(getKeys()); return reply; } }