org.objectstyle.cayenne.dataview.DataView Maven / Gradle / Ivy
The newest version!
/* ====================================================================
*
* The ObjectStyle Group Software License, version 1.1
* ObjectStyle Group - http://objectstyle.org/
*
* Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
* of the software. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if any,
* must include the following acknowlegement:
* "This product includes software developed by independent contributors
* and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
* or promote products derived from this software without prior written
* permission. For written permission, email
* "andrus at objectstyle dot org".
*
* 5. Products derived from this software may not be called "ObjectStyle"
* or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
* names without prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals and hosted on ObjectStyle Group web site. For more
* information on the ObjectStyle Group, please see
* .
*/
package org.objectstyle.cayenne.dataview;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.text.Format;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.math.NumberUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.objectstyle.cayenne.DataObject;
import org.objectstyle.cayenne.map.EntityResolver;
import org.objectstyle.cayenne.map.ObjAttribute;
import org.objectstyle.cayenne.map.ObjEntity;
import org.objectstyle.cayenne.map.ObjRelationship;
/**
* A root of the view configuration hierarchy. Contains a number of ObjEntityViews.
*
* @since 1.1
* @author Andriy Shapochka
*/
public class DataView {
private Locale locale = Locale.US;
//Data type definitions
private DataTypeSpec dataTypeSpec = new DataTypeSpec();
//Format definitions
private FormatFactory formatFactory = new FormatFactory();
//ObjEntity lookup
private EntityResolver entityResolver;
private Map objEntityViews = new TreeMap();
private Set lookupEntityViewFields;
private LookupCache lookupCache = new LookupCache();
private EventDispatcher fieldValueChangeDispatcher;
//used internally to resolve field lookup dependencies
private Map lookupReferenceTable;
public DataView() {
}
public EntityResolver getEntityResolver() {
return entityResolver;
}
public void setEntityResolver(EntityResolver entityResolver) {
Validate.notNull(entityResolver);
this.entityResolver = entityResolver;
}
public void load(File[] xmlSources) throws IOException {
Validate.noNullElements(xmlSources);
SAXBuilder builder = new SAXBuilder();
Document[] documents = new Document[xmlSources.length];
for (int i = 0; i < xmlSources.length; i++) {
try {
documents[i] = builder.build(xmlSources[i]);
}
catch (JDOMException ex) {
ex.printStackTrace();
}
}
load(documents);
}
public void load(URL[] xmlSources) throws IOException {
Validate.noNullElements(xmlSources);
SAXBuilder builder = new SAXBuilder();
Document[] documents = new Document[xmlSources.length];
for (int i = 0; i < xmlSources.length; i++) {
try {
documents[i] = builder.build(xmlSources[i]);
}
catch (JDOMException ex) {
ex.printStackTrace();
}
}
load(documents);
}
public void load(Reader[] xmlSources) throws IOException {
Validate.noNullElements(xmlSources);
SAXBuilder builder = new SAXBuilder();
Document[] documents = new Document[xmlSources.length];
for (int i = 0; i < xmlSources.length; i++) {
try {
documents[i] = builder.build(xmlSources[i]);
}
catch (JDOMException ex) {
ex.printStackTrace();
}
}
load(documents);
}
public void load(InputStream[] xmlSources) throws IOException {
Validate.noNullElements(xmlSources);
SAXBuilder builder = new SAXBuilder();
Document[] documents = new Document[xmlSources.length];
for (int i = 0; i < xmlSources.length; i++) {
try {
documents[i] = builder.build(xmlSources[i]);
}
catch (JDOMException ex) {
ex.printStackTrace();
}
}
load(documents);
}
public void load(Document[] views) {
Validate.noNullElements(views);
lookupReferenceTable = new HashMap();
for (int i = 0; i < views.length; i++) {
Element root = views[i].getRootElement();
List entityViews = root.getChildren("obj-entity-view");
for (Iterator j = entityViews.iterator(); j.hasNext();) {
Element entityViewElement = (Element) j.next();
loadEntityView(entityViewElement);
}
}
resolveLookupReferences();
lookupReferenceTable = null;
}
private void resolveLookupReferences() {
lookupEntityViewFields = new HashSet();
for (Iterator i = lookupReferenceTable.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
ObjEntityViewField field = (ObjEntityViewField) entry.getKey();
String[] lookupDescriptor = (String[]) entry.getValue();
ObjEntityView lookupEntityView = getObjEntityView(lookupDescriptor[0]);
ObjEntityViewField lookupField = lookupEntityView
.getField(lookupDescriptor[1]);
field.setLookupField(lookupField);
lookupEntityViewFields.add(lookupField);
}
}
private void loadEntityView(Element element) {
String name = element.getAttributeValue("name");
Validate.isTrue(name != null && !objEntityViews.containsKey(name));
String objEntityName = element.getAttributeValue("obj-entity-name");
Validate.notNull(objEntityName);
ObjEntity objEntity = entityResolver.getObjEntity(objEntityName);
ObjEntityView entityView = new ObjEntityView();
entityView.setName(name);
entityView.setObjEntity(objEntity);
objEntityViews.put(name, entityView);
entityView.setOwner(this);
List fields = element.getChildren("field");
for (Iterator i = fields.iterator(); i.hasNext();) {
Element fieldElement = (Element) i.next();
loadField(entityView, fieldElement);
}
}
private void loadField(ObjEntityView entityView, Element element) {
String name = element.getAttributeValue("name");
ObjEntityViewField field = new ObjEntityViewField();
field.setName(name);
String prefIndex = element.getAttributeValue("pref-index");
field.setPreferredIndex(NumberUtils.toInt(prefIndex, -1));
entityView.insertField(field);
String calcType = element.getAttributeValue("calc-type");
Validate.notNull(calcType);
CalcTypeEnum fieldCalcType = CalcTypeEnum.getEnum(calcType);
Validate.isTrue(
CalcTypeEnum.NO_CALC_TYPE.equals(fieldCalcType)
|| CalcTypeEnum.LOOKUP_TYPE.equals(fieldCalcType),
"Calc Type not supported yet: ",
fieldCalcType);
field.setCalcType(fieldCalcType);
ObjEntity objEntity = entityView.getObjEntity();
if (CalcTypeEnum.NO_CALC_TYPE.equals(fieldCalcType)) {
String objAttributeName = element.getAttributeValue("obj-attribute-name");
Validate.notNull(objAttributeName);
ObjAttribute objAttribute = (ObjAttribute) objEntity
.getAttribute(objAttributeName);
field.setObjAttribute(objAttribute);
}
else if (CalcTypeEnum.LOOKUP_TYPE.equals(fieldCalcType)) {
String objRelationshipName = element
.getAttributeValue("obj-relationship-name");
Validate.notNull(objRelationshipName);
ObjRelationship objRelationship = (ObjRelationship) objEntity
.getRelationship(objRelationshipName);
field.setObjRelationship(objRelationship);
Element lookupElement = element.getChild("lookup");
Validate.notNull(lookupElement);
String lookupEntityView = lookupElement
.getAttributeValue("obj-entity-view-name");
Validate.notNull(lookupEntityView);
String lookupEntityField = lookupElement.getAttributeValue("field-name");
Validate.notNull(lookupEntityField);
String[] lookupDescriptor = new String[] {
lookupEntityView, lookupEntityField
};
lookupReferenceTable.put(field, lookupDescriptor);
}
String dataType = element.getAttributeValue("data-type");
Validate.notNull(dataType);
field.setDataType(dataTypeSpec.getDataType(dataType));
String editable = element.getAttributeValue("editable");
field.setEditable(BooleanUtils.toBoolean(editable));
String visible = element.getAttributeValue("visible");
field.setVisible(BooleanUtils.toBoolean(visible));
Element captionElement = element.getChild("caption");
if (captionElement != null)
field.setCaption(StringUtils.stripToEmpty(captionElement.getText()));
Element editFormatElement = element.getChild("edit-format");
if (editFormatElement != null) {
String formatClassName = editFormatElement.getAttributeValue("class");
Validate.notNull(formatClassName);
Class formatClass;
try {
formatClass = Class.forName(formatClassName);
Map parameters = DataView.childrenToMap(editFormatElement);
Format format = formatFactory.createFormat(
formatClass,
locale,
parameters);
field.setEditFormat(format);
}
catch (ClassNotFoundException ex) {
}
}
Element displayFormatElement = element.getChild("display-format");
if (displayFormatElement != null) {
String formatClassName = displayFormatElement.getAttributeValue("class");
Validate.notNull(formatClassName);
Class formatClass;
try {
formatClass = Class.forName(formatClassName);
Map parameters = DataView.childrenToMap(displayFormatElement);
Format format = formatFactory.createFormat(
formatClass,
locale,
parameters);
field.setDisplayFormat(format);
}
catch (ClassNotFoundException ex) {
}
}
Element defaultValueElement = element.getChild("default-value");
if (defaultValueElement != null) {
String defaultValueStr = StringUtils.stripToEmpty(defaultValueElement
.getText());
Object defaultValue = dataTypeSpec.create(
field.getDataType(),
defaultValueStr);
field.setDefaultValue(defaultValue);
}
}
public Set getObjEntityViewNames() {
return Collections.unmodifiableSet(objEntityViews.keySet());
}
public Collection getObjEntityViews() {
return Collections.unmodifiableCollection(objEntityViews.values());
}
public ObjEntityView getObjEntityView(String viewName) {
return (ObjEntityView) objEntityViews.get(viewName);
}
public LookupCache getLookupCache() {
return lookupCache;
}
public void setLookupCache(LookupCache lookupCache) {
Validate.notNull(lookupCache);
this.lookupCache = lookupCache;
}
public Set getLookupObjEntityViewFields() {
return Collections.unmodifiableSet(lookupEntityViewFields);
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
public DataTypeSpec getDataTypeSpec() {
return dataTypeSpec;
}
public void setDataTypeSpec(DataTypeSpec dataTypeSpec) {
this.dataTypeSpec = dataTypeSpec;
}
public FormatFactory getFormatFactory() {
return formatFactory;
}
public void setFormatFactory(FormatFactory formatFactory) {
this.formatFactory = formatFactory;
}
private static Map childrenToMap(Element element) {
List children = element.getChildren();
if (children.isEmpty())
return Collections.EMPTY_MAP;
else {
Map map = new HashMap(children.size());
for (Iterator i = children.iterator(); i.hasNext();) {
Element child = (Element) i.next();
map.put(child.getName(), StringUtils.stripToNull(child.getText()));
}
return map;
}
}
public void addFieldValueChangeListener(FieldValueChangeListener listener) {
fieldValueChangeDispatcher = EventDispatcher.add(
fieldValueChangeDispatcher,
listener);
}
public void removeFieldValueChangeListener(FieldValueChangeListener listener) {
fieldValueChangeDispatcher = EventDispatcher.remove(
fieldValueChangeDispatcher,
listener);
}
public void clearFieldValueChangeListeners() {
if (fieldValueChangeDispatcher != null) {
fieldValueChangeDispatcher.clear();
fieldValueChangeDispatcher = null;
}
}
public void fireFieldValueChangeEvent(
ObjEntityViewField source,
DataObject modifiedObject,
Object oldValue,
Object newValue) {
if (fieldValueChangeDispatcher != null && source.getRootOwner() == this) {
fieldValueChangeDispatcher.dispatch(new FieldValueChangeEvent(
source,
modifiedObject,
oldValue,
newValue));
}
}
}