001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * @created Jun 15, 2005
014: * @author Marc Batchelor
015: *
016: */
017:
018: package org.pentaho.repository.runtime;
019:
020: import java.math.BigDecimal;
021: import java.util.Collection;
022: import java.util.Date;
023: import java.util.HashMap;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.pentaho.core.repository.IRuntimeElement;
030: import org.pentaho.core.session.IPentahoSession;
031: import org.pentaho.core.system.PentahoBase;
032: import org.pentaho.core.util.XmlHelper;
033: import org.pentaho.messages.Messages;
034: import org.pentaho.repository.HibernateUtil;
035: import org.pentaho.core.repository.RepositoryException;
036:
037: public class RuntimeElement extends PentahoBase implements
038: IRuntimeElement {
039: public static final int ClassVersionNumber = 3;
040:
041: private static final long serialVersionUID = 5024690844237335928L;
042:
043: private static Log logger = LogFactory.getLog(RuntimeElement.class);
044:
045: private String instanceId;
046:
047: private String parentId;
048:
049: private String solutionId;
050:
051: private String parentType;
052:
053: private int revision;
054:
055: private Map typesMap = new HashMap(); // The total list of properties and
056:
057: // their types
058:
059: private Map paramMapSS = new HashMap(); // ShortString Map ( VARCHAR(254) )
060:
061: private Map paramMapLS = new HashMap(); // LongString Map ( CLOB )
062:
063: private Map paramMapBD = new HashMap(); // BigDecimal Map
064:
065: private Map paramMapDT = new HashMap(); // Date Map
066:
067: private Map paramMapLong = new HashMap(); // Long Map
068:
069: private Map paramMapCPLX = new HashMap(); // Complex Map (Serialized as a
070:
071: private Date createdDate = new Date(); // Created Date
072:
073: // Blob
074:
075: private static final int MAXSSLENGH = 254;
076:
077: private static final ThreadLocal allowableReadAttributeNames = new ThreadLocal();
078:
079: private boolean loaded;
080:
081: private boolean readOnly;
082:
083: // TODO: Implement check on every set and get to make sure that the
084: // attribute is allowed to be read/written
085:
086: /**
087: * Constructor for Hibernate
088: */
089: protected RuntimeElement() {
090:
091: }
092:
093: /**
094: * Constructor
095: *
096: * @param instId
097: * The Instance Id
098: */
099: public RuntimeElement(String instId) {
100: instanceId = instId;
101: }
102:
103: /**
104: * Constructor
105: *
106: * @param instId
107: * The Instance Id
108: * @param parId
109: * The Parent Id
110: * @param parType
111: * The Parent Type
112: */
113: public RuntimeElement(String instId, String parId, String parType) {
114: instanceId = instId;
115: parentId = parId;
116: parentType = parType;
117: }
118:
119: /**
120: * Constructor
121: *
122: * @param instId
123: * The Instance Id
124: * @param parId
125: * The Parent Id
126: * @param parType
127: * The Parent Type
128: * @param solnId
129: * The Solution Id
130: */
131: public RuntimeElement(String instId, String parId, String parType,
132: String solnId) {
133: instanceId = instId;
134: parentId = parId;
135: parentType = parType;
136: solutionId = solnId;
137: }
138:
139: public List getMessages() {
140: return null;
141: }
142:
143: protected void setPentahoSession(IPentahoSession sess) {
144: genLogIdFromSession(sess);
145: }
146:
147: /**
148: * @return Returns the parentId.
149: */
150: public String getParentId() {
151: return parentId;
152: }
153:
154: /**
155: * @param parentId
156: * The parentId to set.
157: */
158: public void setParentId(String parentId) {
159: this .updateOk();
160: this .parentId = parentId;
161: }
162:
163: /**
164: * @return Returns the parentType.
165: */
166: public String getParentType() {
167: return parentType;
168: }
169:
170: /**
171: * @param parentType
172: * The parentType to set.
173: */
174: public void setParentType(String parentType) {
175: this .updateOk();
176: this .parentType = parentType;
177: }
178:
179: /**
180: * @return Returns the instanceId.
181: */
182: public String getInstanceId() {
183: return instanceId;
184: }
185:
186: /**
187: * @param instId
188: * The instanceId to set.
189: */
190: public void setInstanceId(String instId) {
191: this .updateOk();
192: this .instanceId = instId;
193: }
194:
195: /**
196: * @return Returns the solutionId.
197: */
198: public String getSolutionId() {
199: return solutionId;
200: }
201:
202: /**
203: * @param solutionId
204: * The solutionId to set.
205: */
206: public void setSolutionId(String solutionId) {
207: this .updateOk();
208: this .solutionId = solutionId;
209: }
210:
211: /**
212: * Auto-handled revision mechanism.
213: *
214: * @return The current revision
215: */
216: public int getRevision() {
217: return revision;
218: }
219:
220: /**
221: * Sets the revision of the class
222: *
223: * @param rev
224: * New revision to set.
225: */
226: protected void setRevision(int rev) {
227: revision = rev;
228: }
229:
230: /**
231: * Uses the instanceId to distinguish equality. The instanceId will never be
232: * null, won't change, and is the primary key. Therefore, it's the perfect
233: * candidate for equals() and hashcode.
234: */
235: public boolean equals(Object other) {
236: if (this == other) {
237: return true;
238: }
239: if (!(other instanceof RuntimeElement)) {
240: return false;
241: }
242: final RuntimeElement otherRE = (RuntimeElement) other;
243: return this .getInstanceId().equals(otherRE.getInstanceId());
244: }
245:
246: public int hashCode() {
247: return this .getInstanceId().hashCode();
248: }
249:
250: protected Map getParamMapSS() {
251: return paramMapSS;
252: }
253:
254: protected Map getParamMapLS() {
255: return paramMapLS;
256: }
257:
258: protected Map getParamMapDT() {
259: return paramMapDT;
260: }
261:
262: protected Map getParamMapBD() {
263: return paramMapBD;
264: }
265:
266: protected Map getParamMapLong() {
267: return paramMapLong;
268: }
269:
270: protected Map getParamMapCPLX() {
271: return paramMapCPLX;
272: }
273:
274: protected void setParamMapSS(Map ss) {
275: paramMapSS = ss;
276: }
277:
278: protected void setParamMapLS(Map ls) {
279: paramMapLS = ls;
280: }
281:
282: protected void setParamMapDT(Map dt) {
283: paramMapDT = dt;
284: }
285:
286: protected void setParamMapBD(Map bd) {
287: paramMapBD = bd;
288: }
289:
290: protected void setParamMapLong(Map lng) {
291: paramMapLong = lng;
292: }
293:
294: protected void setParamMapCPLX(Map cplx) {
295: paramMapCPLX = cplx;
296: }
297:
298: public Date getCreateDate() {
299: return createdDate;
300: }
301:
302: public void setCreateDate(Date value) {
303: createdDate = value;
304: }
305:
306: /**
307: * Gets a property from the paramMap as a string with no default value.
308: *
309: * @param key
310: * The key into the map.
311: * @return The property.
312: */
313: public String getStringProperty(String key) {
314: return getStringProperty(key, null);
315: }
316:
317: /**
318: * Gets a property from the paramMap as a string, using a default value if
319: * it doesn't exist in the map.
320: *
321: * @param key
322: * The key into the map.
323: * @param defaultValue
324: * Default value returned if the key isn't already in the map.
325: * @return The property.
326: */
327: public String getStringProperty(String key, String defaultValue) {
328: trace(Messages.getString(
329: "RTREPO.DEBUG_PROPERTY_GETSET", "getString", key)); //$NON-NLS-1$ //$NON-NLS-2$
330: Object prop = getParamMapSS().get(key);
331: if (prop == null) {
332: prop = getParamMapLS().get(key);
333: }
334: return (prop != null) ? prop.toString() : defaultValue;
335: }
336:
337: protected void checkType(String key, String type, boolean setIt) {
338: Map localTypesMap = getTypesMap();
339: String curType = (String) localTypesMap.get(key);
340: if (curType != null) {
341: if (!curType.equals(type)) {
342: throw new RepositoryException(Messages.getErrorString(
343: "RTREPO.ERROR_0001_INVALIDTYPE", curType, type)); //$NON-NLS-1$
344: }
345: }
346: if (setIt) {
347: localTypesMap.put(key, type);
348: }
349: }
350:
351: /**
352: * Sets a property into the paramMap. Special implementation note - Null
353: * values aren't supported in the Map. So, if a null value is passed in,
354: * this implementation will remove the entry from the map.
355: *
356: * @param key
357: * The key into the map.
358: * @param value
359: * The value to set.
360: */
361: public void setStringProperty(String key, String value) {
362: this .updateOk();
363: trace(Messages.getString(
364: "RTREPO.DEBUG_PROPERTY_GETSET", "setString", key)); //$NON-NLS-1$ //$NON-NLS-2$
365: checkType(key, value.getClass().getName(), true);
366: Map theMapSS = getParamMapSS();
367: Map theMapLS = getParamMapLS();
368: if (value != null) {
369: if (value.length() > MAXSSLENGH) {
370: theMapSS.remove(key); // Make sure it's not in the short map
371: // first.
372: theMapLS.put(key, new StringBuffer(value));
373: } else {
374: theMapLS.remove(key);
375: theMapSS.put(key, value);
376: }
377: } else {
378: theMapSS.remove(key);
379: theMapLS.remove(key);
380: }
381: }
382:
383: /**
384: * Gets a BigDecimal property from the paramMap.
385: *
386: * @param key
387: * Key in the paramMap.
388: * @return BigDecimal property
389: */
390: public BigDecimal getBigDecimalProperty(String key) {
391: trace(Messages.getString(
392: "RTREPO.DEBUG_PROPERTY_GETSET", "getBigDecimal", key)); //$NON-NLS-1$ //$NON-NLS-2$
393: return getBigDecimalProperty(key, null);
394: }
395:
396: /**
397: * Gets a property from the paramMap as a BigDecimal, using a default value
398: * if it doesn't exist in the map.
399: *
400: * @param key
401: * Key in the paramMap.
402: * @param defaultValue
403: * Detault value if the property doesn't exist in the paramMap.
404: * @return Returns the property from the paramMap.
405: */
406: public BigDecimal getBigDecimalProperty(String key,
407: BigDecimal defaultValue) {
408: trace(Messages.getString(
409: "RTREPO.DEBUG_PROPERTY_GETSET", "getBigDecimal", key)); //$NON-NLS-1$ //$NON-NLS-2$
410: Object prop = getParamMapBD().get(key);
411: return (prop != null) ? new BigDecimal((String) prop)
412: : defaultValue;
413: }
414:
415: /**
416: * Sets the BigDecimal property in the paramMap. Special implementation note -
417: * Null values aren't supported in the Map. So, if a null value is passed
418: * in, this implementation will remove the entry from the map.
419: *
420: * @param key
421: * Key in the paramMap.
422: * @param value
423: * The property value to set.
424: */
425: public void setBigDecimalProperty(String key, BigDecimal value) {
426: this .updateOk();
427: trace(Messages.getString(
428: "RTREPO.DEBUG_PROPERTY_GETSET", "setBigDecimal", key)); //$NON-NLS-1$ //$NON-NLS-2$
429: checkType(key, value.getClass().getName(), true);
430: Map theMap = getParamMapBD();
431: if (value != null) {
432: theMap.put(key, value.toString());
433: } else {
434: theMap.remove(key);
435: }
436: }
437:
438: /**
439: * Gets a property from the paramMap as a Date, with no default value.
440: *
441: * @param key
442: * Key in the paramMap
443: * @return The property in the map.
444: */
445: public Date getDateProperty(String key) {
446: trace(Messages.getString(
447: "RTREPO.DEBUG_PROPERTY_GETSET", "getDate", key)); //$NON-NLS-1$ //$NON-NLS-2$
448: return getDateProperty(key, null);
449: }
450:
451: /**
452: * Gets a property from the paramMap as a Date using a default value if it
453: * doesn't exist in the map
454: *
455: * @param key
456: * Key in the paramMap
457: * @param defaultValue
458: * The default value if the property doesn't exist in the
459: * paramMap.
460: * @return The property in the map.
461: */
462: public Date getDateProperty(String key, Date defaultValue) {
463: trace(Messages.getString(
464: "RTREPO.DEBUG_PROPERTY_GETSET", "getDate", key)); //$NON-NLS-1$ //$NON-NLS-2$
465: Object prop = getParamMapDT().get(key);
466: return (prop != null) ? (Date) prop : defaultValue;
467: }
468:
469: /**
470: * Sets a date property in the paramMap. If null comes in, it removes the
471: * value from the map. Special implementation note - Null values aren't
472: * supported in the Map. So, if a null value is passed in, this
473: * implementation will remove the entry from the map.
474: *
475: * @param key
476: * Key in the paramMap
477: * @param value
478: * The property value to set.
479: */
480: public void setDateProperty(String key, Date value) {
481: this .updateOk();
482: trace(Messages.getString(
483: "RTREPO.DEBUG_PROPERTY_GETSET", "setDate", key)); //$NON-NLS-1$ //$NON-NLS-2$
484: checkType(key, value.getClass().getName(), true);
485: Map theMap = getParamMapDT();
486: if (value != null) {
487: theMap.put(key, value);
488: } else {
489: theMap.remove(key);
490: }
491: }
492:
493: /**
494: * Gets a property from the paramMap as a Long using a default value if it
495: * doesn't exist in the map
496: *
497: * @param key
498: * Key in the paramMap
499: * @param defaultValue
500: * The default value if the property doesn't exist in the
501: * paramMap.
502: * @return The property in the map.
503: */
504: public Long getLongProperty(String key, Long defaultValue) {
505: trace(Messages.getString(
506: "RTREPO.DEBUG_PROPERTY_GETSET", "getLong", key)); //$NON-NLS-1$ //$NON-NLS-2$
507: Object prop = getParamMapLong().get(key);
508: return (prop != null) ? (Long) prop : defaultValue;
509: }
510:
511: /**
512: * Gets a property from the paramMap as a long using a default value if it
513: * doesn't exist in the map
514: *
515: * @param key
516: * Key in the paramMap
517: * @param defaultValue
518: * The default value if the property doesn't exist in the
519: * paramMap.
520: * @return The property in the map.
521: */
522: public long getLongProperty(String key, long defaultValue) {
523: trace(Messages.getString(
524: "RTREPO.DEBUG_PROPERTY_GETSET", "getLong", key)); //$NON-NLS-1$ //$NON-NLS-2$
525: Object prop = getParamMapLong().get(key);
526: return (prop != null) ? ((Long) prop).longValue()
527: : defaultValue;
528: }
529:
530: /**
531: * Sets a long property in the paramMap. If null comes in, it removes the
532: * value from the map. Special implementation note - Null values aren't
533: * supported in the Map. So, if a null value is passed in, this
534: * implementation will remove the entry from the map.
535: *
536: * @param key
537: * Key in the paramMap
538: * @param value
539: * The property value to set.
540: */
541: public void setLongProperty(String key, Long value) {
542: this .updateOk();
543: trace(Messages.getString(
544: "RTREPO.DEBUG_PROPERTY_GETSET", "setLong", key)); //$NON-NLS-1$ //$NON-NLS-2$
545: checkType(key, value.getClass().getName(), true);
546: Map theMap = getParamMapLong();
547: if (value != null) {
548: theMap.put(key, value);
549: } else {
550: theMap.remove(key);
551: }
552: }
553:
554: /**
555: * Sets a long property in the paramMap.
556: *
557: * @param key
558: * Key in the paramMap
559: * @param value
560: * The property value to set.
561: */
562: public void setLongProperty(String key, long value) {
563: this .updateOk();
564: setLongProperty(key, new Long(value));
565: }
566:
567: /**
568: * Gets a list property from the paramMap.
569: *
570: * @param key
571: * Key in the map
572: * @return The list property in the paramMap.
573: */
574: public List getListProperty(String key) {
575: trace(Messages.getString(
576: "RTREPO.DEBUG_PROPERTY_GETSET", "getList", key)); //$NON-NLS-1$ //$NON-NLS-2$
577: Object prop = getParamMapCPLX().get(key);
578: return (List) prop;
579: }
580:
581: /**
582: * Gets a map property from the paramMap.
583: *
584: * @param key
585: * The key in the map
586: * @return The map value in the paramMap.
587: */
588: public Map getMapProperty(String key) {
589: trace(Messages.getString(
590: "RTREPO.DEBUG_PROPERTY_GETSET", "getMap", key)); //$NON-NLS-1$ //$NON-NLS-2$
591: Object prop = getParamMapCPLX().get(key);
592: return (Map) prop;
593: }
594:
595: /**
596: * Sets a list property in the paramMap. Special implementation note - Null
597: * values aren't supported in the Map. So, if a null value is passed in,
598: * this implementation will remove the entry from the map.
599: *
600: * @param key
601: * The key in the map.
602: * @param value
603: * The list property to set.
604: */
605: public void setListProperty(String key, List value) {
606: this .updateOk();
607: trace(Messages.getString(
608: "RTREPO.DEBUG_PROPERTY_GETSET", "setList", key)); //$NON-NLS-1$ //$NON-NLS-2$
609: checkType(key, value.getClass().getName(), true);
610: Map theMap = getParamMapCPLX();
611: if (value != null) {
612: theMap.put(key, value);
613: } else {
614: theMap.remove(key);
615: }
616: }
617:
618: /**
619: * Sets a map property in the paramMap. Special implementation note - Null
620: * values aren't supported in the Map. So, if a null value is passed in,
621: * this implementation will remove the entry from the map.
622: *
623: * @param key
624: * The key in the map.
625: * @param value
626: * The map property to set.
627: */
628: public void setMapProperty(String key, Map value) {
629: this .updateOk();
630: trace(Messages.getString(
631: "RTREPO.DEBUG_PROPERTY_GETSET", "setMap", key)); //$NON-NLS-1$ //$NON-NLS-2$
632: checkType(key, value.getClass().getName(), true);
633: Map theMap = getParamMapCPLX();
634: if (value != null) {
635: theMap.put(key, value);
636: } else {
637: theMap.remove(key);
638: }
639: }
640:
641: /**
642: * Returns an XML representation of the RuntimeElement. Mainly for
643: * Debug/Test Cases to make sure that what goes in is what comes out during
644: * tests.
645: *
646: * @return Returns an XML representation of the RuntimeElement
647: */
648: public String toXML() {
649: StringBuffer rtn = new StringBuffer();
650: rtn.append("<runtime-element>\r"); //$NON-NLS-1$
651: rtn.append(getXMLString(getInstanceId(), "instance-id", " ")); //$NON-NLS-1$ //$NON-NLS-2$
652: rtn.append(getXMLString(Integer.toString(getRevision()),
653: "revision", " ")); //$NON-NLS-1$ //$NON-NLS-2$
654: rtn.append(getXMLString(getParentId(), "parent-id", " ")); //$NON-NLS-1$ //$NON-NLS-2$
655: rtn.append(getXMLString(getParentType(), "parent-type", " ")); //$NON-NLS-1$ //$NON-NLS-2$
656: rtn.append(getXMLString(getSolutionId(), "solution-id", " ")); //$NON-NLS-1$ //$NON-NLS-2$
657: rtn.append(getMapXML(this .getParamMapSS(), "small-string-map")); //$NON-NLS-1$
658: rtn.append(getMapXML(this .getParamMapLS(), "large-string-map")); //$NON-NLS-1$
659: rtn.append(getMapXML(this .getParamMapDT(), "date-map")); //$NON-NLS-1$
660: rtn.append(getMapXML(this .getParamMapBD(), "big-decimal-map")); //$NON-NLS-1$
661: rtn.append(getMapXML(this .getParamMapLong(), "long-map")); //$NON-NLS-1$
662: rtn.append(getMapXML(this .getParamMapCPLX(), "complex-map")); //$NON-NLS-1$
663: rtn.append("</runtime-element>\r"); //$NON-NLS-1$
664: return rtn.toString();
665: }
666:
667: private String getXMLString(String str, String tag, String indent) {
668: return indent
669: + "<" + tag + "><![CDATA[" + str + "]]></" + tag + ">\r"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
670: }
671:
672: private String getMapXML(Map theMap, String tag) {
673: StringBuffer sb = new StringBuffer();
674: sb.append(" <").append(tag).append(">\r"); //$NON-NLS-1$ //$NON-NLS-2$
675: sb.append(XmlHelper.mapToXML(theMap, " ")); //$NON-NLS-1$
676: sb.append(" </").append(tag).append(">\r"); //$NON-NLS-1$ //$NON-NLS-2$
677: return sb.toString();
678: }
679:
680: /* ILogger Needs */
681: public Log getLogger() {
682: return logger;
683: }
684:
685: public void setAllowableAttributeNames(Collection allowedReadNames) {
686: allowableReadAttributeNames.set(allowedReadNames);
687: }
688:
689: /**
690: * @return Returns the typesMap.
691: */
692: protected Map getTypesMap() {
693: return typesMap;
694: }
695:
696: /**
697: * @param typesMap
698: * The typesMap to set.
699: */
700: protected void setTypesMap(Map typesMap) {
701: this .typesMap = typesMap;
702: }
703:
704: public Set getParameterNames() {
705: return getTypesMap().keySet();
706: }
707:
708: public String getParameterType(String parameterName) {
709: return (String) getTypesMap().get(parameterName);
710: }
711:
712: public void setLoaded(boolean value) {
713: this .loaded = value;
714: }
715:
716: public boolean getLoaded() {
717: return this .loaded;
718: }
719:
720: private void updateOk() {
721: if (!loaded) {
722: return;
723: }
724: if (readOnly) {
725: throw new IllegalStateException(
726: Messages
727: .getErrorString("RTELEMENT.ERROR_0001_INVALIDUPDATE")); //$NON-NLS-1$
728: }
729: }
730:
731: public boolean getReadOnly() {
732: return readOnly;
733: }
734:
735: public void setReadOnly(boolean value) {
736: this .readOnly = value;
737: }
738:
739: public void forceSave() {
740: try {
741: HibernateUtil.commitTransaction();
742: HibernateUtil.flushSession();
743: } finally {
744: HibernateUtil.beginTransaction();
745: }
746: }
747: }
|