| /******************************************************************************* |
| * Copyright (c) 2003, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wst.common.frameworks.internal.datamodel; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelOperation; |
| import org.eclipse.wst.common.frameworks.datamodel.DataModelEvent; |
| import org.eclipse.wst.common.frameworks.datamodel.DataModelPropertyDescriptor; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModel; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModelListener; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModelOperation; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModelProperties; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider; |
| import org.eclipse.wst.common.frameworks.internal.WTPResourceHandler; |
| |
| public final class DataModelImpl implements IDataModel, IDataModelListener { |
| |
| private static final String PROPERTY_NOT_LOCATED_ = WTPResourceHandler.getString("20"); //$NON-NLS-1$ |
| private static final String NESTED_MODEL_NOT_LOCATED = WTPResourceHandler.getString("21"); //$NON-NLS-1$ |
| |
| private static final DataModelPropertyDescriptor[] NO_DESCRIPTORS = new DataModelPropertyDescriptor[0]; |
| |
| private Collection basePropertyNames; |
| private Collection allPropertyNames; |
| private Collection nestedPropertyNames; // lazily initialzed when nested models added |
| private Map propertyValues = new Hashtable(); |
| private Map nestedModels; |
| private Set nestingModels; |
| private List listeners; |
| |
| private IDataModelProvider provider; |
| |
| public DataModelImpl(IDataModelProvider dataModelProvider) { |
| init(dataModelProvider); |
| } |
| |
| private void init(IDataModelProvider dataModelProvider) { |
| this.provider = dataModelProvider; |
| dataModelProvider.setDataModel(this); |
| Collection propertyNames = dataModelProvider.getPropertyNames(); |
| HashSet properties = new HashSet(); |
| properties.addAll(propertyNames); |
| |
| properties.add(IDataModelProperties.ALLOW_EXTENSIONS); |
| properties.add(IDataModelProperties.RESTRICT_EXTENSIONS); |
| basePropertyNames = Collections.unmodifiableCollection(properties); |
| allPropertyNames = new HashSet(); |
| allPropertyNames.addAll(basePropertyNames); |
| dataModelProvider.init(); |
| } |
| |
| public boolean isBaseProperty(String propertyName) { |
| return basePropertyNames.contains(propertyName); |
| } |
| |
| public Collection getBaseProperties() { |
| return Collections.unmodifiableCollection(basePropertyNames); |
| } |
| |
| public boolean isProperty(String propertyName) { |
| return allPropertyNames.contains(propertyName); |
| } |
| |
| public Collection getAllProperties() { |
| return Collections.unmodifiableCollection(allPropertyNames); |
| } |
| |
| public boolean isNestedProperty(String propertyName) { |
| return null != nestedPropertyNames && nestedPropertyNames.contains(propertyName); |
| } |
| |
| public Collection getNestedProperties() { |
| return Collections.unmodifiableCollection(nestedPropertyNames); |
| } |
| |
| private void checkValidPropertyName(String propertyName) { |
| if (!isProperty(propertyName)) { |
| throw new RuntimeException(PROPERTY_NOT_LOCATED_ + propertyName); |
| } |
| } |
| |
| private DataModelImpl getOwningDataModel(String propertyName) { |
| checkValidPropertyName(propertyName); |
| return searchNestedModels(propertyName); |
| } |
| |
| private DataModelImpl searchNestedModels(String propertyName) { |
| if (isBaseProperty(propertyName)) { |
| return this; |
| } else if (nestedModels != null) { |
| DataModelImpl dataModel = null; |
| Object[] keys = nestedModels.keySet().toArray(); |
| for (int i = 0; i < keys.length; i++) { |
| dataModel = (DataModelImpl) nestedModels.get(keys[i]); |
| if (dataModel.isProperty(propertyName)) { |
| return dataModel.searchNestedModels(propertyName); |
| } |
| } |
| } |
| throw new RuntimeException(PROPERTY_NOT_LOCATED_ + propertyName); |
| } |
| |
| public Object getProperty(String propertyName) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| if (dataModel.propertyValues.containsKey(propertyName)) { |
| return dataModel.propertyValues.get(propertyName); |
| } |
| return dataModel.provider.getDefaultProperty(propertyName); |
| } |
| |
| public Object getDefaultProperty(String propertyName) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| return dataModel.provider.getDefaultProperty(propertyName); |
| } |
| |
| public int getIntProperty(String propertyName) { |
| Object prop = getProperty(propertyName); |
| if (prop == null) |
| return -1; |
| return ((Integer) prop).intValue(); |
| } |
| |
| public boolean getBooleanProperty(String propertyName) { |
| Object prop = getProperty(propertyName); |
| if (prop == null) |
| return false; |
| return ((Boolean) prop).booleanValue(); |
| } |
| |
| public String getStringProperty(String propertyName) { |
| Object prop = getProperty(propertyName); |
| if (prop == null) |
| return ""; //$NON-NLS-1$ |
| return (String) prop; |
| } |
| |
| public boolean isPropertySet(String propertyName) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| return dataModel.propertyValues.containsKey(propertyName); |
| } |
| |
| public boolean isPropertyEnabled(String propertyName) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| return dataModel.provider.isPropertyEnabled(propertyName); |
| } |
| |
| |
| public void setProperty(String propertyName, Object propertyValue) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| dataModel.internalSetProperty(propertyName, propertyValue); |
| } |
| |
| private void internalSetProperty(String propertyName, Object propertyValue) { |
| Object oldValue = propertyValues.get(propertyName); |
| if (valueChanged(propertyValue, oldValue)) { |
| if (null != propertyValue) |
| propertyValues.put(propertyName, propertyValue); |
| else if (propertyValues.containsKey(propertyName)) |
| propertyValues.remove(propertyName); |
| if (provider.propertySet(propertyName, propertyValue)) { |
| notifyPropertyChange(propertyName, DataModelEvent.VALUE_CHG); |
| } |
| } |
| } |
| |
| private boolean valueChanged(Object o1, Object o2) { |
| return o1 != o2 && ((o1 != null && !o1.equals(o2)) || !o2.equals(o1)); |
| } |
| |
| public void setIntProperty(String propertyName, int value) { |
| setProperty(propertyName, new Integer(value)); |
| } |
| |
| public void setBooleanProperty(String propertyName, boolean value) { |
| setProperty(propertyName, (value) ? Boolean.TRUE : Boolean.FALSE); |
| } |
| |
| public void setStringProperty(String propertyName, String value) { |
| setProperty(propertyName, value); |
| } |
| |
| public boolean addNestedModel(String modelName, IDataModel dataModel) { |
| if (this == dataModel) { |
| return false; |
| } |
| if (null == nestedModels) { |
| nestedModels = new Hashtable(); |
| nestedPropertyNames = new HashSet(); |
| } |
| DataModelImpl nestedDataModel = (DataModelImpl) dataModel; |
| if (null == nestedDataModel.nestingModels) { |
| nestedDataModel.nestingModels = new HashSet(); |
| } |
| if (nestedDataModel.nestingModels.contains(this)) { |
| return false; |
| } |
| nestedDataModel.nestingModels.add(this); |
| |
| nestedModels.put(modelName, nestedDataModel); |
| |
| addNestedProperties(nestedDataModel.allPropertyNames); |
| nestedDataModel.addListener(this); |
| return true; |
| } |
| |
| private void addNestedProperties(Collection nestedProperties) { |
| boolean propertiesAdded = allPropertyNames.addAll(nestedProperties); |
| propertiesAdded = nestedPropertyNames.addAll(nestedProperties) || propertiesAdded; |
| // Pass the new properties up the nesting chain |
| if (propertiesAdded && nestingModels != null) { |
| Iterator iterator = nestingModels.iterator(); |
| while (iterator.hasNext()) { |
| ((DataModelImpl) iterator.next()).addNestedProperties(nestedProperties); |
| } |
| } |
| } |
| |
| public Collection getNestedModels() { |
| return nestedModels != null ? Collections.unmodifiableCollection(nestedModels.values()) : Collections.EMPTY_SET; |
| } |
| |
| public Collection getNestedModelNames() { |
| return nestedModels != null ? Collections.unmodifiableCollection(nestedModels.keySet()) : Collections.EMPTY_SET; |
| } |
| |
| public Collection getNestingModels() { |
| return nestingModels != null ? Collections.unmodifiableCollection(nestingModels) : Collections.EMPTY_SET; |
| } |
| |
| public IDataModel removeNestedModel(String modelName) { |
| if (!isNestedModel(modelName)) { |
| return null; |
| } |
| DataModelImpl model = (DataModelImpl) nestedModels.remove(modelName); |
| model.nestingModels.remove(this); |
| removeNestedProperties(model.allPropertyNames); |
| model.removeListener(this); |
| if (nestedModels.isEmpty()) { |
| nestedModels = null; |
| } |
| return model; |
| } |
| |
| private void removeNestedProperties(Collection nestedProperties) { |
| Iterator iterator = nestedProperties.iterator(); |
| String property = null; |
| boolean keepProperty = false; |
| Set nestedPropertiesToRemove = null; |
| while (iterator.hasNext()) { |
| keepProperty = false; |
| property = (String) iterator.next(); |
| if (basePropertyNames.contains(property)) { |
| keepProperty = true; |
| } |
| if (!keepProperty && nestedModels != null) { |
| Iterator nestedModelsIterator = nestedModels.values().iterator(); |
| while (!keepProperty && nestedModelsIterator.hasNext()) { |
| DataModelImpl nestedModel = (DataModelImpl) nestedModelsIterator.next(); |
| if (nestedModel.isProperty(property)) { |
| keepProperty = true; |
| } |
| } |
| } |
| if (!keepProperty) { |
| if (null == nestedPropertiesToRemove) { |
| nestedPropertiesToRemove = new HashSet(); |
| } |
| nestedPropertiesToRemove.add(property); |
| } |
| } |
| |
| if (null != nestedPropertiesToRemove) { |
| allPropertyNames.removeAll(nestedPropertiesToRemove); |
| nestedPropertyNames.removeAll(nestedPropertiesToRemove); |
| if (nestingModels != null) { |
| Iterator nestingModelsIterator = nestingModels.iterator(); |
| while (nestingModelsIterator.hasNext()) { |
| ((DataModelImpl) nestingModelsIterator.next()).removeNestedProperties(nestedPropertiesToRemove); |
| } |
| } |
| } |
| } |
| |
| public boolean isNestedModel(String modelName) { |
| return modelName != null && null != nestedModels && nestedModels.containsKey(modelName); |
| } |
| |
| public IDataModel getNestedModel(String modelName) { |
| IDataModel dataModel = (null != nestedModels && null != modelName) ? (IDataModel) nestedModels.get(modelName) : null; |
| if (null == dataModel) { |
| throw new RuntimeException(NESTED_MODEL_NOT_LOCATED + modelName); |
| } |
| return dataModel; |
| } |
| |
| public DataModelPropertyDescriptor[] getValidPropertyDescriptors(String propertyName) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| DataModelPropertyDescriptor[] descriptors = dataModel.provider.getValidPropertyDescriptors(propertyName); |
| return descriptors == null ? NO_DESCRIPTORS : descriptors; |
| } |
| |
| public DataModelPropertyDescriptor getPropertyDescriptor(String propertyName) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| DataModelPropertyDescriptor descriptor = dataModel.provider.getPropertyDescriptor(propertyName); |
| return descriptor == null ? new DataModelPropertyDescriptor(getProperty(propertyName)) : descriptor; |
| } |
| |
| public void notifyPropertyChange(String propertyName, int flag) { |
| if (flag == DEFAULT_CHG) { |
| if (isPropertySet(propertyName)) { |
| return; |
| } |
| flag = VALUE_CHG; |
| } |
| notifyListeners(new DataModelEvent(this, propertyName, flag)); |
| } |
| |
| private void notifyListeners(DataModelEvent event) { |
| if (listeners != null && !listeners.isEmpty()) { |
| IDataModelListener listener; |
| for (int i = 0; i < listeners.size(); i++) { |
| listener = (IDataModelListener) listeners.get(i); |
| if (listener != event.getDataModel()) { |
| listener.propertyChanged(event); |
| } |
| } |
| } |
| } |
| |
| public void propertyChanged(DataModelEvent event) { |
| notifyListeners(event); |
| } |
| |
| public IStatus validate() { |
| return validate(true); |
| } |
| |
| public IStatus validate(boolean stopOnFirstFailure) { |
| IStatus status = null; |
| IStatus propStatus; |
| String propName; |
| Iterator it; |
| for (int i = 0; i < 2; i++) { |
| switch (i) { |
| case 0 : |
| it = basePropertyNames.iterator(); |
| break; |
| case 1 : |
| default : |
| it = getNestedModelNames().iterator(); |
| } |
| while (it.hasNext()) { |
| propName = (String) it.next(); |
| propStatus = provider.validate(propName); |
| if (propStatus != null) { |
| if (status == null || status.isOK()) |
| status = propStatus; |
| else { |
| if (status.isMultiStatus()) |
| ((MultiStatus) status).merge(propStatus); |
| else { |
| MultiStatus multi = new MultiStatus("org.eclipse.wst.common.frameworks.internal", 0, "", null); //$NON-NLS-1$ //$NON-NLS-2$ |
| multi.merge(status); |
| multi.merge(propStatus); |
| status = multi; |
| } |
| } |
| if (stopOnFirstFailure && status != null && !status.isOK() && status.getSeverity() == IStatus.ERROR) |
| return status; |
| } |
| } |
| } |
| |
| if (status == null) |
| return IDataModelProvider.OK_STATUS; |
| return status; |
| } |
| |
| public void addListener(IDataModelListener listener) { |
| if (listener != null) { |
| if (listeners == null) { |
| listeners = new ArrayList(); |
| listeners.add(listener); |
| } else if (!listeners.contains(listener)) |
| listeners.add(listener); |
| } |
| } |
| |
| public void removeListener(IDataModelListener listener) { |
| if (listeners != null && listener != null) |
| listeners.remove(listener); |
| } |
| |
| /** |
| * Return true if the model doesn't have any errors. |
| * |
| * @return boolean |
| */ |
| public boolean isValid() { |
| return validate(true).getSeverity() != IStatus.ERROR; |
| } |
| |
| public boolean isPropertyValid(String propertyName) { |
| return validateProperty(propertyName).getSeverity() != IStatus.ERROR; |
| } |
| |
| public IStatus validateProperty(String propertyName) { |
| DataModelImpl dataModel = getOwningDataModel(propertyName); |
| IStatus status = dataModel.provider.validate(propertyName); |
| return status == null ? IDataModelProvider.OK_STATUS : status; |
| } |
| |
| public List getExtendedContext() { |
| List extendedContext = provider.getExtendedContext(); |
| return extendedContext == null ? Collections.EMPTY_LIST : extendedContext; |
| } |
| |
| public void dispose() { |
| provider.dispose(); |
| } |
| |
| public IDataModelOperation getRawOperation() { |
| IDataModelOperation providerOp = provider.getDefaultOperation(); |
| if (null == providerOp) { |
| providerOp = new AbstractDataModelOperation(this) { |
| public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { |
| return OK_STATUS; |
| } |
| }; |
| } |
| return providerOp; |
| } |
| |
| public IDataModelOperation getDefaultOperation() { |
| return new DataModelPausibleOperationImpl(getRawOperation()); |
| } |
| |
| public String toString() { |
| return "IDataModel, provider=" + provider.toString(); //$NON-NLS-1$ |
| } |
| |
| public String getID() { |
| String id = provider.getID(); |
| return null != id ? id : ""; //$NON-NLS-1$ |
| } |
| } |