001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * @created Oct 15, 2005
014: * @author dmoran
015: */
016:
017: package org.pentaho.plugin.core;
018:
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.dom4j.Node;
026: import org.pentaho.core.runtime.IActionParameter;
027: import org.pentaho.core.runtime.SelectionMapper;
028: import org.pentaho.core.solution.IOutputHandler;
029: import org.pentaho.core.util.XmlHelper;
030: import org.pentaho.messages.Messages;
031: import org.pentaho.plugin.ComponentBase;
032:
033: /**
034: * The secure filter component has two separate but related functions. It allows
035: * you to customize the default prompting done by the runtime context and can
036: * verify that only valid selections are returned.
037: */
038: public class SecureFilterComponent extends ComponentBase {
039:
040: private static final long serialVersionUID = 7119516440509549539L;
041:
042: List selList = new ArrayList(); // list of valid selections
043:
044: List hiddenList = new ArrayList(); // List of hidden fields that will be
045:
046: // added if any prompting happens.
047:
048: public Log getLogger() {
049: return LogFactory.getLog(SecureFilterComponent.class);
050: }
051:
052: protected boolean validateSystemSettings() {
053: // No System Settings to validate
054: return true;
055: }
056:
057: public boolean validateAction() {
058: Node compDef = getComponentDefinition();
059: List selNodes = compDef.selectNodes("selections/*"); //$NON-NLS-1$
060:
061: String inputName = null;
062: boolean isOk = true;
063:
064: for (Iterator it = selNodes.iterator(); it.hasNext();) {
065: Node node = (Node) it.next();
066: try {
067: inputName = node.getName(); // Get the Data Node
068: IActionParameter inputParam = getInputParameter(inputName);
069: String filterType = XmlHelper.getNodeText(
070: "@filter", node, null); //$NON-NLS-1$
071:
072: // BISERVER-149 Changed isOptional param to default to false in order to
073: // enable prompting when no default value AND no selection list is given...
074: // This is also the default that Design Studio presumes.
075:
076: String optionalParm = XmlHelper.getNodeText(
077: "@optional", node, "false"); //$NON-NLS-1$ //$NON-NLS-2$
078: boolean isOptional = "true".equals(optionalParm); //$NON-NLS-1$
079:
080: if ("none".equalsIgnoreCase(filterType)) { //$NON-NLS-1$
081: IActionParameter selectParam = getInputParameter(inputName);
082: String title = XmlHelper.getNodeText(
083: "title", node, inputName); //$NON-NLS-1$
084: String valueCol = ""; //$NON-NLS-1$
085: String dispCol = ""; //$NON-NLS-1$
086: String displayStyle = XmlHelper.getNodeText(
087: "@style", node, null); //$NON-NLS-1$
088: boolean promptOne = "true".equalsIgnoreCase(XmlHelper.getNodeText("@prompt-if-one-value", node, "false")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
089: if ("hidden".equals(displayStyle)) { //$NON-NLS-1$
090: hiddenList.add(new SelEntry(inputParam,
091: selectParam, valueCol, dispCol, title,
092: displayStyle, promptOne, isOptional));
093: } else {
094: selList.add(new SelEntry(inputParam,
095: selectParam, valueCol, dispCol, title,
096: displayStyle, promptOne, isOptional));
097: }
098: } else {
099: Node filterNode = node.selectSingleNode("filter"); //$NON-NLS-1$
100: IActionParameter selectParam = getInputParameter(filterNode
101: .getText().trim());
102:
103: String valueCol = XmlHelper.getNodeText(
104: "@value-col-name", filterNode, null); //$NON-NLS-1$
105: String dispCol = XmlHelper.getNodeText(
106: "@display-col-name", filterNode, null); //$NON-NLS-1$
107:
108: String title = XmlHelper.getNodeText(
109: "title", node, null); //$NON-NLS-1$
110: String displayStyle = XmlHelper.getNodeText(
111: "@style", node, null); //$NON-NLS-1$
112: boolean promptOne = "true".equalsIgnoreCase(XmlHelper.getNodeText("@prompt-if-one-value", node, "false")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
113:
114: selList.add(new SelEntry(inputParam, selectParam,
115: valueCol, dispCol, title, displayStyle,
116: promptOne, isOptional));
117: }
118:
119: } catch (Exception e) { // Catch the exception to let us test all
120: // the params
121: isOk = false;
122: error(Messages
123: .getErrorString(
124: "SecureFilterComponent.ERROR_0001_PARAM_MISSING", inputName)); //$NON-NLS-1$
125: }
126: }
127:
128: return (isOk);
129: }
130:
131: public boolean executeAction() {
132:
133: boolean parameterUINeeded = false;
134: if (getOutputPreference() == IOutputHandler.OUTPUT_TYPE_PARAMETERS) {
135: parameterUINeeded = true;
136: }
137:
138: boolean stopHere = getInputBooleanValue(
139: StandardSettings.HANDLE_ALL_PROMPTS, true);
140:
141: SelEntry entry;
142: boolean isOk = true;
143: boolean causingPrompting = false; // Set to true if this securefilter
144: // component actually adds feeback parameters.
145: for (Iterator it = selList.iterator(); it.hasNext();) {
146: entry = (SelEntry) it.next();
147:
148: SelectionMapper selMap = SelectionMapper.create(
149: entry.selectionParam, entry.valueCol,
150: entry.dispCol, entry.title, entry.displayStyle);
151:
152: // If we have a value for the input param, verify that it is within the selections
153: if (entry.inputParam.hasValue() && !parameterUINeeded) {
154: // TODO support numeric values here
155: Object value = entry.inputParam.getValue();
156: if (value instanceof String) {
157: if (selMap != null
158: && !selMap.hasValue((String) value)) {
159: if (!entry.isOptional || !"".equals(value)) { //$NON-NLS-1$
160: error(Messages
161: .getErrorString(
162: "SecureFilterComponent.ERROR_0001_INVALID_SELECTION", entry.inputParam.getValue().toString(), entry.inputParam.getName())); //$NON-NLS-1$
163: isOk = false;
164: }
165: } // else this should be ok, we are just checking for selMap's existance
166: } else if (value instanceof Object[]) {
167: // test each item
168: if (selMap != null) {
169: Object values[] = (Object[]) value;
170: for (int i = 0; i < values.length; i++) {
171: if (!selMap.hasValue(values[i].toString())) {
172: if (!entry.isOptional
173: || !"".equals(value)) { //$NON-NLS-1$
174: error(Messages
175: .getErrorString(
176: "SecureFilterComponent.ERROR_0001_INVALID_SELECTION", entry.inputParam.getValue().toString(), entry.inputParam.getName())); //$NON-NLS-1$
177: isOk = false;
178: }
179: }
180: }
181: } // else this should be ok, we are just checking for selMap's existence
182: } else {
183: // we cannot validate this
184: error(Messages
185: .getErrorString(
186: "SecureFilterComponent.ERROR_0001_INVALID_SELECTION", entry.inputParam.getValue().toString(), entry.inputParam.getName())); //$NON-NLS-1$
187: isOk = false;
188: }
189: } else { // Need to prompt
190: if (selMap == null) {
191: entry.createFeedbackParam = true;
192: if (!entry.isOptional) {
193: causingPrompting = true; // trigger feedback below
194: }
195: } else if (!entry.promptOne
196: && (selMap.selectionCount() == 1)) {
197: entry.inputParam.setValue(selMap.getValueAt(0));
198: } else if (!feedbackAllowed()) {
199: isOk = false;
200: } else {
201: entry.createFeedbackParam = true;
202: entry.selMap = selMap;
203: if (!entry.isOptional) {
204: causingPrompting = true; // trigger feedback below
205: }
206: }
207: }
208: } // Done with the regular selections
209:
210: if (causingPrompting) {
211:
212: // Only make the call to createFeedbackParameter if causingPrompting is true.
213: for (Iterator it = selList.iterator(); it.hasNext();) {
214: entry = (SelEntry) it.next();
215: if (entry.createFeedbackParam) {
216: if (entry.selMap != null) {
217: createFeedbackParameter(entry.selMap,
218: entry.inputParam.getName(),
219: entry.inputParam.getValue(),
220: entry.isOptional);
221: } else {
222: // TODO support help/hints
223: createFeedbackParameter(
224: entry.inputParam.getName(),
225: entry.title,
226: "", entry.inputParam.getValue().toString(), true, entry.isOptional); //$NON-NLS-1$
227: }
228: entry.inputParam
229: .setPromptStatus(IActionParameter.PROMPT_PENDING);
230: }
231: }
232:
233: promptNeeded();
234: if (stopHere) {
235: promptNow();
236: }
237:
238: // We want the hidden fields to be processed after everything else is processed because
239: // we only want to add the hidden fields if this component has caused prompting to occur.
240: for (int i = 0; i < hiddenList.size(); i++) {
241: entry = (SelEntry) hiddenList.get(i);
242: Object value = entry.inputParam.getValue();
243: if (value instanceof String) {
244: createFeedbackParameter(entry.inputParam.getName(),
245: entry.inputParam.getName(),
246: "", (String) value, false); //$NON-NLS-1$
247: } else {
248: // Support other types of hidden field parameters (like
249: // Integer/Decimal/Etc.) by using toString.
250: createFeedbackParameter(entry.inputParam.getName(),
251: entry.inputParam.getName(),
252: "", value.toString(), false); //$NON-NLS-1$
253: }
254: }
255: }
256: return isOk;
257: }
258:
259: /*
260: * (non-Javadoc)
261: *
262: * @see org.pentaho.component.ComponentBase#done()
263: */
264: public void done() {
265: }
266:
267: /*
268: * (non-Javadoc)
269: *
270: * @see org.pentaho.component.ComponentBase#init()
271: */
272: public boolean init() {
273: return true;
274: }
275:
276: class SelEntry {
277: IActionParameter inputParam;
278:
279: IActionParameter selectionParam;
280:
281: String valueCol, dispCol, title, displayStyle;
282:
283: boolean promptOne;
284:
285: SelectionMapper selMap;
286:
287: boolean isOptional;
288:
289: boolean createFeedbackParam = false;
290:
291: SelEntry(IActionParameter inputParam,
292: IActionParameter selectionParam, String valueCol,
293: String dispCol, String title, String displayStyle,
294: boolean promptOne, boolean optional) {
295: this.inputParam = inputParam;
296: this.selectionParam = selectionParam;
297: this.valueCol = valueCol;
298: this.dispCol = dispCol;
299: this.title = title;
300: this.displayStyle = displayStyle;
301: this.promptOne = promptOne;
302: this.isOptional = optional;
303: }
304:
305: }
306:
307: }
|