/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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 Public License for more details. * * * Copyright 2006 - 2013 Pentaho Corporation. All rights reserved. */ package org.pentaho.platform.engine.services.runtime; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.repository.IRuntimeElement; import org.pentaho.platform.api.repository.RepositoryException; import org.pentaho.platform.engine.core.system.PentahoBase; import org.pentaho.platform.engine.services.messages.Messages; import org.pentaho.platform.util.xml.XmlHelper; import java.math.BigDecimal; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; public class SimpleRuntimeElement extends PentahoBase implements IRuntimeElement { private static final long serialVersionUID = 5024690844237335928L; private static final Log logger = LogFactory.getLog( SimpleRuntimeElement.class ); private String instanceId; private String parentId; private String solutionId; private String parentType; private int revision; private Map typesMap = new HashMap(); // The total list of properties and // their types private Map paramMapSS = new HashMap(); // ShortString Map ( VARCHAR(254) ) private Map paramMapLS = new HashMap(); // LongString Map ( CLOB ) private Map paramMapBD = new HashMap(); // BigDecimal Map private Map paramMapDT = new HashMap(); // Date Map private Map paramMapLong = new HashMap(); // Long Map private Map paramMapCPLX = new HashMap(); // Complex Map (Serialized as a // Blob) private static final int MAXSSLENGH = 254; private static final ThreadLocal allowableReadAttributeNames = new ThreadLocal(); private boolean loaded; private boolean readOnly; // TODO: Implement check on every set and get to make sure that the // attribute is allowed to be read/written /** * Constructor for Hibernate */ protected SimpleRuntimeElement() { } /** * Constructor * * @param instId * The Instance Id */ public SimpleRuntimeElement( final String instId ) { instanceId = instId; } /** * Constructor * * @param instId * The Instance Id * @param parId * The Parent Id * @param parType * The Parent Type */ public SimpleRuntimeElement( final String instId, final String parId, final String parType ) { instanceId = instId; parentId = parId; parentType = parType; } /** * Constructor * * @param instId * The Instance Id * @param parId * The Parent Id * @param parType * The Parent Type * @param solnId * The Solution Id */ public SimpleRuntimeElement( final String instId, final String parId, final String parType, final String solnId ) { instanceId = instId; parentId = parId; parentType = parType; solutionId = solnId; } public List getMessages() { return null; } protected void setPentahoSession( final IPentahoSession sess ) { genLogIdFromSession( sess ); } /** * @return Returns the parentId. */ public String getParentId() { return parentId; } /** * @param parentId * The parentId to set. */ public void setParentId( final String parentId ) { this.updateOk(); this.parentId = parentId; } /** * @return Returns the parentType. */ public String getParentType() { return parentType; } /** * @param parentType * The parentType to set. */ public void setParentType( final String parentType ) { this.updateOk(); this.parentType = parentType; } /** * @return Returns the instanceId. */ public String getInstanceId() { return instanceId; } /** * @param instId * The instanceId to set. */ public void setInstanceId( final String instId ) { this.updateOk(); this.instanceId = instId; } /** * @return Returns the solutionId. */ public String getSolutionId() { return solutionId; } /** * @param solutionId * The solutionId to set. */ public void setSolutionId( final String solutionId ) { this.updateOk(); this.solutionId = solutionId; } /** * Auto-handled revision mechanism. * * @return The current revision */ public int getRevision() { return revision; } /** * Sets the revision of the class * * @param rev * New revision to set. */ protected void setRevision( final int rev ) { revision = rev; } /** * Uses the instanceId to distinguish equality. The instanceId will never be null, won't change, and is the * primary key. Therefore, it's the perfect candidate for equals() and hashcode. */ @Override public boolean equals( final Object other ) { if ( this == other ) { return true; } if ( !( other instanceof IRuntimeElement ) ) { return false; } final IRuntimeElement otherRE = (IRuntimeElement) other; return this.getInstanceId().equals( otherRE.getInstanceId() ); } @Override public int hashCode() { return this.getInstanceId().hashCode(); } protected Map getParamMapSS() { return paramMapSS; } protected Map getParamMapLS() { return paramMapLS; } protected Map getParamMapDT() { return paramMapDT; } protected Map getParamMapBD() { return paramMapBD; } protected Map getParamMapLong() { return paramMapLong; } protected Map getParamMapCPLX() { return paramMapCPLX; } protected void setParamMapSS( final Map ss ) { paramMapSS = ss; } protected void setParamMapLS( final Map ls ) { paramMapLS = ls; } protected void setParamMapDT( final Map dt ) { paramMapDT = dt; } protected void setParamMapBD( final Map bd ) { paramMapBD = bd; } protected void setParamMapLong( final Map lng ) { paramMapLong = lng; } protected void setParamMapCPLX( final Map cplx ) { paramMapCPLX = cplx; } /** * Gets a property from the paramMap as a string with no default value. * * @param key * The key into the map. * @return The property. */ public String getStringProperty( final String key ) { return getStringProperty( key, null ); } /** * Gets a property from the paramMap as a string, using a default value if it doesn't exist in the map. * * @param key * The key into the map. * @param defaultValue * Default value returned if the key isn't already in the map. * @return The property. */ public String getStringProperty( final String key, final String defaultValue ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getString", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Object prop = getParamMapSS().get( key ); if ( prop == null ) { prop = getParamMapLS().get( key ); } return ( prop != null ) ? prop.toString() : defaultValue; } protected void checkType( final String key, final String type, final boolean setIt ) { Map localTypesMap = getTypesMap(); String curType = (String) localTypesMap.get( key ); if ( curType != null ) { if ( !curType.equals( type ) ) { throw new RepositoryException( Messages.getInstance().getErrorString( "RTREPO.ERROR_0001_INVALIDTYPE", curType, type ) ); //$NON-NLS-1$ } } if ( setIt ) { localTypesMap.put( key, type ); } } /** * Sets a property into the paramMap. Special implementation note - Null values aren't supported in the Map. So, * if a null value is passed in, this implementation will remove the entry from the map. * * @param key * The key into the map. * @param value * The value to set. */ public void setStringProperty( final String key, final String value ) { this.updateOk(); trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "setString", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Map theMapSS = getParamMapSS(); Map theMapLS = getParamMapLS(); if ( value != null ) { checkType( key, value.getClass().getName(), true ); if ( value.length() > SimpleRuntimeElement.MAXSSLENGH ) { theMapSS.remove( key ); // Make sure it's not in the short map // first. theMapLS.put( key, new StringBuffer( value ) ); } else { theMapLS.remove( key ); theMapSS.put( key, value ); } } else { theMapSS.remove( key ); theMapLS.remove( key ); } } /** * Gets a BigDecimal property from the paramMap. * * @param key * Key in the paramMap. * @return BigDecimal property */ public BigDecimal getBigDecimalProperty( final String key ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getBigDecimal", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ return getBigDecimalProperty( key, null ); } /** * Gets a property from the paramMap as a BigDecimal, using a default value if it doesn't exist in the map. * * @param key * Key in the paramMap. * @param defaultValue * Detault value if the property doesn't exist in the paramMap. * @return Returns the property from the paramMap. */ public BigDecimal getBigDecimalProperty( final String key, final BigDecimal defaultValue ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getBigDecimal", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Object prop = getParamMapBD().get( key ); return ( prop != null ) ? new BigDecimal( (String) prop ) : defaultValue; } /** * Sets the BigDecimal property in the paramMap. Special implementation note - Null values aren't supported in * the Map. So, if a null value is passed in, this implementation will remove the entry from the map. * * @param key * Key in the paramMap. * @param value * The property value to set. */ public void setBigDecimalProperty( final String key, final BigDecimal value ) { this.updateOk(); trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "setBigDecimal", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Map theMap = getParamMapBD(); if ( value != null ) { checkType( key, value.getClass().getName(), true ); theMap.put( key, value.toString() ); } else { theMap.remove( key ); } } /** * Gets a property from the paramMap as a Date, with no default value. * * @param key * Key in the paramMap * @return The property in the map. */ public Date getDateProperty( final String key ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getDate", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ return getDateProperty( key, null ); } /** * Gets a property from the paramMap as a Date using a default value if it doesn't exist in the map * * @param key * Key in the paramMap * @param defaultValue * The default value if the property doesn't exist in the paramMap. * @return The property in the map. */ public Date getDateProperty( final String key, final Date defaultValue ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getDate", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Object prop = getParamMapDT().get( key ); return ( prop != null ) ? (Date) prop : defaultValue; } /** * Sets a date property in the paramMap. If null comes in, it removes the value from the map. Special * implementation note - Null values aren't supported in the Map. So, if a null value is passed in, this * implementation will remove the entry from the map. * * @param key * Key in the paramMap * @param value * The property value to set. */ public void setDateProperty( final String key, final Date value ) { this.updateOk(); trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "setDate", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Map theMap = getParamMapDT(); if ( value != null ) { checkType( key, value.getClass().getName(), true ); theMap.put( key, value ); } else { theMap.remove( key ); } } /** * Gets a property from the paramMap as a Long using a default value if it doesn't exist in the map * * @param key * Key in the paramMap * @param defaultValue * The default value if the property doesn't exist in the paramMap. * @return The property in the map. */ public Long getLongProperty( final String key, final Long defaultValue ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getLong", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Object prop = getParamMapLong().get( key ); return ( prop != null ) ? (Long) prop : defaultValue; } /** * Gets a property from the paramMap as a long using a default value if it doesn't exist in the map * * @param key * Key in the paramMap * @param defaultValue * The default value if the property doesn't exist in the paramMap. * @return The property in the map. */ public long getLongProperty( final String key, final long defaultValue ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getLong", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Object prop = getParamMapLong().get( key ); return ( prop != null ) ? ( (Long) prop ).longValue() : defaultValue; } /** * Sets a long property in the paramMap. If null comes in, it removes the value from the map. Special * implementation note - Null values aren't supported in the Map. So, if a null value is passed in, this * implementation will remove the entry from the map. * * @param key * Key in the paramMap * @param value * The property value to set. */ public void setLongProperty( final String key, final Long value ) { this.updateOk(); trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "setLong", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Map theMap = getParamMapLong(); if ( value != null ) { checkType( key, value.getClass().getName(), true ); theMap.put( key, value ); } else { theMap.remove( key ); } } /** * Sets a long property in the paramMap. * * @param key * Key in the paramMap * @param value * The property value to set. */ public void setLongProperty( final String key, final long value ) { this.updateOk(); setLongProperty( key, new Long( value ) ); } /** * Gets a list property from the paramMap. * * @param key * Key in the map * @return The list property in the paramMap. */ public List getListProperty( final String key ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getList", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Object prop = getParamMapCPLX().get( key ); return (List) prop; } /** * Gets a map property from the paramMap. * * @param key * The key in the map * @return The map value in the paramMap. */ public Map getMapProperty( final String key ) { trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "getMap", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Object prop = getParamMapCPLX().get( key ); return (Map) prop; } /** * Sets a list property in the paramMap. Special implementation note - Null values aren't supported in the Map. * So, if a null value is passed in, this implementation will remove the entry from the map. * * @param key * The key in the map. * @param value * The list property to set. */ public void setListProperty( final String key, final List value ) { this.updateOk(); trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "setList", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Map theMap = getParamMapCPLX(); if ( value != null ) { checkType( key, value.getClass().getName(), true ); theMap.put( key, value ); } else { theMap.remove( key ); } } /** * Sets a map property in the paramMap. Special implementation note - Null values aren't supported in the Map. * So, if a null value is passed in, this implementation will remove the entry from the map. * * @param key * The key in the map. * @param value * The map property to set. */ public void setMapProperty( final String key, final Map value ) { this.updateOk(); trace( Messages.getInstance().getString( "RTREPO.DEBUG_PROPERTY_GETSET", "setMap", key ) ); //$NON-NLS-1$ //$NON-NLS-2$ Map theMap = getParamMapCPLX(); if ( value != null ) { checkType( key, value.getClass().getName(), true ); theMap.put( key, value ); } else { theMap.remove( key ); } } /** * Returns an XML representation of the RuntimeElement. Mainly for Debug/Test Cases to make sure that what goes * in is what comes out during tests. * * @return Returns an XML representation of the RuntimeElement */ public String toXML() { StringBuffer rtn = new StringBuffer(); rtn.append( "<runtime-element>\r" ); //$NON-NLS-1$ rtn.append( getXMLString( getInstanceId(), "instance-id", " " ) ); //$NON-NLS-1$ //$NON-NLS-2$ rtn.append( getXMLString( Integer.toString( getRevision() ), "revision", " " ) ); //$NON-NLS-1$ //$NON-NLS-2$ rtn.append( getXMLString( getParentId(), "parent-id", " " ) ); //$NON-NLS-1$ //$NON-NLS-2$ rtn.append( getXMLString( getParentType(), "parent-type", " " ) ); //$NON-NLS-1$ //$NON-NLS-2$ rtn.append( getXMLString( getSolutionId(), "solution-id", " " ) ); //$NON-NLS-1$ //$NON-NLS-2$ rtn.append( getMapXML( this.getParamMapSS(), "small-string-map" ) ); //$NON-NLS-1$ rtn.append( getMapXML( this.getParamMapLS(), "large-string-map" ) ); //$NON-NLS-1$ rtn.append( getMapXML( this.getParamMapDT(), "date-map" ) ); //$NON-NLS-1$ rtn.append( getMapXML( this.getParamMapBD(), "big-decimal-map" ) ); //$NON-NLS-1$ rtn.append( getMapXML( this.getParamMapLong(), "long-map" ) ); //$NON-NLS-1$ rtn.append( getMapXML( this.getParamMapCPLX(), "complex-map" ) ); //$NON-NLS-1$ rtn.append( "</runtime-element>\r" ); //$NON-NLS-1$ return rtn.toString(); } private String getXMLString( final String str, final String tag, final String indent ) { return indent + "<" + tag + "><![CDATA[" + str + "]]></" + tag + ">\r"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } private String getMapXML( final Map theMap, final String tag ) { StringBuffer sb = new StringBuffer(); sb.append( " <" ).append( tag ).append( ">\r" ); //$NON-NLS-1$ //$NON-NLS-2$ sb.append( XmlHelper.mapToXML( theMap, " " ) ); //$NON-NLS-1$ sb.append( " </" ).append( tag ).append( ">\r" ); //$NON-NLS-1$ //$NON-NLS-2$ return sb.toString(); } /* ILogger Needs */ @Override public Log getLogger() { return SimpleRuntimeElement.logger; } public void setAllowableAttributeNames( final Collection allowedReadNames ) { SimpleRuntimeElement.allowableReadAttributeNames.set( allowedReadNames ); } /** * @return Returns the typesMap. */ protected Map getTypesMap() { return typesMap; } /** * @param typesMap * The typesMap to set. */ protected void setTypesMap( final Map typesMap ) { this.typesMap = typesMap; } public Set getParameterNames() { return getTypesMap().keySet(); } public String getParameterType( final String parameterName ) { return (String) getTypesMap().get( parameterName ); } public void setLoaded( final boolean value ) { this.loaded = value; } public boolean getLoaded() { return this.loaded; } private void updateOk() { if ( !loaded ) { return; } if ( readOnly ) { throw new IllegalStateException( Messages.getInstance().getErrorString( "RTELEMENT.ERROR_0001_INVALIDUPDATE" ) ); //$NON-NLS-1$ } } public boolean getReadOnly() { return readOnly; } public void setReadOnly( final boolean value ) { this.readOnly = value; } public void forceSave() { } }