| /******************************************************************************* |
| * Copyright (c) 2005, 2007 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 |
| * yyyymmdd bug Email and other contact information |
| * -------- -------- ----------------------------------------------------------- |
| * 20060523 133714 joan@ca.ibm.com - Joan Haggarty |
| * 20060726 151614 pmoogk@ca.ibm.com - Peter Moogk |
| * 20070314 176886 pmoogk@ca.ibm.com - Peter Moogk |
| *******************************************************************************/ |
| package org.eclipse.wst.command.internal.env.ant; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.Vector; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.wst.command.internal.env.EnvironmentMessages; |
| import org.eclipse.wst.command.internal.env.core.CommandManager; |
| import org.eclipse.wst.command.internal.env.core.context.TransientResourceContext; |
| import org.eclipse.wst.command.internal.env.core.data.BeanModifier; |
| import org.eclipse.wst.command.internal.env.core.data.ClassEntry; |
| import org.eclipse.wst.command.internal.env.core.data.Transformer; |
| import org.eclipse.wst.command.internal.env.core.fragment.CommandFragment; |
| import org.eclipse.wst.command.internal.env.eclipse.EclipseEnvironment; |
| import org.eclipse.wst.command.internal.env.eclipse.IEclipseStatusHandler; |
| import org.eclipse.wst.command.internal.env.plugin.EnvPlugin; |
| import org.eclipse.wst.common.environment.ILog; |
| import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelOperation; |
| |
| /** |
| * |
| * Access to status handler, log, resource context and command manager. |
| * Initializes data for commands from Ant property files based on antDataMapping extensions. |
| * |
| * @author joan |
| * |
| */ |
| |
| public class AntEnvironment extends EclipseEnvironment{ |
| |
| private Hashtable antProperties_; |
| private Hashtable operationDataRecord_ = new Hashtable(); |
| private boolean mappingComplete_; |
| private ClassEntry classEntry; |
| |
| // extensionPoint names and namespace |
| private static String MAPPER_EXT_PT = "antDataMapping"; //$NON-NLS-1$ |
| private static String SCENARIO_EXT_PT = "antScenario"; //$NON-NLS-1$ |
| private static String EXT_PT_NAMESPACE = "org.eclipse.wst.command.env"; ////$NON-NLS-1$ |
| |
| // antDataMapping extension point attributes |
| private static final String MAPPER_OPERATION_ATTRIBUTE= "operation"; //$NON-NLS-1$ |
| private static final String MAPPER_KEY_ATTRIBUTE= "key"; //$NON-NLS-1$ |
| private static final String MAPPER_PROPERTY_ATTRIBUTE= "property"; //$NON-NLS-1$ |
| private static final String MAPPER_TRANSFORM_ATTRIBUTE= "transform"; //$NON-NLS-1$ |
| private static final String MAPPER_REQUIRED_ATTRIBUTE= "required"; //$NON-NLS-1$ |
| |
| // antScenario extension point attributes |
| private static final String SCENARIO_TYPE_ATTRIBUTE = "scenarioType"; //$NON-NLS-1$ |
| private static final String SCENARIO_CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ |
| |
| // Ant property IDs |
| private static final String VERBOSE_PROPERTY = "Verbose"; //$NON-NLS-1$ |
| private static final String OVERWRITE_PROPERTY = "OverwriteFilesEnabled"; //$NON-NLS-1$ |
| private static final String CREATEFOLDER_PROPERTY = "CreateFoldersEnabled"; //$NON-NLS-1$ |
| private static final String CHECKOUT_PROPERTY = "CheckoutFilesEnabled"; //$NON-NLS-1$ |
| private static final String SCENARIO_TYPE_PROPERTY = "ScenarioType"; //$NON-NLS-1$ |
| |
| private AntController controller_; |
| |
| public AntEnvironment(AntController controller, TransientResourceContext context, IEclipseStatusHandler handler, Hashtable properties) |
| { |
| super(controller.getOperationManager(), context, handler); |
| antProperties_ = properties; |
| controller_ = controller; |
| setContext( context ); |
| } |
| |
| private void setContext(TransientResourceContext context) |
| { |
| Boolean overwriteSet = getBooleanProperty( OVERWRITE_PROPERTY ); |
| Boolean createfolderSet = getBooleanProperty( CREATEFOLDER_PROPERTY ); |
| Boolean checkoutSet = getBooleanProperty( CHECKOUT_PROPERTY ); |
| |
| if( overwriteSet != null ) context.setOverwriteFilesEnabled( overwriteSet.booleanValue() ); |
| if( createfolderSet != null ) context.setCreateFoldersEnabled( createfolderSet.booleanValue() ); |
| if( checkoutSet != null ) context.setCheckoutFilesEnabled( checkoutSet.booleanValue() ); |
| } |
| |
| public boolean verbose() |
| { |
| Boolean result = getBooleanProperty( VERBOSE_PROPERTY ); |
| |
| return result == null ? false : result.booleanValue(); |
| } |
| |
| public Boolean getBooleanProperty( String property ) |
| { |
| String value = getProperty( property ); |
| Boolean result = null; |
| |
| if( value != null ) |
| { |
| value = value.toLowerCase(); |
| result = new Boolean( value.equals( "true") ); |
| } |
| |
| return result; |
| } |
| |
| // returns String since the property table built by Ant is property value pairs where the value is a String |
| private String getProperty(String key) |
| { |
| Object property = antProperties_.get(key); |
| if (property != null && (!property.toString().equals(""))) |
| return property.toString().trim(); |
| return null; |
| } |
| |
| // call from engine prior to executing the operation |
| public IStatus initOperationData(AbstractDataModelOperation op) |
| { |
| //check to see if data has already been primed for this operation |
| String qualifiedClassName = op.getClass().getName(); |
| if (operationDataRecord_.get(qualifiedClassName) == null) |
| { |
| classEntry = new ClassEntry(); |
| |
| try { |
| //extension lookup for the bean - may be more than one property for it |
| Enumeration operationData = getMappingExtensions(op); |
| classEntry.setterList_= getSetterList(op); |
| while (operationData.hasMoreElements()) |
| { |
| PropertyDataHolder mapping = (PropertyDataHolder)operationData.nextElement(); |
| |
| mappingComplete_ = false; |
| String property = mapping.property_; |
| String setterMethodName = createSetterName(property); |
| |
| int step = 1; |
| while (!mappingComplete_) |
| { |
| switch (step) { |
| case 1: |
| mappingComplete_ = transformAndSet(mapping, setterMethodName); |
| break; |
| case 2: |
| mappingComplete_ = callSetter(mapping.operation_, mapping.value_, setterMethodName); |
| break; |
| |
| case 3: |
| mappingComplete_ = callPrimitiveSetter(mapping); |
| break; |
| |
| case 4: |
| mappingComplete_ = callSetterConstructor(mapping); |
| break; |
| |
| default: |
| mappingComplete_ = true; |
| break; |
| } |
| step++; |
| } |
| } |
| //add operation to the record - no need to initialize again... |
| operationDataRecord_.put(qualifiedClassName, ""); |
| } |
| catch (Exception e) |
| { |
| throw new IllegalArgumentException(e.getMessage()); |
| } |
| |
| } |
| return Status.OK_STATUS; |
| } |
| |
| /** |
| * Creates setter name based on the property passed in. If the |
| * property has any leading qualifiers they are stripped off. |
| * The property is capitalized and set is prepended. |
| * @param property The name of the property that requires a setter. |
| * @return |
| */ |
| private String createSetterName(String property) |
| { |
| while (property.indexOf(".")>=0) |
| { |
| property=property.substring(property.indexOf(".")+1); |
| } |
| String firstChar = property.substring(0,1); |
| firstChar = firstChar.toUpperCase(); |
| property = firstChar + property.substring(1); |
| String setterName = "set" + property; |
| return setterName; |
| } |
| |
| /** |
| * Retrieves extensions for the org.eclipse.wst.command.env antDataMapping |
| * extension point. Extracts those that with class attribute values that match operationName. |
| * All mappings are converted to PropertyDataHolder objects. |
| * Any m:1 Ant key to property mappings are collected into a key-value map within |
| * a single PropertyDataHolder. |
| * @param operationName The name of the operation that is being initialized. |
| * @return A collection of PropertyDataHolder objects. Returns null if there are no extensions matching the operationName. |
| */ |
| private Enumeration getMappingExtensions(AbstractDataModelOperation operation) throws CoreException |
| { |
| String operationName = operation.getClass().getName(); |
| //go to ext registry and get all antMapping extensions |
| IExtensionRegistry reg = Platform.getExtensionRegistry(); |
| IExtensionPoint extPt = reg.getExtensionPoint(EXT_PT_NAMESPACE, MAPPER_EXT_PT); |
| Hashtable dataTable = new Hashtable(25); |
| |
| IConfigurationElement[] elements = extPt.getConfigurationElements(); |
| |
| for (int i = 0; i < elements.length; i++) { |
| |
| IConfigurationElement ce = elements[i]; |
| Object obj = ce.getAttribute(MAPPER_OPERATION_ATTRIBUTE); |
| // look for mappings for this operation |
| if (obj.equals(operationName)) |
| { |
| String key = ce.getAttribute(MAPPER_KEY_ATTRIBUTE); |
| String value = getProperty(key); |
| |
| //check to see if the property for this extension is already in the data table |
| // if so, there is a m:1 mapping |
| if (value != null) //only do a mapping if there is an Ant property value passed in... |
| { |
| |
| String property = ce.getAttribute(MAPPER_PROPERTY_ATTRIBUTE); |
| Object transform = null; |
| try |
| { |
| //check to make sure there is an transform attribute provided |
| // if so, get the class to do the transformation |
| if (ce.getAttribute(MAPPER_TRANSFORM_ATTRIBUTE)!= null) |
| transform = ce.createExecutableExtension(MAPPER_TRANSFORM_ATTRIBUTE); |
| } |
| catch (CoreException cex) { |
| Status errorStatus = new Status(Status.ERROR, "ws_ant", 5092, cex.getMessage(), cex); |
| getStatusHandler().reportError(errorStatus); |
| getLog().log(ILog.ERROR, "ws_ant", 5092, this, "getMappingExtensions", EnvironmentMessages.bind(EnvironmentMessages.MSG_ERROR_ANT_DATA_TRANSFORM, key, transform)); |
| throw new CoreException(errorStatus); |
| } |
| |
| if (transform != null && transform instanceof BeanModifier/*dataTable.containsKey(property)*/) |
| { |
| //get the PropertyDataHolder from the table |
| PropertyDataHolder holder = (PropertyDataHolder)dataTable.get(property); |
| if (holder == null) |
| { |
| holder = new PropertyDataHolder(); |
| holder.key_ = ""; |
| holder.value_ = ""; |
| holder.transform_ = transform; |
| holder.operation_ = operation; |
| holder.property_ = property; |
| holder.map_ = new HashMap(); |
| holder.map_.put(key, value); |
| dataTable.put(property, holder); |
| } |
| else |
| { |
| holder.map_.put(key, value); |
| } |
| } |
| else //plain property mapping not a bean |
| { |
| PropertyDataHolder holder = new PropertyDataHolder(); |
| holder.operation_ = operation; |
| holder.key_ = key; |
| holder.property_ = property; |
| holder.transform_ = transform; |
| holder.value_ = value; |
| dataTable.put(property, holder); |
| } |
| } |
| else if(ce.getAttribute(MAPPER_REQUIRED_ATTRIBUTE)!=null && ce.getAttribute(MAPPER_REQUIRED_ATTRIBUTE).equals("true")) |
| { |
| String msg = EnvironmentMessages.bind(EnvironmentMessages.MSG_ERROR_ANT_REQUIRED_PROPERTY, key.toString()); |
| Status statusObj = new Status(IStatus.ERROR, |
| EnvPlugin.ID, |
| IStatus.ERROR, |
| msg, |
| null); |
| getStatusHandler().reportError(statusObj); |
| getLog().log(ILog.ERROR, "ws_ant", 9999, this, "getMappingExtensions", msg); |
| } |
| else if (verbose()) |
| { |
| String msg = EnvironmentMessages.bind(EnvironmentMessages.MSG_INFO_ANT__PROPERTY_DEFAULT, key.toString()); |
| Status statusObj = new Status(IStatus.INFO, |
| EnvPlugin.ID, |
| IStatus.INFO, |
| msg, |
| null); |
| getStatusHandler().reportInfo(statusObj); |
| getLog().log(ILog.INFO, "ws_ant", 9999, this, "getMappingExtensions", msg); |
| } |
| } |
| } |
| return dataTable.elements(); |
| } |
| |
| private boolean transformAndSet(PropertyDataHolder mapping, String setterMethodName) |
| { |
| Object transform = mapping.transform_; |
| if (transform != null) |
| { |
| // get transform class & create setter parameters |
| try |
| { |
| //Object classObject = Class.forName(transform).newInstance(); |
| Object param = new Object(); |
| if (transform instanceof Transformer) |
| { |
| Transformer transformer = (Transformer)transform; |
| // transform the property value |
| param = transformer.transform(mapping.value_); |
| } |
| else if (mapping.map_ != null && transform instanceof BeanModifier) |
| { |
| BeanModifier modifier = (BeanModifier)transform; |
| Method getter = getGetterMethod(mapping); |
| param = getter.invoke(mapping.operation_, new Object[]{}); |
| modifier.modify(param, mapping.map_); |
| } |
| return callSetter(mapping.operation_, param, setterMethodName); |
| |
| } |
| catch (Exception exc) |
| { |
| getStatusHandler().reportError(new Status(Status.ERROR, "ws_ant", 5093, exc.getMessage(), exc)); |
| getLog().log(ILog.ERROR, "ws_ant", 5093, this, "transformAndSet", EnvironmentMessages.bind(EnvironmentMessages.MSG_ERROR_ANT_DATA_TRANSFORM, mapping.key_, mapping.transform_)); |
| throw new IllegalArgumentException(exc.getMessage()); |
| } |
| } |
| return false; |
| } |
| |
| private Vector getSetterList(Object op) |
| { |
| Vector result = new Vector(); |
| Method[] methods = op.getClass().getMethods(); |
| for( int index = 0; index < methods.length; index++ ) |
| { |
| Method method = methods[index]; |
| boolean isPublic = Modifier.isPublic( method.getModifiers() ); |
| Class returnType = method.getReturnType(); |
| |
| if( isPublic && |
| returnType == Void.TYPE && |
| method.getParameterTypes().length == 1 && |
| method.getName().startsWith( "set" )) |
| { |
| method.setAccessible( true ); |
| result.add( method ); |
| } |
| } |
| |
| return result; |
| } |
| |
| private Method getGetterMethod(PropertyDataHolder mapping) |
| { |
| Method getterFound = null; |
| |
| if (classEntry.getterList_ == null) |
| { |
| classEntry.getterList_ = getGetterList(mapping.operation_); |
| } |
| |
| for( int index = 0; index < classEntry.getterList_.size(); index++ ) |
| { |
| Method getter = (Method)classEntry.getterList_.elementAt( index ); |
| |
| if( getter.getName().equals( "get" + mapping.property_ )) |
| { |
| getterFound = getter; |
| break; |
| } |
| } |
| return getterFound; |
| } |
| |
| private Vector getGetterList( Object object ) |
| { |
| Vector result = new Vector(); |
| Method[] methods = object.getClass().getMethods(); |
| |
| for( int index = 0; index < methods.length; index++ ) |
| { |
| Method method = methods[index]; |
| boolean isPublic = Modifier.isPublic( method.getModifiers() ); |
| Class returnType = method.getReturnType(); |
| |
| if( isPublic && |
| returnType != Void.TYPE && |
| method.getParameterTypes().length == 0 && |
| method.getName().startsWith( "get" )) |
| { |
| method.setAccessible( true ); |
| result.add( method ); |
| } |
| } |
| |
| return result; |
| } |
| |
| private boolean callSetter(AbstractDataModelOperation op, Object param, String setterMethodName) throws CoreException |
| { |
| for (Iterator iterator = classEntry.setterList_.iterator(); iterator.hasNext();) |
| { |
| Method method = (Method) iterator.next(); |
| if (method.getName().equals(setterMethodName)) |
| { |
| Class[] paramTypes = method.getParameterTypes(); |
| if (paramTypes.length == 1 && param != null) |
| { |
| try{ |
| method.invoke(op, new Object[]{param}); |
| return true; |
| } |
| catch(Exception cex){ |
| Status errorStatus = new Status(Status.ERROR, "ws_ant", 5094, cex.getMessage(), cex); |
| getStatusHandler().reportError(errorStatus); |
| getLog().log(ILog.ERROR, "ws_ant", 5094, this, "callSetter", EnvironmentMessages.bind(EnvironmentMessages.MSG_ERROR_ANT_CALL_SETTER, setterMethodName)); |
| throw new CoreException(errorStatus); |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| |
| // look for setter with primitive type parameter - if find one, convert String propertyValue and call it |
| private boolean callPrimitiveSetter(PropertyDataHolder mapping) throws CoreException |
| { |
| for (Iterator iterator = classEntry.setterList_.iterator(); iterator.hasNext();) { |
| Method element = (Method) iterator.next(); |
| Class[] parmTypes = element.getParameterTypes(); |
| if (parmTypes.length==1 && parmTypes[0].isPrimitive()) |
| { |
| Class parmType = parmTypes[0].getClass(); |
| Object setterParm = null; |
| if (parmType.equals(Integer.class)) |
| { |
| setterParm = Integer.valueOf(mapping.value_); |
| } |
| else if (parmType.equals(Boolean.class)) |
| { |
| setterParm = Boolean.valueOf(mapping.value_); |
| } |
| else if (parmType.equals(Character.class) && mapping.value_.length() == 1) |
| { |
| setterParm = new Character(mapping.value_.charAt(0)); |
| } |
| else if (parmType.equals(Byte.class)) |
| { |
| setterParm = Byte.valueOf(mapping.value_); |
| } |
| else if (parmType.equals(Short.class)) |
| { |
| setterParm = Short.valueOf(mapping.value_); |
| } |
| else if (parmType.equals(Long.class)) |
| { |
| setterParm = Long.valueOf(mapping.value_); |
| } |
| else if (parmType.equals(Float.class)) |
| { |
| setterParm = Float.valueOf(mapping.value_); |
| } |
| else if (parmType.equals(Double.class)) |
| { |
| setterParm = Double.valueOf(mapping.value_); |
| } |
| |
| if (setterParm != null) |
| { |
| try |
| { |
| element.invoke(mapping.operation_, new Object[]{setterParm}); |
| return true; |
| } |
| catch(Exception e){ |
| Status errorStatus = new Status(Status.ERROR, "ws_ant", 5095, e.getMessage(), e); |
| getStatusHandler().reportError(errorStatus); |
| getLog().log(ILog.ERROR, "ws_ant", 5095, this, "callPrimitiveSetter", EnvironmentMessages.bind(EnvironmentMessages.MSG_ERROR_ANT_CALL_SETTER, element.getName())); |
| throw new CoreException(errorStatus); |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| //check for setter with parameter type that takes a String to construct |
| // construct the parameter using String & call the setter |
| private boolean callSetterConstructor(PropertyDataHolder mapping) throws CoreException |
| { |
| for (Iterator iterator = classEntry.setterList_.iterator(); iterator.hasNext();) { |
| Method element = (Method) iterator.next(); |
| Class[] parmTypes = element.getParameterTypes(); |
| Class[] stringParm = new Class[]{String.class}; |
| if (parmTypes.length==1) |
| { |
| try |
| { |
| Constructor ctor = parmTypes.getClass().getConstructor(stringParm); |
| Object parameter = ctor.newInstance(new Object[]{mapping.value_}); |
| element.invoke(mapping.operation_, new Object[]{parameter}); |
| } |
| catch (Exception exc) |
| { |
| Status errorStatus = new Status(Status.ERROR, "ws_ant", 5096, exc.getMessage(), exc); |
| getStatusHandler().reportError(errorStatus); |
| getLog().log(ILog.ERROR, "ws_ant", 5096, this, "callSetterConstructor", EnvironmentMessages.bind(EnvironmentMessages.MSG_ERROR_ANT_CALL_SETTER, element.getName())); |
| throw new CoreException(errorStatus); |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns an object that helps manage execution/undoing of Commands. |
| */ |
| public CommandManager getCommandManager (){ |
| return controller_.getOperationManager(); |
| } |
| |
| public CommandFragment getRootCommandFragment() |
| { |
| |
| //look up the commandFragment in the scenarioRegistry extension point with an ID corresponding to the scenario property in the propertytable |
| String scenarioProperty = (String)getProperty(SCENARIO_TYPE_PROPERTY); |
| IExtensionRegistry reg = Platform.getExtensionRegistry(); |
| IExtensionPoint extPt = reg.getExtensionPoint(EXT_PT_NAMESPACE, SCENARIO_EXT_PT); |
| |
| IConfigurationElement[] elements = extPt.getConfigurationElements(); |
| |
| for (int i = 0; i < elements.length; i++) { |
| |
| IConfigurationElement configElement = elements[i]; |
| if (configElement.getAttribute(SCENARIO_TYPE_ATTRIBUTE).equals(scenarioProperty)) |
| { |
| try |
| { |
| Object obj = configElement.createExecutableExtension(SCENARIO_CLASS_ATTRIBUTE); |
| |
| if (obj instanceof org.eclipse.wst.command.internal.env.core.fragment.CommandFragment) |
| { |
| return (org.eclipse.wst.command.internal.env.core.fragment.CommandFragment)obj; |
| } |
| } |
| catch (Exception exception) |
| { |
| Status errorStatus = new Status(Status.ERROR, "ws_ant", 5097, exception.getMessage(), exception); |
| getStatusHandler().reportError(errorStatus); |
| getLog().log(ILog.ERROR, "ws_ant", 5097, this, "getRootCommandFragment", EnvironmentMessages.MSG_ERROR_ANT_CMD_FRAGMENT); |
| } |
| } |
| } |
| return null; |
| } |
| } |