001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.rm.metadata;
020:
021: import java.text.*;
022: import java.util.*;
023: import java.util.logging.*;
024:
025: import org.openharmonise.commons.dsi.*;
026: import org.openharmonise.commons.dsi.dml.*;
027: import org.openharmonise.rm.*;
028: import org.openharmonise.rm.publishing.*;
029: import org.openharmonise.rm.resources.AbstractProfiledObject;
030: import org.openharmonise.rm.resources.metadata.properties.Property;
031: import org.openharmonise.rm.resources.metadata.properties.ranges.*;
032: import org.w3c.dom.*;
033:
034: /**
035: * PropertyInstance class for profile data held in string format in the
036: * database.
037: *
038: * @author Michael Bell
039: * @version $Revision: 1.5 $
040: *
041: */
042: public class GeneralPropertyInstance extends AbstractPropertyInstance
043: implements Publishable {
044:
045: /**
046: * <code>String</code> constant for the extension used to name the database
047: * table corresponding to this property instance type. The naming convention
048: * for this property instance type is as follows:
049: *
050: * Profile.getTableName() + EXT_DATA
051: */
052: private static final String EXT_DATA = "_data";
053:
054: /**
055: * The name of the database column containing the property instance values
056: */
057: protected static final String CLMN_VALUE = "value";
058:
059: /**
060: * Date format for converting <code>String</code> values to <code>Date</code>
061: * values if the <code>String</code> does not parse to a <code>long</code>
062: * and the value should include the time
063: */
064: private static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss G";
065:
066: /**
067: * Date format for converting <code>String</code> values to <code>Date</code>
068: * values if the <code>String</code> does not parse to a <code>long</code>
069: * and the value does not include the time
070: */
071: private static final String DATE_FORMAT = "yyyy-MM-dd G";
072:
073: /**
074: * Data XML element name
075: */
076: public static final String TAG_DATA = "Data";
077:
078: /**
079: * Date format attribute used to specify the date format to be used
080: * when publishing dates
081: */
082: public static final String ATTRIB_DATEFORMAT = "dateFormat";
083:
084: /**
085: * Logger for this class
086: */
087: private static final Logger m_logger = Logger
088: .getLogger(GeneralPropertyInstance.class.getName());
089:
090: /**
091: * Constructs a property instance
092: */
093: public GeneralPropertyInstance() {
094: super ();
095:
096: }
097:
098: /**
099: * Constructs a property instance with an interface to the data store.
100: *
101: * @param dbint the data store interface
102: */
103: public GeneralPropertyInstance(AbstractDataStoreInterface dbint) {
104: super (dbint);
105:
106: }
107:
108: /**
109: * Constructs a property instance with an interface to
110: * the data store and a reference to the <code>Profile</code> which
111: * will contain this property instance.
112: *
113: * @param dbintrf the data store interface
114: * @param profile the owner <code>Profile</code>
115: */
116: public GeneralPropertyInstance(AbstractDataStoreInterface dbintrf,
117: Profile profile) {
118: super (dbintrf, profile);
119:
120: }
121:
122: /**
123: * Constructs an <code>GeneralPropertyInstance</code> which has an interface to
124: * the database, has a reference to it's owner <code>Profile</code> and the
125: * <code>Property</code> associated to this instance.
126: *
127: * @param dbintrf the data store inteface
128: * @param nPropertyId the id of the <code>Property</code> that this object is an instance of
129: * @param profile the owner <code>Profile</code>
130: */
131: public GeneralPropertyInstance(AbstractDataStoreInterface dbintrf,
132: int nPropertyId, Profile profile) {
133: super (dbintrf, nPropertyId, profile);
134:
135: }
136:
137: /**
138: * Constructs a property instance of the specified <code>Property</code>
139: * with an interface to the data store.
140: *
141: * @param dbintrf the data store interface
142: * @param prop the <code>Property</code> that this object is an instance of
143: */
144: public GeneralPropertyInstance(AbstractDataStoreInterface dbintrf,
145: Property prop) {
146: super (dbintrf, prop);
147: }
148:
149: /**
150: * Constructs an <code>GeneralPropertyInstance</code> which has an interface to
151: * the data store, has a reference to its owner <code>Profile</code> and the
152: * <code>Property</code> associated to this instance.
153: *
154: * @param dbintrf the data store interface
155: * @param property the <code>Property</code>
156: * @param profile the owner <code>Profile</code>
157: */
158: public GeneralPropertyInstance(AbstractDataStoreInterface dbintrf,
159: Property property, Profile profile) {
160: super (dbintrf, property, profile);
161:
162: }
163:
164: /* (non-Javadoc)
165: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
166: */
167: public void populate(Element xmlElement, State state)
168: throws PopulateException {
169:
170: String sTagName = xmlElement.getTagName();
171: Text txt = null;
172: NodeList nodes = null;
173: boolean bTagFound = false;
174:
175: if (sTagName.equals(TAG_PROP_INSTANCE_VALUES) == true) {
176: nodes = xmlElement.getChildNodes();
177:
178: for (int i = 0; i < nodes.getLength(); i++) {
179: if (nodes.item(i).getNodeType() == Node.TEXT_NODE) {
180: continue;
181: }
182: Element elNext = (Element) nodes.item(i);
183: if (elNext.getTagName().equals(TAG_DATA)
184: && bTagFound == false) {
185: this .clearValues();
186: bTagFound = true;
187: }
188: populate(elNext, state);
189: }
190: } else if (sTagName.equals(TAG_ATTACH) == true) {
191: nodes = xmlElement.getChildNodes();
192:
193: for (int i = 0; i < nodes.getLength(); i++) {
194: if (nodes.item(i).getNodeType() == Node.TEXT_NODE) {
195: continue;
196: }
197: Element elNext = (Element) nodes.item(i);
198:
199: populate(elNext, state);
200: }
201: } else if (sTagName.equals(TAG_DETACH) == true) {
202: nodes = xmlElement.getChildNodes();
203:
204: for (int i = 0; i < nodes.getLength(); i++) {
205: if (nodes.item(i).getNodeType() == Node.TEXT_NODE) {
206: continue;
207: }
208: Element elNext = (Element) nodes.item(i);
209:
210: if (elNext.getTagName().equals(TAG_DATA)) {
211: txt = (Text) elNext.getFirstChild();
212: this .removeValue(txt.getNodeValue());
213: }
214: }
215: } else if (sTagName.equals(TAG_DATA) == true) {
216: txt = (Text) xmlElement.getFirstChild();
217: try {
218:
219: addValue(txt.getNodeValue());
220: } catch (InvalidPropertyValueException e) {
221: throw new PopulateException(
222: "Invalid value for PropertyInstance", e);
223: }
224: } else {
225: super .populate(xmlElement, state);
226: }
227: }
228:
229: /* (non-Javadoc)
230: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
231: */
232: public Element publish(Element formEl, HarmoniseOutput xmlDoc,
233: State state) throws PublishException {
234:
235: Element resultEl = null;
236: String sTagname = formEl.getTagName();
237:
238: if (sTagname.equals(TAG_PROP_INSTANCE_VALUES)) {
239: resultEl = xmlDoc.createElement(TAG_PROP_INSTANCE_VALUES);
240:
241: String sDateFormat = null;
242: try {
243: Range range = this .getProperty().getRange();
244: if (range instanceof DateRange) {
245:
246: sDateFormat = formEl
247: .getAttribute(ATTRIB_DATEFORMAT);
248:
249: if (sDateFormat == null
250: || sDateFormat.length() == 0) {
251: // use the DateRange formatting strings for display purposes
252: if (((DateRange) range).includeTime()) {
253: sDateFormat = DateRange.DATETIME_FORMAT;
254: } else {
255: sDateFormat = DateRange.DATE_FORMAT;
256: }
257: }
258:
259: }
260: } catch (DataAccessException e) {
261: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
262: }
263:
264: if (m_values != null) {
265: Element valueEl = null;
266: Text txt = null;
267: for (int j = 0; j < m_values.size(); j++) {
268: valueEl = xmlDoc.createElement(TAG_DATA);
269:
270: if (m_values.size() > 0) {
271:
272: String sValue = null;
273: if (sDateFormat != null) {
274: SimpleDateFormat format = new SimpleDateFormat(
275: sDateFormat);
276: Date date = (Date) m_values.get(j);
277: sValue = format.format(date);
278: } else {
279: sValue = (String) m_values.get(j);
280: }
281: txt = xmlDoc.createTextNode(sValue);
282: valueEl.appendChild(txt);
283: }
284:
285: resultEl.appendChild(valueEl);
286: }
287: }
288: } else {
289: resultEl = super .publish(formEl, xmlDoc, state);
290: }
291:
292: if (resultEl == null) {
293: resultEl = xmlDoc.createElement(TAG_ERROR);
294: resultEl.appendChild(xmlDoc
295: .createTextNode("Problem publishing " + sTagname));
296: }
297:
298: return resultEl;
299: }
300:
301: /**
302: * Returns a list of processed values for this property instance. This method
303: * is applicable for those values which are formulas which can be calculated
304: * at runtime.
305: *
306: * @return the list of values which have been processed
307: * @throws DataAccessException if an error occurs accessing the property
308: * associated to this instance
309: */
310: public List getCalculatedValues() throws DataAccessException {
311: List values = null;
312:
313: if (getProperty().getRange().getObject().equals(
314: Date.class.getName()) == false) {
315: values = m_values;
316: } else {
317: values = new Vector(m_values.size());
318:
319: for (int i = 0; i < m_values.size(); i++) {
320: Object valObj = m_values.get(i);
321:
322: if (valObj instanceof String) {
323: try {
324: values.add(parseDate((String) valObj));
325: } catch (ParseException e) {
326: //can't parse just copy the data over
327: m_logger.log(Level.WARNING, e
328: .getLocalizedMessage(), e);
329: values.add(m_values.get(i));
330: }
331: } else if (valObj instanceof Date) {
332: values.add(String
333: .valueOf(((Date) valObj).getTime()));
334: }
335: }
336: }
337:
338: return values;
339: }
340:
341: /* (non-Javadoc)
342: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#match(org.openharmonise.rm.metadata.AbstractPropertyInstance)
343: */
344: public boolean match(AbstractPropertyInstance propInst)
345: throws ProfileException {
346: boolean bMatch = true;
347:
348: List otherValues = propInst.getValues();
349: if (m_values.size() == 0 || otherValues.size() == 0) {
350: bMatch = false;
351: } else if (m_property_ptr.equals(propInst.m_property_ptr) == false) {
352: bMatch = false;
353: } else if (m_sOperator.equals(">") || m_sOperator.equals("<")
354: || m_sOperator.equals(">=") || m_sOperator.equals("<=")) {
355: try {
356: if (getProperty().getRange().getObject().equals(
357: Number.class.getName()) == true) {
358: int nTemp1 = Integer.parseInt((String) otherValues
359: .get(0));
360: int nTemp2 = Integer.parseInt((String) m_values
361: .get(0));
362:
363: if ((m_sOperator.equals(">") && (nTemp1 > nTemp2) == false)
364: || (m_sOperator.equals("<") && (nTemp1 < nTemp2) == false)
365: || (m_sOperator.equals(">=") && (nTemp1 >= nTemp2) == false)
366: || (m_sOperator.equals("<=") && (nTemp1 <= nTemp2) == false)) {
367: bMatch = false;
368: }
369: }
370: } catch (DataAccessException e) {
371: throw new ProfileException(
372: "Error occured accessing property range", e);
373: }
374: } else if (m_sOperator.equals("=")
375: && (false == ((String) otherValues.get(0))
376: .equalsIgnoreCase((String) m_values.get(0)))) {
377: bMatch = false;
378: } else if (m_sOperator.equals("!=")
379: && ((String) otherValues.get(0))
380: .equalsIgnoreCase((String) m_values.get(0))) {
381: bMatch = false;
382: } else if (m_sOperator.equals("CONTAINS")) {
383: String sTemp1 = (String) m_values.get(0);
384: String sTemp2 = (String) otherValues.get(0);
385:
386: if (sTemp1.indexOf(sTemp1) < 0) {
387: bMatch = false;
388: }
389: } else if (m_sOperator.equals("BETWEEN")) {
390: try {
391: if (getProperty().getRange().getObject().equals(
392: Number.class.getName()) == true) {
393: int nTemp1 = Integer.parseInt((String) otherValues
394: .get(0));
395: int nTemp2 = Integer.parseInt((String) m_values
396: .get(0));
397: int nTemp3 = Integer.parseInt((String) m_values
398: .get(1));
399:
400: if ((nTemp2 < nTemp3)) {
401: if ((nTemp2 < nTemp1 && nTemp1 < nTemp3) == false) {
402: bMatch = false;
403: }
404: } else {
405: if ((nTemp3 < nTemp1 && nTemp1 < nTemp2) == false) {
406: bMatch = false;
407: }
408: }
409: }
410: } catch (DataAccessException e) {
411: throw new ProfileException(
412: "Error occured accessing property range", e);
413: }
414: } else if (m_sOperator.equals("STARTS_WITH")) {
415: String sTemp1 = (String) m_values.get(0);
416: String sTemp2 = (String) otherValues.get(0);
417:
418: if (sTemp1.startsWith(sTemp2) == false) {
419: bMatch = false;
420: }
421: } else if (m_sOperator.equals("IN")
422: || m_sOperator.equals("NOT IN")) {
423: boolean bCheck = false;
424:
425: for (int j = 0; j < otherValues.size(); j++) {
426: for (int k = 0; k < m_values.size(); k++) {
427: if (((String) m_values.get(k)).trim().equals(
428: ((String) otherValues.get(j)).trim())) {
429: bCheck = true;
430: }
431: }
432: }
433:
434: if ((m_sOperator.equals("NOT IN") && bCheck)
435: || (m_sOperator.equals("IN") && bCheck == false)) {
436: bMatch = false;
437: }
438: }
439:
440: return bMatch;
441: }
442:
443: /* (non-Javadoc)
444: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
445: */
446: public ColumnRef getInstanceColumnRef(String sColumn,
447: boolean bIsHist) throws DataStoreException {
448: ColumnRef returnColRef = null;
449: String sDBTable = getDBTableName();
450:
451: if (sColumn.equals(TAG_VALUE) == true
452: || sColumn.equals(CLMN_VALUE) == true) {
453: returnColRef = new ColumnRef(sDBTable, CLMN_VALUE,
454: ColumnRef.TEXT);
455: }
456:
457: if (returnColRef != null) {
458: return returnColRef;
459: } else {
460: return super .getInstanceColumnRef(sColumn, bIsHist);
461: }
462: }
463:
464: /* (non-Javadoc)
465: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceJoinConditions(java.lang.String, boolean)
466: */
467: public JoinConditions getInstanceJoinConditions(String sObjectTag,
468: boolean bIsOuter) throws DataStoreException {
469: throw new UnsupportedOperationException("Not implemented");
470: }
471:
472: /* (non-Javadoc)
473: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
474: */
475: public List processResultSet(CachedResultSet resultSet,
476: SelectStatement select) {
477: throw new UnsupportedOperationException("Not implemented");
478: }
479:
480: /* (non-Javadoc)
481: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement, int)
482: */
483: public List processResultSet(CachedResultSet resultSet,
484: SelectStatement select, int limit) {
485: throw new UnsupportedOperationException("Not implemented");
486: }
487:
488: /**
489: * Adds a <code>Date</code> value to this instance.
490: *
491: * @param date the date
492: * @throws InvalidPropertyValueException if the given value is invalid
493: */
494: public void addValue(java.util.Date date) throws PopulateException {
495: if (date != null) {
496: super .addValue(date);
497: }
498: }
499:
500: /**
501: * Adds a <code>String</code> value to this instance.
502: *
503: * @param sValue the value to add
504: * @throws InvalidPropertyValueException if the given value is invalid
505: */
506: public void addValue(String sValue) throws PopulateException {
507: if (sValue != null && sValue.trim().equals("") == false) {
508: try {
509: Range range = this .getProperty().getRange();
510:
511: Object objVal = sValue;
512:
513: if (range instanceof DateRange) {
514: objVal = getDateValue(sValue);
515: }
516:
517: if (range instanceof BooleanRange && m_values != null
518: && m_values.size() > 0) {
519: throw new InvalidPropertyValueException(
520: "Boolean property can only have one value");
521: }
522:
523: super .addValue(objVal);
524:
525: } catch (DataAccessException e) {
526: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
527: } catch (InvalidPropertyValueException e) {
528: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
529: }
530: }
531: }
532:
533: /**
534: * Returns a <code>Date</code> object representation of the given <code>String</code>.
535: *
536: * @param sVal the <code>String</code> value
537: * @return the <code>Date</code> obtained by parsing the <code>String</code>
538: * @throws DataAccessException if an error occurs parsing the <code>String</code>
539: * or accessing the associated <code>Property</code>
540: */
541: public Date getDateValue(String sVal) throws DataAccessException {
542: Date dtVal = null;
543:
544: Range range = this .getProperty().getRange();
545:
546: if (range instanceof DateRange) {
547:
548: try {
549: long lDate = Long.parseLong(sVal);
550: dtVal = new Date(lDate);
551: } catch (NumberFormatException e) {
552: //assume the date was represented in the other format
553: SimpleDateFormat format = null;
554: DateRange dtRange = (DateRange) range;
555: if (dtRange.includeTime() == true) {
556: format = new SimpleDateFormat(DATETIME_FORMAT);
557: } else {
558: format = new SimpleDateFormat(DATE_FORMAT);
559: }
560:
561: try {
562: dtVal = format.parse(sVal);
563: } catch (ParseException pe) {
564: throw new DataAccessException(
565: "Problem parsing date as a string", pe);
566: }
567: }
568:
569: } else {
570: throw new DataAccessException(
571: "Invalid request: this is not a date property instance - "
572: + range.getClass().getName());
573: }
574:
575: return dtVal;
576: }
577:
578: /**
579: * Removes the specified value from this instance
580: *
581: * @param sValue the value to remove
582: */
583: public void removeValue(String sValue) {
584: if (m_values != null) {
585: super .removeValue(sValue);
586: }
587: }
588:
589: /**
590: * Returns a <code>boolean</code> value for an instance of a property with a
591: * boolean range.
592: *
593: * @return a boolean value for this property instance
594: * @throws DataAccessException if an error occurs accessing the property
595: * associated to this instance
596: */
597: public boolean getBooleanValue() throws DataAccessException {
598: boolean bool = false;
599:
600: if (m_values.size() > 0
601: && getProperty().getRange() instanceof BooleanRange) {
602: bool = Boolean.valueOf((String) m_values.get(0))
603: .booleanValue();
604: }
605:
606: return bool;
607: }
608:
609: /*-------------------------------------------------------------------------------------
610: Protected Methods
611: --------------------------------------------------------------------------------------*/
612:
613: /**
614: * Parses a date formula, creating a string representation of the absolute date.
615: *
616: * @param sDateFormula the date formula to be parsed
617: * @return the resultant date
618: * @throws ParseException if an error occurs parsing the date formula
619: *
620: */
621: protected String parseDate(String sDateFormula)
622: throws ParseException {
623: String sDate = null;
624: String sOperator = null;
625: String sPeriod = null;
626: GregorianCalendar calendar = null;
627: java.text.SimpleDateFormat formatter = null;
628:
629: // the formulas must follow the following BNF:
630: // datecalculation = datedescriptor [ " + " | " - " period]
631: // datedescriptor = datetime | "today" | "now"
632: // datetime = [number "-" number "-" number] [" " number ":" number ":" number]
633: // period = ["P" ["Y" number] ["M" number] ["D" number]] ["T" ["H" number] ["M" number] ["S" number]]
634: // first need to separate the datedescriptor, operator and period
635: if ((sDateFormula.indexOf(" +") >= 0)
636: || (sDateFormula.indexOf(" -") >= 0)) {
637: StringTokenizer tokenizer = new StringTokenizer(
638: sDateFormula, " ");
639:
640: String sNext = null;
641: StringBuffer sDateRecorder = new StringBuffer();
642: StringBuffer sPeriodRecorder = new StringBuffer();
643: boolean bRecordingDate = true;
644:
645: while (tokenizer.hasMoreElements()) {
646: sNext = tokenizer.nextToken();
647:
648: if (sNext.equals("+") || sNext.equals("-")) {
649: sOperator = sNext;
650: bRecordingDate = false;
651: } else if (bRecordingDate) {
652: sDateRecorder.append(sNext);
653: } else {
654: sPeriodRecorder.append(sNext);
655: }
656: }
657:
658: sDate = sDateRecorder.toString();
659: sPeriod = sPeriodRecorder.toString();
660: } else {
661: sDate = sDateFormula;
662: }
663:
664: // process the special date tokens and create a calendar representing them
665: if (sDate.equalsIgnoreCase("today")) {
666: // set it to today
667: calendar = new GregorianCalendar();
668: calendar.setTime(new java.util.Date());
669: formatter = new java.text.SimpleDateFormat(DATE_FORMAT);
670:
671: // ensure that equality will work with the reduced precision
672: if ((m_sOperator != null) && m_sOperator.equals("=")) {
673: m_sOperator = "STARTS_WITH";
674: }
675: } else if (sDate.equalsIgnoreCase("now")) {
676: // set it to now
677: calendar = new GregorianCalendar();
678: calendar.setTime(new java.util.Date());
679: formatter = new java.text.SimpleDateFormat(DATETIME_FORMAT);
680: }
681:
682: // we only have a calculation to do if we have both an operator and a period
683: if ((sOperator != null) && (sPeriod != null)) {
684: // this is the case where we have an absolute date in the formula
685: // this is done here so the degenerate case where we just have a datetime
686: // falls straight through
687: if (calendar == null) {
688: // create it
689: calendar = new GregorianCalendar();
690: calendar.setTime(formatter.parse(sDate));
691: formatter = new java.text.SimpleDateFormat(
692: DATETIME_FORMAT);
693: }
694:
695: char[] caPeriod = sPeriod.toCharArray();
696: StringBuffer sNumber = new StringBuffer();
697: boolean bDate = true;
698: // true if we are doing date fields, false if we are in time
699: char cNext = 0;
700:
701: for (int i = 0; i < caPeriod.length; i++) {
702: cNext = caPeriod[i];
703:
704: // 'P' and 'T' just affect the interpretation of 'M'
705: if (cNext == 'P') { // date
706: bDate = true;
707: } else if (cNext == 'T') { // time
708: bDate = false;
709: } else if (cNext == 'Y') { // year
710: changeDate(calendar, Calendar.YEAR, sOperator,
711: Integer.parseInt(sNumber.toString()));
712: sNumber = new StringBuffer();
713: } else if (cNext == 'M') { // month or minute
714:
715: if (bDate) {
716: changeDate(calendar, Calendar.MONTH, sOperator,
717: Integer.parseInt(sNumber.toString()));
718: } else {
719: changeDate(calendar, Calendar.MINUTE,
720: sOperator, Integer.parseInt(sNumber
721: .toString()));
722: }
723:
724: sNumber = new StringBuffer();
725: } else if (cNext == 'D') { // day of the month
726: changeDate(calendar, Calendar.DATE, sOperator,
727: Integer.parseInt(sNumber.toString()));
728: sNumber = new StringBuffer();
729: } else if (cNext == 'H') { // hour
730: changeDate(calendar, Calendar.HOUR_OF_DAY,
731: sOperator, Integer.parseInt(sNumber
732: .toString()));
733: sNumber = new StringBuffer();
734: } else if (cNext == 'S') { // second
735: changeDate(calendar, Calendar.SECOND, sOperator,
736: Integer.parseInt(sNumber.toString()));
737: sNumber = new StringBuffer();
738: } else if (Character.isDigit(cNext)) {
739: sNumber.append(cNext);
740: }
741:
742: // should probably throw an exception if we find something else
743: }
744: }
745:
746: // convert calendar to a string, if we used it
747: if (calendar != null) {
748: sDate = formatter.format(calendar.getTime());
749: }
750:
751: return sDate;
752: }
753:
754: /**
755: * Returns the name of database table for a property instance associated to
756: * the given <code>Profile</code>.
757: *
758: * @param prof the <code>Profile</code> which will be the associated to the property #
759: * instance
760: * @return the database table name for the property instance
761: */
762: static protected String getDBTableName(Profile prof) {
763: StringBuffer sTable = new StringBuffer();
764:
765: if (prof.isHistorical() == true) {
766: AbstractProfiledObject profObj = prof.getProfiledObject();
767: sTable.append(profObj.getDBTableName()).append(
768: Profile.EXT_PROFILE).append(EXT_DATA).append(
769: EXT_HIST);
770: } else {
771: sTable.append(prof.getDBTableName()).append(EXT_DATA);
772: }
773:
774: return sTable.toString();
775: }
776:
777: /* (non-Javadoc)
778: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#setDBTable(org.openharmonise.rm.metadata.Profile)
779: */
780: protected void setDBTable(Profile profile) {
781: m_sDataTable = getDBTableName(profile);
782:
783: }
784:
785: /* (non-Javadoc)
786: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#getColumnForData()
787: */
788: protected ColumnRef getColumnForData() throws DataStoreException {
789:
790: return getInstanceColumnRef(TAG_VALUE, isHistorical());
791: }
792:
793: /* (non-Javadoc)
794: * @see org.openharmonise.rm.metadata.AbstractPropertyInstance#getValueToStoreForValue(java.lang.Object)
795: */
796: protected Object getValueToStoreForValue(Object val)
797: throws ProfileException {
798: String sVal = null;
799:
800: if (val instanceof String) {
801: sVal = (String) val;
802: } else if (val instanceof Date) {
803: sVal = String.valueOf(((Date) val).getTime());
804: }
805:
806: return sVal;
807: }
808:
809: /**
810: * Adds a value to this instance.
811: *
812: * @param sValue the value to add
813: * @throws InvalidPropertyValueException if the given valus is invalid
814: */
815: protected void addValue(String sValue, int nId)
816: throws PopulateException {
817: if (sValue.trim().equals("") == false) {
818: try {
819: Range range = this .getProperty().getRange();
820:
821: if (range instanceof DateRange) {
822: super .addValue(getDateValue(sValue), nId);
823: } else {
824: super .addValue(sValue, nId);
825: }
826: } catch (DataAccessException e) {
827: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
828: } catch (InvalidPropertyValueException e) {
829: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
830: }
831: }
832: }
833:
834: /**
835: * Changes date in the given calendar by the delta value given.
836: *
837: * @param calendar calander representing date
838: * @param nField the time field
839: * @param sOperator '+' or '-'
840: * @param nDelta the amount of date or time to be added to the field
841: */
842: protected void changeDate(Calendar calendar, int nField,
843: String sOperator, int nDelta) {
844: if (sOperator.equals("-")) {
845: nDelta = 0 - nDelta;
846: }
847:
848: calendar.add(nField, nDelta);
849: }
850:
851: /**
852: * Returns the name of the database table for a property instance associated
853: * to the given <code>AbstractProfileObject</code>.
854: *
855: * @param profObj the profiled object
856: * @return the database table name for the property instance
857: */
858: public static String getDBTableName(String sClassname)
859: throws DataStoreException {
860: StringBuffer sbuf = new StringBuffer();
861:
862: sbuf.append(Profile.getTableName(sClassname, false));
863: sbuf.append(EXT_DATA);
864:
865: return sbuf.toString();
866: }
867:
868: /**
869: * Returns the name of the database table for a property instance associated
870: * to the given <code>AbstractProfileObject</code>.
871: *
872: * @param profObj the profiled object
873: * @return the database table name for the property instance
874: */
875: public static String getDBTableName(AbstractProfiledObject profObj) {
876: StringBuffer sbuf = new StringBuffer();
877:
878: sbuf.append(Profile.getDBTableName(profObj));
879: sbuf.append(EXT_DATA);
880:
881: return sbuf.toString();
882: }
883:
884: }
|