|
Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java Wed Jun 13 18:01:08 2012 @@ -18,73 +18,93 @@ *******************************************************************************/ package org.ofbiz.minilang.method.envops; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import javolution.util.FastList; - -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.UtilValidate; import org.ofbiz.base.util.UtilXml; import org.ofbiz.base.util.collections.FlexibleMapAccessor; import org.ofbiz.base.util.collections.MapComparator; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangRuntimeException; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Copies an environment field to a list + * Implements the <order-map-list> element. */ -public class OrderMapList extends MethodOperation { - - public static final String module = FieldToList.class.getName(); +public final class OrderMapList extends MethodOperation { - protected ContextAccessor<List<Map<Object, Object>>> listAcsr; - protected MapComparator mc; - protected List<FlexibleMapAccessor<String>> orderByAcsrList = FastList.newInstance(); + private final FlexibleMapAccessor<List<Map<Object, Object>>> listFma; + private final MapComparator mc; public OrderMapList(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - listAcsr = new ContextAccessor<List<Map<Object, Object>>>(element.getAttribute("list"), element.getAttribute("list-name")); - for (Element orderByElement : UtilXml.childElementList(element, "order-by")) { - FlexibleMapAccessor<String> fma = FlexibleMapAccessor.getInstance(UtilValidate.isNotEmpty(orderByElement.getAttribute("field")) ? orderByElement.getAttribute("field") : orderByElement.getAttribute("field-name")); - this.orderByAcsrList.add(fma); + if (MiniLangValidate.validationOn()) { + MiniLangValidate.attributeNames(simpleMethod, element, "list"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "list"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "list"); + MiniLangValidate.childElements(simpleMethod, element, "order-by"); + MiniLangValidate.requiredChildElements(simpleMethod, element, "order-by"); + } + listFma = FlexibleMapAccessor.getInstance(element.getAttribute("list")); + List<? extends Element> orderByElements = UtilXml.childElementList(element, "order-by"); + if (orderByElements.size() > 0) { + ArrayList<FlexibleMapAccessor<String>> orderByList = new ArrayList<FlexibleMapAccessor<String>>(orderByElements.size()); + for (Element orderByElement : orderByElements) { + FlexibleMapAccessor<String> fma = FlexibleMapAccessor.getInstance(orderByElement.getAttribute("field")); + orderByList.add(fma); + } + mc = new MapComparator(orderByList); + } else { + mc = null; } - this.mc = new MapComparator(this.orderByAcsrList); } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - List<Map<Object, Object>> orderList = listAcsr.get(methodContext); - if (orderList == null) { - if (Debug.infoOn()) - Debug.logInfo("List not found with name " + listAcsr + ", not ordering/sorting list.", module); - return true; + if (mc == null) { + throw new MiniLangRuntimeException("order-by sub-elements not found.", this); + } + List<Map<Object, Object>> orderList = listFma.get(methodContext.getEnvMap()); + if (orderList != null) { + Collections.sort(orderList, mc); } - Collections.sort(orderList, mc); return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - return "<order-map-list list-name=\"" + this.listAcsr + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<order-map-list "); + sb.append("list=\"").append(this.listFma).append("\" />"); + return sb.toString(); } + /** + * A factory for the <order-map-list> element. + */ public static final class OrderMapListFactory implements Factory<OrderMapList> { + @Override public OrderMapList createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new OrderMapList(element, simpleMethod); } + @Override public String getName() { return "order-map-list"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java Wed Jun 13 18:01:08 2012 @@ -24,12 +24,16 @@ import java.util.TimeZone; import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.ObjectType; +import org.ofbiz.base.util.Scriptlet; +import org.ofbiz.base.util.StringUtil; import org.ofbiz.base.util.UtilDateTime; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangRuntimeException; import org.ofbiz.minilang.MiniLangUtil; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; @@ -37,90 +41,144 @@ import org.w3c.dom.Element; import com.ibm.icu.util.Calendar; /** - * Adjust a Timestamp by a specified time. + * Implements the <set-calendar> element. */ -public class SetCalendar extends MethodOperation { +public final class SetCalendar extends MethodOperation { public static final String module = SetCalendar.class.getName(); - protected FlexibleStringExpander daysExdr; - protected FlexibleStringExpander defaultExdr; - protected ContextAccessor<Timestamp> field; - protected ContextAccessor<Object> fromField; - protected FlexibleStringExpander hoursExdr; - protected FlexibleStringExpander localeExdr; - protected FlexibleStringExpander millisExdr; - protected FlexibleStringExpander minutesExdr; - protected FlexibleStringExpander monthsExdr; - protected FlexibleStringExpander periodAlignEnd; - protected FlexibleStringExpander periodAlignStart; - protected FlexibleStringExpander secondsExdr; - protected boolean setIfEmpty; // default to true - protected boolean setIfNull; // default to false - protected FlexibleStringExpander timeZoneExdr; - protected FlexibleStringExpander valueExdr; - protected FlexibleStringExpander yearsExdr; + // This method is needed only during the v1 to v2 transition + private static boolean autoCorrect(Element element) { + boolean elementModified = false; + // Correct deprecated default-value attribute + String defaultAttr = element.getAttribute("default-value"); + if (defaultAttr.length() > 0) { + element.setAttribute("default", defaultAttr); + element.removeAttribute("default-value"); + elementModified = true; + } + // Correct deprecated from-field attribute + String fromAttr = element.getAttribute("from-field"); + if (fromAttr.length() > 0) { + element.setAttribute("from", fromAttr); + element.removeAttribute("from-field"); + elementModified = true; + } + // Correct value attribute expression that belongs in from attribute + String valueAttr = element.getAttribute("value").trim(); + if (valueAttr.startsWith("${") && valueAttr.endsWith("}")) { + valueAttr = valueAttr.substring(2, valueAttr.length() - 1); + if (!valueAttr.contains("${")) { + element.setAttribute("from", valueAttr); + element.removeAttribute("value"); + elementModified = true; + } + } + return elementModified; + } + + private final FlexibleStringExpander daysFse; + private final FlexibleStringExpander defaultFse; + private final FlexibleMapAccessor<Object> fieldFma; + private final FlexibleMapAccessor<Object> fromFma; + private final FlexibleStringExpander hoursFse; + private final FlexibleStringExpander localeFse; + private final FlexibleStringExpander millisFse; + private final FlexibleStringExpander minutesFse; + private final FlexibleStringExpander monthsFse; + private final FlexibleStringExpander periodAlignEnd; + private final FlexibleStringExpander periodAlignStart; + private final FlexibleStringExpander secondsFse; + private final boolean setIfEmpty; + private final boolean setIfNull; + private final Scriptlet scriptlet; + private final FlexibleStringExpander timeZoneFse; + private final FlexibleStringExpander valueFse; + private final FlexibleStringExpander yearsFse; public SetCalendar(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - this.field = new ContextAccessor<Timestamp>(element.getAttribute("field")); - this.fromField = new ContextAccessor<Object>(element.getAttribute("from-field")); - this.valueExdr = FlexibleStringExpander.getInstance(element.getAttribute("value")); - this.defaultExdr = FlexibleStringExpander.getInstance(element.getAttribute("default-value")); - this.yearsExdr = FlexibleStringExpander.getInstance(element.getAttribute("years")); - this.monthsExdr = FlexibleStringExpander.getInstance(element.getAttribute("months")); - this.daysExdr = FlexibleStringExpander.getInstance(element.getAttribute("days")); - this.hoursExdr = FlexibleStringExpander.getInstance(element.getAttribute("hours")); - this.minutesExdr = FlexibleStringExpander.getInstance(element.getAttribute("minutes")); - this.secondsExdr = FlexibleStringExpander.getInstance(element.getAttribute("seconds")); - this.millisExdr = FlexibleStringExpander.getInstance(element.getAttribute("millis")); - this.periodAlignStart = FlexibleStringExpander.getInstance(element.getAttribute("period-align-start")); - this.periodAlignEnd = FlexibleStringExpander.getInstance(element.getAttribute("period-align-end")); - this.localeExdr = FlexibleStringExpander.getInstance(element.getAttribute("locale")); - this.timeZoneExdr = FlexibleStringExpander.getInstance(element.getAttribute("time-zone")); - // default to false, anything but true is false + if (MiniLangValidate.validationOn()) { + MiniLangValidate.deprecatedAttribute(simpleMethod, element, "from-field", "replace with \"from\""); + MiniLangValidate.deprecatedAttribute(simpleMethod, element, "default-value", "replace with \"default\""); + MiniLangValidate.attributeNames(simpleMethod, element, "field", "from-field", "from", "value", "default-value", "default", "set-if-null", "set-if-empty", + "years", "months", "days", "hours", "minutes", "seconds", "millis", "period-align-start", "period-align-end", "locale", "time-zone"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "field"); + MiniLangValidate.requireAnyAttribute(simpleMethod, element, "from", "value"); + MiniLangValidate.constantPlusExpressionAttributes(simpleMethod, element, "value"); + MiniLangValidate.constantAttributes(simpleMethod, element, "set-if-null", "set-if-empty"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "field", "from", "from-field"); + MiniLangValidate.noChildElements(simpleMethod, element); + } + boolean elementModified = autoCorrect(element); + if (elementModified && MiniLangUtil.autoCorrectOn()) { + MiniLangUtil.flagDocumentAsCorrected(element); + } + this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field")); + String fromAttribute = element.getAttribute("from"); + if (MiniLangUtil.containsScript(fromAttribute)) { + this.scriptlet = new Scriptlet(StringUtil.convertOperatorSubstitutions(fromAttribute)); + this.fromFma = FlexibleMapAccessor.getInstance(null); + } else { + this.scriptlet = null; + this.fromFma = FlexibleMapAccessor.getInstance(fromAttribute); + } + this.valueFse = FlexibleStringExpander.getInstance(element.getAttribute("value")); + if (!fromAttribute.isEmpty() && !this.valueFse.isEmpty()) { + throw new IllegalArgumentException("Cannot include both a from attribute and a value attribute in a <set-calendar> element."); + } + this.defaultFse = FlexibleStringExpander.getInstance(element.getAttribute("default")); this.setIfNull = "true".equals(element.getAttribute("set-if-null")); - // default to true, anything but false is true this.setIfEmpty = !"false".equals(element.getAttribute("set-if-empty")); - if (!this.fromField.isEmpty() && !this.valueExdr.isEmpty()) { - throw new IllegalArgumentException("Cannot specify a from-field [" + element.getAttribute("from-field") + "] and a value [" + element.getAttribute("value") + "] on the set-calendar action in a screen widget"); - } + this.yearsFse = FlexibleStringExpander.getInstance(element.getAttribute("years")); + this.monthsFse = FlexibleStringExpander.getInstance(element.getAttribute("months")); + this.daysFse = FlexibleStringExpander.getInstance(element.getAttribute("days")); + this.hoursFse = FlexibleStringExpander.getInstance(element.getAttribute("hours")); + this.minutesFse = FlexibleStringExpander.getInstance(element.getAttribute("minutes")); + this.secondsFse = FlexibleStringExpander.getInstance(element.getAttribute("seconds")); + this.millisFse = FlexibleStringExpander.getInstance(element.getAttribute("millis")); + this.periodAlignStart = FlexibleStringExpander.getInstance(element.getAttribute("period-align-start")); + this.periodAlignEnd = FlexibleStringExpander.getInstance(element.getAttribute("period-align-end")); + this.localeFse = FlexibleStringExpander.getInstance(element.getAttribute("locale")); + this.timeZoneFse = FlexibleStringExpander.getInstance(element.getAttribute("time-zone")); } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { Object newValue = null; - if (!this.fromField.isEmpty()) { - newValue = this.fromField.get(methodContext); - if (Debug.verboseOn()) - Debug.logVerbose("In screen getting value for field from [" + this.fromField.toString() + "]: " + newValue, module); - } else if (!this.valueExdr.isEmpty()) { - newValue = methodContext.expandString(this.valueExdr); - } - // If newValue is still empty, use the default value - if (ObjectType.isEmpty(newValue) && !this.defaultExdr.isEmpty()) { - newValue = methodContext.expandString(this.defaultExdr); + if (this.scriptlet != null) { + try { + newValue = this.scriptlet.executeScript(methodContext.getEnvMap()); + } catch (Exception exc) { + Debug.logWarning(exc, "Error evaluating scriptlet [" + this.scriptlet + "]: " + exc, module); + } + } else if (!this.fromFma.isEmpty()) { + newValue = this.fromFma.get(methodContext.getEnvMap()); + } else if (!this.valueFse.isEmpty()) { + newValue = this.valueFse.expand(methodContext.getEnvMap()); + } + if (ObjectType.isEmpty(newValue) && !this.defaultFse.isEmpty()) { + newValue = this.defaultFse.expand(methodContext.getEnvMap()); } if (!setIfNull && newValue == null) { - if (Debug.verboseOn()) - Debug.logVerbose("Field value not found (null) with name [" + fromField + "] and value [" + valueExdr + "], and there was not default value, not setting field", module); return true; } if (!setIfEmpty && ObjectType.isEmpty(newValue)) { - if (Debug.verboseOn()) - Debug.logVerbose("Field value not found (empty) with name [" + fromField + "] and value [" + valueExdr + "], and there was not default value, not setting field", module); return true; } - // Convert attributes to the corresponding data types Locale locale = null; TimeZone timeZone = null; Timestamp fromStamp = null; + int years = 0; + int months = 0; + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + int millis = 0; try { - if (!this.localeExdr.isEmpty()) { - locale = (Locale) ObjectType.simpleTypeConvert(methodContext.expandString(this.localeExdr), "Locale", null, null); - } - if (!this.timeZoneExdr.isEmpty()) { - timeZone = (TimeZone) ObjectType.simpleTypeConvert(methodContext.expandString(this.timeZoneExdr), "TimeZone", null, null); + if (!this.localeFse.isEmpty()) { + locale = (Locale) ObjectType.simpleTypeConvert(this.localeFse.expand(methodContext.getEnvMap()), "Locale", null, null); } if (locale == null) { locale = methodContext.getLocale(); @@ -128,6 +186,9 @@ public class SetCalendar extends MethodO if (locale == null) { locale = Locale.getDefault(); } + if (!this.timeZoneFse.isEmpty()) { + timeZone = (TimeZone) ObjectType.simpleTypeConvert(this.timeZoneFse.expand(methodContext.getEnvMap()), "TimeZone", null, null); + } if (timeZone == null) { timeZone = methodContext.getTimeZone(); } @@ -135,21 +196,30 @@ public class SetCalendar extends MethodO timeZone = TimeZone.getDefault(); } fromStamp = (Timestamp) MiniLangUtil.convertType(newValue, java.sql.Timestamp.class, locale, timeZone, UtilDateTime.DATE_TIME_FORMAT); + if (!this.yearsFse.isEmpty()) { + years= Integer.parseInt(this.yearsFse.expandString(methodContext.getEnvMap())); + } + if (!this.monthsFse.isEmpty()) { + months = Integer.parseInt(this.monthsFse.expandString(methodContext.getEnvMap())); + } + if (!this.daysFse.isEmpty()) { + days = Integer.parseInt(this.daysFse.expandString(methodContext.getEnvMap())); + } + if (!this.hoursFse.isEmpty()) { + hours = Integer.parseInt(this.hoursFse.expandString(methodContext.getEnvMap())); + } + if (!this.minutesFse.isEmpty()) { + minutes = Integer.parseInt(this.minutesFse.expandString(methodContext.getEnvMap())); + } + if (!this.secondsFse.isEmpty()) { + seconds = Integer.parseInt(this.secondsFse.expandString(methodContext.getEnvMap())); + } + if (!this.millisFse.isEmpty()) { + millis = Integer.parseInt(this.millisFse.expandString(methodContext.getEnvMap())); + } } catch (Exception e) { - // Catching all exceptions - even potential ClassCastException - if (Debug.verboseOn()) - Debug.logVerbose("Error converting attributes to objects: " + e.getMessage(), module); - return true; + throw new MiniLangRuntimeException("Exception thrown while parsing attributes: " + e.getMessage(), this); } - // Convert Strings to ints - int years = this.yearsExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.yearsExdr)); - int months = this.monthsExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.monthsExdr)); - int days = this.daysExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.daysExdr)); - int hours = this.hoursExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.hoursExdr)); - int minutes = this.minutesExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.minutesExdr)); - int seconds = this.secondsExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.secondsExdr)); - int millis = this.millisExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.millisExdr)); - // Adjust calendar Calendar cal = UtilDateTime.toCalendar(fromStamp, timeZone, locale); cal.add(Calendar.MILLISECOND, millis); cal.add(Calendar.SECOND, seconds); @@ -159,9 +229,8 @@ public class SetCalendar extends MethodO cal.add(Calendar.MONTH, months); cal.add(Calendar.YEAR, years); Timestamp toStamp = new Timestamp(cal.getTimeInMillis()); - // Align period start/end if (!periodAlignStart.isEmpty()) { - String period = methodContext.expandString(periodAlignStart); + String period = periodAlignStart.expandString(methodContext.getEnvMap()); if ("day".equals(period)) { toStamp = UtilDateTime.getDayStart(toStamp, 0, timeZone, locale); } else if ("week".equals(period)) { @@ -170,9 +239,11 @@ public class SetCalendar extends MethodO toStamp = UtilDateTime.getMonthStart(toStamp, 0, timeZone, locale); } else if ("year".equals(period)) { toStamp = UtilDateTime.getYearStart(toStamp, 0, timeZone, locale); + } else { + throw new MiniLangRuntimeException("Invalid period-align-start attribute value: " + period, this); } } else if (!periodAlignEnd.isEmpty()) { - String period = methodContext.expandString(periodAlignEnd); + String period = periodAlignEnd.expandString(methodContext.getEnvMap()); if ("day".equals(period)) { toStamp = UtilDateTime.getDayEnd(toStamp, timeZone, locale); } else if ("week".equals(period)) { @@ -181,31 +252,93 @@ public class SetCalendar extends MethodO toStamp = UtilDateTime.getMonthEnd(toStamp, timeZone, locale); } else if ("year".equals(period)) { toStamp = UtilDateTime.getYearEnd(toStamp, timeZone, locale); + } else { + throw new MiniLangRuntimeException("Invalid period-align-end attribute value: " + period, this); } } - if (Debug.verboseOn()) - Debug.logVerbose("In screen setting calendar [" + this.field.toString(), module); - this.field.put(methodContext, toStamp); + this.fieldFma.put(methodContext.getEnvMap(), toStamp); return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - return "<set-calendar field=\"" + this.field + (this.valueExdr.isEmpty() ? "" : "\" value=\"" + this.valueExdr.getOriginal()) + (this.fromField.isEmpty() ? "" : "\" from-field=\"" + this.fromField) + (this.defaultExdr.isEmpty() ? "" : "\" default-value=\"" + this.defaultExdr.getOriginal()) - + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<set-calendar "); + sb.append("field=\"").append(this.fieldFma).append("\" "); + if (!this.fromFma.isEmpty()) { + sb.append("from=\"").append(this.fromFma).append("\" "); + } + if (this.scriptlet != null) { + sb.append("from=\"").append(this.scriptlet).append("\" "); + } + if (!this.valueFse.isEmpty()) { + sb.append("value=\"").append(this.valueFse).append("\" "); + } + if (!this.defaultFse.isEmpty()) { + sb.append("default=\"").append(this.defaultFse).append("\" "); + } + if (!this.yearsFse.isEmpty()) { + sb.append("years=\"").append(this.yearsFse).append("\" "); + } + if (!this.monthsFse.isEmpty()) { + sb.append("months=\"").append(this.monthsFse).append("\" "); + } + if (!this.daysFse.isEmpty()) { + sb.append("days=\"").append(this.daysFse).append("\" "); + } + if (!this.hoursFse.isEmpty()) { + sb.append("hours=\"").append(this.hoursFse).append("\" "); + } + if (!this.minutesFse.isEmpty()) { + sb.append("minutes=\"").append(this.minutesFse).append("\" "); + } + if (!this.secondsFse.isEmpty()) { + sb.append("seconds=\"").append(this.secondsFse).append("\" "); + } + if (!this.millisFse.isEmpty()) { + sb.append("millis=\"").append(this.millisFse).append("\" "); + } + if (!this.periodAlignStart.isEmpty()) { + sb.append("period-align-start=\"").append(this.localeFse).append("\" "); + } + if (!this.periodAlignEnd.isEmpty()) { + sb.append("period-align-end=\"").append(this.localeFse).append("\" "); + } + if (!this.localeFse.isEmpty()) { + sb.append("locale=\"").append(this.localeFse).append("\" "); + } + if (!this.timeZoneFse.isEmpty()) { + sb.append("time-zone=\"").append(this.timeZoneFse).append("\" "); + } + if (this.setIfNull) { + sb.append("set-if-null=\"true\" "); + } + if (!this.setIfEmpty) { + sb.append("set-if-empty=\"false\" "); + } + sb.append("/>"); + return sb.toString(); } + /** + * A factory for the <set-calendar> element. + */ public static final class SetCalendarFactory implements Factory<SetCalendar> { + @Override public SetCalendar createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new SetCalendar(element, simpleMethod); } + @Override public String getName() { return "set-calendar"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java Wed Jun 13 18:01:08 2012 @@ -36,7 +36,7 @@ import org.ofbiz.minilang.method.MethodO import org.w3c.dom.Element; /** - * Assigns a field from an expression or script, or from a constant value. Also supports a default value and type conversion. + * Implements the <set> element. */ public final class SetOperation extends MethodOperation { @@ -73,6 +73,7 @@ public final class SetOperation extends } private final FlexibleStringExpander defaultFse; + private final FlexibleStringExpander formatFse; private final FlexibleMapAccessor<Object> fieldFma; private final FlexibleMapAccessor<Object> fromFma; private final Scriptlet scriptlet; @@ -85,11 +86,9 @@ public final class SetOperation extends public SetOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); if (MiniLangValidate.validationOn()) { - /* MiniLangValidate.deprecatedAttribute(simpleMethod, element, "from-field", "replace with \"from\""); MiniLangValidate.deprecatedAttribute(simpleMethod, element, "default-value", "replace with \"default\""); - */ - MiniLangValidate.attributeNames(simpleMethod, element, "field", "from-field", "from", "value", "default-value", "default", "type", "set-if-null", "set-if-empty"); + MiniLangValidate.attributeNames(simpleMethod, element, "field", "from-field", "from", "value", "default-value", "default", "format", "type", "set-if-null", "set-if-empty"); MiniLangValidate.requiredAttributes(simpleMethod, element, "field"); MiniLangValidate.requireAnyAttribute(simpleMethod, element, "from-field", "from", "value"); MiniLangValidate.constantPlusExpressionAttributes(simpleMethod, element, "value"); @@ -112,6 +111,7 @@ public final class SetOperation extends } this.valueFse = FlexibleStringExpander.getInstance(element.getAttribute("value")); this.defaultFse = FlexibleStringExpander.getInstance(element.getAttribute("default")); + this.formatFse = FlexibleStringExpander.getInstance(element.getAttribute("format")); this.type = element.getAttribute("type"); Class<?> targetClass = null; if (!this.type.isEmpty()) { @@ -124,7 +124,7 @@ public final class SetOperation extends this.targetClass = targetClass; this.setIfNull = "true".equals(element.getAttribute("set-if-null")); // default to false, anything but true is false this.setIfEmpty = !"false".equals(element.getAttribute("set-if-empty")); // default to true, anything but false is true - if (!this.fromFma.isEmpty() && !this.valueFse.isEmpty()) { + if (!fromAttribute.isEmpty() && !this.valueFse.isEmpty()) { throw new IllegalArgumentException("Cannot include both a from attribute and a value attribute in a <set> element."); } } @@ -166,13 +166,17 @@ public final class SetOperation extends newValue = FastList.newInstance(); } else { try { + String format = null; + if (!this.formatFse.isEmpty()) { + format = this.formatFse.expandString(methodContext.getEnvMap()); + } Class<?> targetClass = this.targetClass; if (targetClass == null) { targetClass = MiniLangUtil.getObjectClassForConversion(newValue); } - newValue = MiniLangUtil.convertType(newValue, targetClass, methodContext.getLocale(), methodContext.getTimeZone(), null); + newValue = MiniLangUtil.convertType(newValue, targetClass, methodContext.getLocale(), methodContext.getTimeZone(), format); } catch (Exception e) { - String errMsg = "Could not convert field value for the field: [" + this.fieldFma.toString() + "] to the [" + this.type + "] type for the value [" + newValue + "]: " + e.toString(); + String errMsg = "Could not convert field value for the field: [" + this.fieldFma.toString() + "] to the [" + this.type + "] type for the value [" + newValue + "]: " + e.getMessage(); Debug.logWarning(e, errMsg, module); this.simpleMethod.addErrorMessage(methodContext, errMsg); return false; @@ -180,7 +184,7 @@ public final class SetOperation extends } } if (Debug.verboseOn()) - Debug.logVerbose("In screen setting field [" + this.fieldFma.toString() + "] to value: " + newValue, module); + Debug.logVerbose("Setting field [" + this.fieldFma.toString() + "] to value: " + newValue, module); this.fieldFma.put(methodContext.getEnvMap(), newValue); return true; } @@ -216,15 +220,26 @@ public final class SetOperation extends if (this.type.length() > 0) { sb.append("type=\"").append(this.type).append("\" "); } + if (this.setIfNull) { + sb.append("set-if-null=\"true\" "); + } + if (!this.setIfEmpty) { + sb.append("set-if-empty=\"false\" "); + } sb.append("/>"); return sb.toString(); } + /** + * A factory for the <set> element. + */ public static final class SetOperationFactory implements Factory<SetOperation> { + @Override public SetOperation createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new SetOperation(element, simpleMethod); } + @Override public String getName() { return "set"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java Wed Jun 13 18:01:08 2012 @@ -20,110 +20,106 @@ package org.ofbiz.minilang.method.envops import java.text.MessageFormat; import java.util.List; -import java.util.Map; -import javolution.util.FastMap; - -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangRuntimeException; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Appends the specified String to a field + * Implements the <string-append> element. */ -public class StringAppend extends MethodOperation { - - public static final String module = StringAppend.class.getName(); +public final class StringAppend extends MethodOperation { - ContextAccessor<List<? extends Object>> argListAcsr; - ContextAccessor<String> fieldAcsr; - ContextAccessor<Map<String, Object>> mapAcsr; - String prefix; - String string; - String suffix; + private final FlexibleMapAccessor<List<? extends Object>> argListFma; + private final FlexibleMapAccessor<String> fieldFma; + private final FlexibleStringExpander prefixFse; + private final FlexibleStringExpander stringFse; + private final FlexibleStringExpander suffixFse; public StringAppend(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - string = element.getAttribute("string"); - prefix = element.getAttribute("prefix"); - suffix = element.getAttribute("suffix"); - // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported - fieldAcsr = new ContextAccessor<String>(element.getAttribute("field"), element.getAttribute("field-name")); - mapAcsr = new ContextAccessor<Map<String, Object>>(element.getAttribute("map-name")); - argListAcsr = new ContextAccessor<List<? extends Object>>(element.getAttribute("arg-list"), element.getAttribute("arg-list-name")); - } - - public String appendString(String oldValue, MethodContext methodContext) { - String value = methodContext.expandString(string); - String prefixValue = methodContext.expandString(prefix); - String suffixValue = methodContext.expandString(suffix); - if (!argListAcsr.isEmpty()) { - List<? extends Object> argList = argListAcsr.get(methodContext); - if (UtilValidate.isNotEmpty(argList)) { - value = MessageFormat.format(value, argList.toArray()); - } - } - StringBuilder newValue = new StringBuilder(); - if (UtilValidate.isNotEmpty(value)) { - if (UtilValidate.isEmpty(oldValue)) { - newValue.append(value); - } else { - newValue.append(oldValue); - if (prefixValue != null) - newValue.append(prefixValue); - newValue.append(value); - if (suffixValue != null) - newValue.append(suffixValue); - } - } else { - if (UtilValidate.isEmpty(oldValue)) { - newValue.append(oldValue); - } + if (MiniLangValidate.validationOn()) { + MiniLangValidate.attributeNames(simpleMethod, element, "field", "arg-list", "prefix", "string", "suffix"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "field", "string"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "field", "arg-list"); + MiniLangValidate.noChildElements(simpleMethod, element); } - return newValue.toString(); + argListFma = FlexibleMapAccessor.getInstance(element.getAttribute("arg-list")); + fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field")); + prefixFse = FlexibleStringExpander.getInstance(element.getAttribute("prefix")); + stringFse = FlexibleStringExpander.getInstance(element.getAttribute("string")); + suffixFse = FlexibleStringExpander.getInstance(element.getAttribute("suffix")); } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - if (!mapAcsr.isEmpty()) { - Map<String, Object> toMap = mapAcsr.get(methodContext); - if (toMap == null) { - if (Debug.verboseOn()) - Debug.logVerbose("Map not found with name " + mapAcsr + ", creating new map", module); - toMap = FastMap.newInstance(); - mapAcsr.put(methodContext, toMap); + String value = stringFse.expandString(methodContext.getEnvMap()); + List<? extends Object> argList = argListFma.get(methodContext.getEnvMap()); + if (argList != null) { + try { + value = MessageFormat.format(value, argList.toArray()); + } catch (IllegalArgumentException e) { + throw new MiniLangRuntimeException("Exception thrown while formatting the string attribute: " + e.getMessage(), this); } - String oldValue = fieldAcsr.get(toMap, methodContext); - fieldAcsr.put(toMap, this.appendString(oldValue, methodContext), methodContext); - } else { - String oldValue = fieldAcsr.get(methodContext); - fieldAcsr.put(methodContext, this.appendString(oldValue, methodContext)); + } + if (!value.isEmpty()) { + String prefixValue = prefixFse.expandString(methodContext.getEnvMap()); + String suffixValue = suffixFse.expandString(methodContext.getEnvMap()); + StringBuilder newValue = new StringBuilder(); + String oldValue = fieldFma.get(methodContext.getEnvMap()); + if (oldValue != null) { + newValue.append(oldValue); + } + newValue.append(prefixValue).append(value).append(suffixValue); + fieldFma.put(methodContext.getEnvMap(), newValue.toString()); } return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - // TODO: something more than the empty tag - return "<string-append string=\"" + this.string + "\" prefix=\"" + this.prefix + "\" suffix=\"" + this.suffix + "\" field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<string-append "); + sb.append("field=\"").append(this.fieldFma).append("\" "); + sb.append("string=\"").append(this.stringFse).append("\" "); + if (!this.argListFma.isEmpty()) { + sb.append("arg-list=\"").append(this.argListFma).append("\" "); + } + if (!this.prefixFse.isEmpty()) { + sb.append("prefix=\"").append(this.prefixFse).append("\" "); + } + if (!this.suffixFse.isEmpty()) { + sb.append("suffix=\"").append(this.suffixFse).append("\" "); + } + sb.append("/>"); + return sb.toString(); } + /** + * A factory for the <string-append> element. + */ public static final class StringAppendFactory implements Factory<StringAppend> { + @Override public StringAppend createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new StringAppend(element, simpleMethod); } + @Override public String getName() { return "string-append"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringToList.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringToList.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringToList.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/StringToList.java Wed Jun 13 18:01:08 2012 @@ -23,43 +23,52 @@ import java.util.List; import javolution.util.FastList; -import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.MessageString; import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangRuntimeException; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Appends the specified String to a List + * Implements the <string-to-list> element. */ -public class StringToList extends MethodOperation { +public final class StringToList extends MethodOperation { - public static final String module = StringToList.class.getName(); - - ContextAccessor<List<? extends Object>> argListAcsr; - ContextAccessor<List<Object>> listAcsr; - String messageFieldName; - String string; + private final FlexibleMapAccessor<List<? extends Object>> argListFma; + private final FlexibleMapAccessor<List<Object>> listFma; + private final String messageFieldName; + private final FlexibleStringExpander stringFse; public StringToList(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - string = element.getAttribute("string"); - listAcsr = new ContextAccessor<List<Object>>(element.getAttribute("list"), element.getAttribute("list-name")); - argListAcsr = new ContextAccessor<List<? extends Object>>(element.getAttribute("arg-list"), element.getAttribute("arg-list-name")); - messageFieldName = UtilValidate.isNotEmpty(element.getAttribute("message-field")) ? element.getAttribute("message-field") : element.getAttribute("message-field-name"); + if (MiniLangValidate.validationOn()) { + MiniLangValidate.handleError("<string-to-list> element is deprecated (use <set>)", simpleMethod, element); + MiniLangValidate.attributeNames(simpleMethod, element, "list", "arg-list", "string", "message-field"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "list", "string"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "list", "arg-list"); + MiniLangValidate.noChildElements(simpleMethod, element); + } + stringFse = FlexibleStringExpander.getInstance(element.getAttribute("string")); + listFma = FlexibleMapAccessor.getInstance(element.getAttribute("list")); + argListFma = FlexibleMapAccessor.getInstance(element.getAttribute("arg-list")); + messageFieldName = element.getAttribute("message-field"); } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - String valueStr = methodContext.expandString(string); - if (!argListAcsr.isEmpty()) { - List<? extends Object> argList = argListAcsr.get(methodContext); - if (UtilValidate.isNotEmpty(argList)) { + String valueStr = stringFse.expandString(methodContext.getEnvMap()); + List<? extends Object> argList = argListFma.get(methodContext.getEnvMap()); + if (argList != null) { + try { valueStr = MessageFormat.format(valueStr, argList.toArray()); + } catch (IllegalArgumentException e) { + throw new MiniLangRuntimeException("Exception thrown while formatting the string attribute: " + e.getMessage(), this); } } Object value; @@ -68,12 +77,10 @@ public class StringToList extends Method } else { value = valueStr; } - List<Object> toList = listAcsr.get(methodContext); + List<Object> toList = listFma.get(methodContext.getEnvMap()); if (toList == null) { - if (Debug.verboseOn()) - Debug.logVerbose("List not found with name " + listAcsr + ", creating new List", module); toList = FastList.newInstance(); - listAcsr.put(methodContext, toList); + listFma.put(methodContext.getEnvMap(), toList); } toList.add(value); return true; @@ -81,21 +88,39 @@ public class StringToList extends Method @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - // TODO: something more than the empty tag - return "<string-to-list string=\"" + this.string + "\" list-name=\"" + this.listAcsr + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<string-to-list "); + sb.append("string=\"").append(this.stringFse).append("\" "); + sb.append("list=\"").append(this.listFma).append("\" "); + if (!this.argListFma.isEmpty()) { + sb.append("arg-list=\"").append(this.argListFma).append("\" "); + } + if (!this.messageFieldName.isEmpty()) { + sb.append("message-field=\"").append(this.messageFieldName).append("\" "); + } + sb.append("/>"); + return sb.toString(); } + /** + * A factory for the <string-to-list> element. + */ public static final class StringToListFactory implements Factory<StringToList> { + @Override public StringToList createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new StringToList(element, simpleMethod); } + @Override public String getName() { return "string-to-list"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/ToString.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/ToString.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/ToString.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/envops/ToString.java Wed Jun 13 18:01:08 2012 @@ -18,111 +18,106 @@ *******************************************************************************/ package org.ofbiz.minilang.method.envops; -import java.util.Map; - -import javolution.util.FastMap; - -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.GeneralException; -import org.ofbiz.base.util.ObjectType; import org.ofbiz.base.util.StringUtil; -import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangRuntimeException; import org.ofbiz.minilang.MiniLangUtil; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Converts the specified field to a String, using toString() + * Implements the <to-string> element. */ -public class ToString extends MethodOperation { +public final class ToString extends MethodOperation { - public static final String module = ToString.class.getName(); - - ContextAccessor<Object> fieldAcsr; - String format; - ContextAccessor<Map<String, Object>> mapAcsr; - Integer numericPadding; + private final FlexibleMapAccessor<Object> fieldFma; + private final String format; + private final Integer numericPadding; public ToString(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported - fieldAcsr = new ContextAccessor<Object>(element.getAttribute("field"), element.getAttribute("field-name")); - mapAcsr = new ContextAccessor<Map<String, Object>>(element.getAttribute("map-name")); + if (MiniLangValidate.validationOn()) { + MiniLangValidate.handleError("<to-string> element is deprecated (use <set>)", simpleMethod, element); + MiniLangValidate.attributeNames(simpleMethod, element, "field", "format", "numeric-padding"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "field"); + MiniLangValidate.constantAttributes(simpleMethod, element, "format", "numeric-padding"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "field"); + MiniLangValidate.noChildElements(simpleMethod, element); + } + fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field")); format = element.getAttribute("format"); - String npStr = element.getAttribute("numeric-padding"); - if (UtilValidate.isNotEmpty(npStr)) { + Integer numericPadding = null; + String npAttribute = element.getAttribute("numeric-padding"); + if (!npAttribute.isEmpty()) { try { - this.numericPadding = Integer.valueOf(npStr); + numericPadding = Integer.valueOf(npAttribute); } catch (Exception e) { - Debug.logError(e, "Error parsing numeric-padding attribute value on the to-string element", module); + MiniLangValidate.handleError("Exception thrown while parsing numeric-padding attribute: " + e.getMessage(), simpleMethod, element); } } - } - - public String doToString(Object obj, MethodContext methodContext) { - String outStr = null; - try { - if (UtilValidate.isNotEmpty(format)) { - outStr = (String) MiniLangUtil.convertType(obj, String.class, methodContext.getLocale(), methodContext.getTimeZone(), format); - } else { - outStr = obj.toString(); - } - } catch (Exception e) { - Debug.logError(e, "", module); - outStr = obj.toString(); - } - if (this.numericPadding != null) { - outStr = StringUtil.padNumberString(outStr, this.numericPadding.intValue()); - } - return outStr; + this.numericPadding = numericPadding; } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - if (!mapAcsr.isEmpty()) { - Map<String, Object> toMap = mapAcsr.get(methodContext); - if (toMap == null) { - // it seems silly to create a new map, but necessary since whenever - // an env field like a Map or List is referenced it should be created, even if empty - if (Debug.verboseOn()) - Debug.logVerbose("Map not found with name " + mapAcsr + ", creating new map", module); - toMap = FastMap.newInstance(); - mapAcsr.put(methodContext, toMap); - } - Object obj = fieldAcsr.get(toMap, methodContext); - if (obj != null) { - fieldAcsr.put(toMap, doToString(obj, methodContext), methodContext); + Object value = fieldFma.get(methodContext.getEnvMap()); + if (value != null) { + try { + if (!format.isEmpty()) { + value = MiniLangUtil.convertType(value, String.class, methodContext.getLocale(), methodContext.getTimeZone(), format); + } else { + value = value.toString(); + } + } catch (Exception e) { + throw new MiniLangRuntimeException("Exception thrown while converting field to a string: " + e.getMessage(), this); } - } else { - Object obj = fieldAcsr.get(methodContext); - if (obj != null) { - fieldAcsr.put(methodContext, doToString(obj, methodContext)); + if (this.numericPadding != null) { + value = StringUtil.padNumberString(value.toString(), this.numericPadding.intValue()); } + fieldFma.put(methodContext.getEnvMap(), value); } return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - // TODO: something more than the empty tag - return "<to-string field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>"; + return toString(); } + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<to-string "); + sb.append("field=\"").append(this.fieldFma).append("\" "); + if (!this.format.isEmpty()) { + sb.append("format=\"").append(this.format).append("\" "); + } + if (numericPadding != null) { + sb.append("numeric-padding=\"").append(this.numericPadding).append("\" "); + } + sb.append("/>"); + return sb.toString(); + } + + /** + * A factory for the <to-string> element. + */ public static final class ToStringFactory implements Factory<ToString> { + @Override public ToString createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new ToString(element, simpleMethod); } + @Override public String getName() { return "to-string"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToRequest.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToRequest.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToRequest.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToRequest.java Wed Jun 13 18:01:08 2012 @@ -18,79 +18,85 @@ *******************************************************************************/ package org.ofbiz.minilang.method.eventops; -import java.util.Map; - -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.collections.FlexibleServletAccessor; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Copies a map field to a Servlet request attribute + * Implements the <field-to-request> element. */ -public class FieldToRequest extends MethodOperation { - - public static final String module = FieldToRequest.class.getName(); +public final class FieldToRequest extends MethodOperation { - ContextAccessor<Object> fieldAcsr; - ContextAccessor<Map<String, ? extends Object>> mapAcsr; - FlexibleServletAccessor<Object> requestAcsr; + private final FlexibleMapAccessor<Object> fieldFma; + private final FlexibleStringExpander attributeNameFse; public FieldToRequest(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported - mapAcsr = new ContextAccessor<Map<String, ? extends Object>>(element.getAttribute("map-name")); - fieldAcsr = new ContextAccessor<Object>(element.getAttribute("field"), element.getAttribute("field-name")); - requestAcsr = new FlexibleServletAccessor<Object>(element.getAttribute("request-name"), fieldAcsr.toString()); + if (MiniLangValidate.validationOn()) { + MiniLangValidate.attributeNames(simpleMethod, element, "field", "request-name"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "field"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "field"); + MiniLangValidate.noChildElements(simpleMethod, element); + } + this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field")); + String attributeName = element.getAttribute("request-name"); + if (!attributeName.isEmpty()) { + this.attributeNameFse = FlexibleStringExpander.getInstance(attributeName); + } else { + this.attributeNameFse = FlexibleStringExpander.getInstance(this.fieldFma.toString()); + } } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - // only run this if it is in an EVENT context if (methodContext.getMethodType() == MethodContext.EVENT) { - Object fieldVal = null; - if (!mapAcsr.isEmpty()) { - Map<String, ? extends Object> fromMap = mapAcsr.get(methodContext); - if (fromMap == null) { - Debug.logWarning("Map not found with name " + mapAcsr, module); - return true; + Object fieldVal = fieldFma.get(methodContext.getEnvMap()); + if (fieldVal != null) { + String attributeName = attributeNameFse.expandString(methodContext.getEnvMap()); + if (!attributeName.isEmpty()) { + methodContext.getRequest().setAttribute(attributeName, fieldVal); } - fieldVal = fieldAcsr.get(fromMap, methodContext); - } else { - // no map name, try the env - fieldVal = fieldAcsr.get(methodContext); - } - - if (fieldVal == null) { - Debug.logWarning("Field value not found with name " + fieldAcsr + " in Map with name " + mapAcsr, module); - return true; } - requestAcsr.put(methodContext.getRequest(), fieldVal, methodContext.getEnvMap()); } return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - // TODO: add all attributes and other info - return "<field-to-request field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<field-to-request "); + sb.append("field=\"").append(this.fieldFma).append("\" "); + if (!this.attributeNameFse.isEmpty()) { + sb.append("request-name=\"").append(this.attributeNameFse).append("\" "); + } + sb.append("/>"); + return sb.toString(); } + /** + * A factory for the <field-to-request> element. + */ public static final class FieldToRequestFactory implements Factory<FieldToRequest> { + @Override public FieldToRequest createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new FieldToRequest(element, simpleMethod); } + @Override public String getName() { return "field-to-request"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToSession.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToSession.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToSession.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/FieldToSession.java Wed Jun 13 18:01:08 2012 @@ -18,79 +18,85 @@ *******************************************************************************/ package org.ofbiz.minilang.method.eventops; -import java.util.Map; - -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.collections.FlexibleServletAccessor; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Copies a map field to a Servlet session attribute + * Implements the <field-to-session> element. */ -public class FieldToSession extends MethodOperation { - - public static final String module = FieldToSession.class.getName(); +public final class FieldToSession extends MethodOperation { - ContextAccessor<Object> fieldAcsr; - ContextAccessor<Map<String, ? extends Object>> mapAcsr; - FlexibleServletAccessor<Object> sessionAcsr; + private final FlexibleMapAccessor<Object> fieldFma; + private final FlexibleStringExpander attributeNameFse; public FieldToSession(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported - mapAcsr = new ContextAccessor<Map<String, ? extends Object>>(element.getAttribute("map-name")); - fieldAcsr = new ContextAccessor<Object>(element.getAttribute("field"), element.getAttribute("field-name")); - sessionAcsr = new FlexibleServletAccessor<Object>(element.getAttribute("session-name"), fieldAcsr.toString()); + if (MiniLangValidate.validationOn()) { + MiniLangValidate.attributeNames(simpleMethod, element, "field", "session-name"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "field"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "field"); + MiniLangValidate.noChildElements(simpleMethod, element); + } + this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field")); + String attributeName = element.getAttribute("session-name"); + if (!attributeName.isEmpty()) { + this.attributeNameFse = FlexibleStringExpander.getInstance(attributeName); + } else { + this.attributeNameFse = FlexibleStringExpander.getInstance(this.fieldFma.toString()); + } } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - // only run this if it is in an EVENT context if (methodContext.getMethodType() == MethodContext.EVENT) { - Object fieldVal = null; - if (!mapAcsr.isEmpty()) { - Map<String, ? extends Object> fromMap = mapAcsr.get(methodContext); - if (fromMap == null) { - Debug.logWarning("Map not found with name " + mapAcsr, module); - return true; + Object fieldVal = fieldFma.get(methodContext.getEnvMap()); + if (fieldVal != null) { + String attributeName = attributeNameFse.expandString(methodContext.getEnvMap()); + if (!attributeName.isEmpty()) { + methodContext.getRequest().getSession().setAttribute(attributeName, fieldVal); } - fieldVal = fieldAcsr.get(fromMap, methodContext); - } else { - // no map name, try the env - fieldVal = fieldAcsr.get(methodContext); - } - - if (fieldVal == null) { - Debug.logWarning("Field value not found with name " + fieldAcsr + " in Map with name " + mapAcsr, module); - return true; } - sessionAcsr.put(methodContext.getRequest().getSession(), fieldVal, methodContext.getEnvMap()); } return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - // TODO: add all attributes and other info - return "<field-to-session field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<field-to-session "); + sb.append("field=\"").append(this.fieldFma).append("\" "); + if (!this.attributeNameFse.isEmpty()) { + sb.append("session-name=\"").append(this.attributeNameFse).append("\" "); + } + sb.append("/>"); + return sb.toString(); } + /** + * A factory for the <field-to-session> element. + */ public static final class FieldToSessionFactory implements Factory<FieldToSession> { + @Override public FieldToSession createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new FieldToSession(element, simpleMethod); } + @Override public String getName() { return "field-to-session"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestParametersToList.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestParametersToList.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestParametersToList.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestParametersToList.java Wed Jun 13 18:01:08 2012 @@ -22,74 +22,108 @@ import java.util.List; import javolution.util.FastList; -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.UtilMisc; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangUtil; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Copies a Servlet request parameter values to a list + * Implements the <request-parameters-to-list> element. */ -public class RequestParametersToList extends MethodOperation { +public final class RequestParametersToList extends MethodOperation { - public static final String module = RequestParametersToList.class.getName(); + // This method is needed only during the v1 to v2 transition + private static boolean autoCorrect(Element element) { + // Correct deprecated list-name attribute + String listAttr = element.getAttribute("list-name"); + if (listAttr.length() > 0) { + element.setAttribute("list", listAttr); + element.removeAttribute("list-name"); + return true; + } + return false; + } - ContextAccessor<List<String>> listAcsr; - String requestName; + private final FlexibleMapAccessor<List<String>> listFma; + private final FlexibleStringExpander attributeNameFse; public RequestParametersToList(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - requestName = element.getAttribute("request-name"); - listAcsr = new ContextAccessor<List<String>>(element.getAttribute("list-name"), requestName); + if (MiniLangValidate.validationOn()) { + MiniLangValidate.deprecatedAttribute(simpleMethod, element, "list-name", "replace with \"list\""); + MiniLangValidate.attributeNames(simpleMethod, element, "list", "request-name"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "request-name"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "list"); + MiniLangValidate.noChildElements(simpleMethod, element); + } + boolean elementModified = autoCorrect(element); + if (elementModified && MiniLangUtil.autoCorrectOn()) { + MiniLangUtil.flagDocumentAsCorrected(element); + } + this.attributeNameFse = FlexibleStringExpander.getInstance(element.getAttribute("request-name")); + String attributeName = element.getAttribute("list"); + if (!attributeName.isEmpty()) { + this.listFma = FlexibleMapAccessor.getInstance(attributeName); + } else { + this.listFma = FlexibleMapAccessor.getInstance(attributeNameFse.toString()); + } } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - List<String> listVal = null; - // only run this if it is in an EVENT context if (methodContext.getMethodType() == MethodContext.EVENT) { - String[] parameterValues = methodContext.getRequest().getParameterValues(requestName); - if (parameterValues == null) { - Debug.logWarning("Request parameter values not found with name " + requestName, module); - } else { - listVal = UtilMisc.toListArray(parameterValues); + String attributeName = attributeNameFse.expandString(methodContext.getEnvMap()); + String[] parameterValues = methodContext.getRequest().getParameterValues(attributeName); + if (parameterValues != null) { + List<String> valueList = listFma.get(methodContext.getEnvMap()); + if (valueList == null) { + valueList = FastList.newInstance(); + listFma.put(methodContext.getEnvMap(), valueList); + } + for (int i = 0; i < parameterValues.length; i++) { + valueList.add(parameterValues[i]); + } } } - // if listVal is null, use a empty list; - if (listVal == null) { - listVal = FastList.newInstance(); - } - List<String> toList = listAcsr.get(methodContext); - if (toList == null) { - if (Debug.verboseOn()) - Debug.logVerbose("List not found with name " + listAcsr + ", creating new list", module); - toList = FastList.newInstance(); - listAcsr.put(methodContext, toList); - } - toList.addAll(listVal); return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - return "<request-parameters-to-list request-name=\"" + this.requestName + "\" list-name=\"" + this.listAcsr + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<request-parameters-to-list "); + sb.append("request-name=\"").append(this.attributeNameFse).append("\" "); + if (!this.listFma.isEmpty()) { + sb.append("list=\"").append(this.listFma).append("\" "); + } + sb.append("/>"); + return sb.toString(); } + /** + * A factory for the <request-parameters-to-list> element. + */ public static final class RequestParametersToListFactory implements Factory<RequestParametersToList> { + @Override public RequestParametersToList createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new RequestParametersToList(element, simpleMethod); } + @Override public String getName() { return "request-parameters-to-list"; } Modified: ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestToField.java URL: http://svn.apache.org/viewvc/ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestToField.java?rev=1349976&r1=1349975&r2=1349976&view=diff ============================================================================== --- ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestToField.java (original) +++ ofbiz/branches/jackrabbit20120501/framework/minilang/src/org/ofbiz/minilang/method/eventops/RequestToField.java Wed Jun 13 18:01:08 2012 @@ -18,92 +18,89 @@ *******************************************************************************/ package org.ofbiz.minilang.method.eventops; -import java.util.Map; - -import javolution.util.FastMap; - -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.collections.FlexibleServletAccessor; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.MiniLangValidate; import org.ofbiz.minilang.SimpleMethod; -import org.ofbiz.minilang.method.ContextAccessor; import org.ofbiz.minilang.method.MethodContext; import org.ofbiz.minilang.method.MethodOperation; import org.w3c.dom.Element; /** - * Copies a Servlet request attribute to a map field + * Implements the <request-to-field> element. */ -public class RequestToField extends MethodOperation { - - public static final String module = RequestToField.class.getName(); +public final class RequestToField extends MethodOperation { - String defaultVal; - ContextAccessor<Object> fieldAcsr; - ContextAccessor<Map<String, Object>> mapAcsr; - FlexibleServletAccessor<Object> requestAcsr; + private final FlexibleStringExpander defaultFse; + private final FlexibleMapAccessor<Object> fieldFma; + private final FlexibleStringExpander attributeNameFse; public RequestToField(Element element, SimpleMethod simpleMethod) throws MiniLangException { super(element, simpleMethod); - // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported - mapAcsr = new ContextAccessor<Map<String, Object>>(element.getAttribute("map-name")); - fieldAcsr = new ContextAccessor<Object>(element.getAttribute("field"), element.getAttribute("field-name")); - requestAcsr = new FlexibleServletAccessor<Object>(element.getAttribute("request-name"), fieldAcsr.toString()); - defaultVal = element.getAttribute("default"); + if (MiniLangValidate.validationOn()) { + MiniLangValidate.attributeNames(simpleMethod, element, "field", "request-name", "default"); + MiniLangValidate.requiredAttributes(simpleMethod, element, "field"); + MiniLangValidate.expressionAttributes(simpleMethod, element, "field"); + MiniLangValidate.noChildElements(simpleMethod, element); + } + this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field")); + String attributeName = element.getAttribute("request-name"); + if (!attributeName.isEmpty()) { + this.attributeNameFse = FlexibleStringExpander.getInstance(attributeName); + } else { + this.attributeNameFse = FlexibleStringExpander.getInstance(this.fieldFma.toString()); + } + this.defaultFse = FlexibleStringExpander.getInstance(element.getAttribute("default")); } @Override public boolean exec(MethodContext methodContext) throws MiniLangException { - String defaultVal = methodContext.expandString(this.defaultVal); - Object fieldVal = null; - // only run this if it is in an EVENT context if (methodContext.getMethodType() == MethodContext.EVENT) { - fieldVal = requestAcsr.get(methodContext.getRequest(), methodContext.getEnvMap()); - if (fieldVal == null) { - Debug.logWarning("Request attribute value not found with name " + requestAcsr, module); - } - } - // if fieldVal is null, or is a String and has zero length, use defaultVal - if (fieldVal == null) { - fieldVal = defaultVal; - } else if (fieldVal instanceof String) { - String strVal = (String) fieldVal; - - if (strVal.length() == 0) { - fieldVal = defaultVal; + String attributeName = attributeNameFse.expandString(methodContext.getEnvMap()); + Object value = methodContext.getRequest().getAttribute(attributeName); + if (value == null || (value instanceof String && ((String) value).isEmpty())) { + value = defaultFse.expandString(methodContext.getEnvMap()); } - } - if (!mapAcsr.isEmpty()) { - Map<String, Object> fromMap = mapAcsr.get(methodContext); - if (fromMap == null) { - Debug.logWarning("Map not found with name " + mapAcsr + " creating a new map", module); - fromMap = FastMap.newInstance(); - mapAcsr.put(methodContext, fromMap); - } - fieldAcsr.put(fromMap, fieldVal, methodContext); - } else { - fieldAcsr.put(methodContext, fieldVal); + fieldFma.put(methodContext.getEnvMap(), value); } return true; } @Override public String expandedString(MethodContext methodContext) { - // TODO: something more than a stub/dummy - return this.rawString(); + return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap()); } @Override public String rawString() { - // TODO: add all attributes and other info - return "<request-to-field request-name=\"" + this.requestAcsr + "\" field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>"; + return toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<request-to-field "); + sb.append("field=\"").append(this.fieldFma).append("\" "); + if (!this.attributeNameFse.isEmpty()) { + sb.append("request-name=\"").append(this.attributeNameFse).append("\" "); + } + if (!this.defaultFse.isEmpty()) { + sb.append("default=\"").append(this.defaultFse).append("\" "); + } + sb.append("/>"); + return sb.toString(); } + /** + * A factory for the <request-to-field> element. + */ public static final class RequestToFieldFactory implements Factory<RequestToField> { + @Override public RequestToField createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException { return new RequestToField(element, simpleMethod); } + @Override public String getName() { return "request-to-field"; } |
| Free forum by Nabble | Edit this page |
