001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.services.controller.dbmaint;
066:
067: import com.jcorporate.expresso.core.controller.Block;
068: import com.jcorporate.expresso.core.controller.Controller;
069: import com.jcorporate.expresso.core.controller.ControllerException;
070: import com.jcorporate.expresso.core.controller.ControllerRequest;
071: import com.jcorporate.expresso.core.controller.ControllerResponse;
072: import com.jcorporate.expresso.core.controller.Input;
073: import com.jcorporate.expresso.core.controller.NonHandleableException;
074: import com.jcorporate.expresso.core.controller.Transition;
075: import com.jcorporate.expresso.core.controller.session.PersistentSession;
076: import com.jcorporate.expresso.core.dataobjects.DataObject;
077: import com.jcorporate.expresso.core.dataobjects.DataObjectMetaData;
078: import com.jcorporate.expresso.core.dataobjects.Defineable;
079: import com.jcorporate.expresso.core.dataobjects.Securable;
080: import com.jcorporate.expresso.core.db.DBException;
081: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
082: import com.jcorporate.expresso.core.misc.StringUtil;
083: import com.jcorporate.expresso.core.misc.URLUTF8Encoder;
084: import com.jcorporate.expresso.core.security.User;
085: import com.jcorporate.expresso.services.controller.ui.DefaultAutoElement;
086: import com.jcorporate.expresso.services.dbobj.Setup;
087:
088: import java.util.Iterator;
089: import java.util.StringTokenizer;
090:
091: /**
092: * Provides a standard form for user to update all fields
093: * (except primary key). Extend this class if only updating
094: * one or several but not all fields.
095: *
096: * @author Michael Nash, contributions by Kevin King
097: */
098: public class Update extends GetBase {
099:
100: public Update() {
101: }
102:
103: /**
104: * Constructor
105: *
106: * @param code The name of the state.
107: * @param descrip The friendly name of the state
108: */
109: public Update(String code, String descrip) {
110: super (code, descrip);
111: } /* Update(String, String) */
112:
113: /**
114: * Create an input for one field specified by the field name. This is
115: * sort of a callback function generated by the base class' autoForm function.
116: *
117: * @param oneFieldName The name of the field
118: * @throws DBException If a problem occurs getting field info from the
119: * database object
120: * @throws ControllerException upon other errors
121: * @see com.jcorporate.expresso.services.controller.dbmaint.GetBase
122: */
123: protected void autoField(String oneFieldName) throws DBException,
124: ControllerException {
125: DataObject myDBObj = this .getDataObject();
126: DataObjectMetaData metadata = myDBObj.getMetaData();
127:
128: if (oneFieldName == null) {
129: throw new ControllerException("Field Name must not be null");
130: }
131: if (myDBObj == null) {
132: throw new DBException("Database object must be "
133: + "initialized before calling autoField");
134: }
135:
136: boolean readOnly = false;
137:
138: /* if it's a key field, it's read-only */
139: if (isKeyField(oneFieldName)) {
140: readOnly = true;
141: }
142: /* Virtual fields, never get input... */
143: if (metadata.isVirtual(oneFieldName)) {
144: readOnly = true;
145: }
146: /* If the field is explicitly set to read only, then only offer */
147: /* input to it in search mode */
148: if (metadata.isReadOnly(oneFieldName)) {
149: readOnly = true;
150: }
151: String cachedValue = StringUtil
152: .notNull(getFormCache(oneFieldName));
153:
154: //
155: //Zero out cached value so that rendering of Mapped objects takes place
156: //
157: if (cachedValue != null && cachedValue.length() == 0) {
158: cachedValue = null;
159: }
160: /* Now, if there is a lookup object specified for the field */
161: Input oneField = DefaultAutoElement.getAutoControllerElement()
162: .renderDBObjectField(this .getControllerResponse(),
163: myDBObj, oneFieldName, cachedValue, readOnly);
164:
165: if (oneField == null) {
166: return;
167: }
168:
169: addInput(oneField);
170:
171: /* Now, if there is a lookup object specified for the field */
172:
173: /* add an icon for the user to search this object in a new window */
174: String lookupObjectName = StringUtil.notNull(metadata
175: .getLookupObject(oneFieldName));
176:
177: if (!lookupObjectName.equals("")) {
178: Transition lookup = new Transition();
179: lookup.setName("lookup");
180: lookup.addParam("dbobj", lookupObjectName);
181: lookup.addParam(Controller.STATE_PARAM_KEY, "Search");
182: lookup.setDescription("Look up Values");
183: oneField.addNested(lookup);
184: } /* if there was a lookup object */
185:
186: //
187: //Added by Mike R. to properly support boolean datatypes and checkboxes
188: //
189: if (metadata.getAttribute(oneFieldName, "checkbox") != null) {
190: if (metadata.getType(oneFieldName).equals("boolean")) {
191: Boolean boolValue = myDBObj.getDataField(oneFieldName)
192: .asBoolean();
193: if (boolValue == null) {
194: oneField.setDefaultValue("N");
195: } else {
196: boolean b = boolValue.booleanValue();
197: oneField.setDefaultValue(b ? "Y" : "N");
198: }
199: }
200: }
201:
202: //
203: //If we have a BLOB then the Input will contain an icon to the MimeType
204: //Icon, and we add a Transition to view the blob.
205: //
206: if ("file".equalsIgnoreCase(oneField.getType())
207: && myDBObj.getFieldMetaData(oneFieldName)
208: .isLongObjectType()) {
209:
210: Transition t = new Transition(
211: "view",
212: "View",
213: com.jcorporate.expresso.services.controller.DBMaint.class,
214: "ViewBlob");
215: t.addParam("fieldName", oneFieldName);
216: t
217: .addParam("dbobj", ((Object) myDBObj).getClass()
218: .getName());
219: this .showBlobViewLink(oneFieldName, myDBObj, oneField, this
220: .getController().getClass().getName());
221: }
222: } /* autoField(String) */
223:
224: /**
225: * Perform the actions of this state.
226: *
227: * @param req The <code>ControllerRequest</code> object
228: * @param res The <code>ControllerResponse</code> object
229: */
230: public void run(ControllerRequest req, ControllerResponse res)
231: throws NonHandleableException, ControllerException {
232: super .run(req, res);
233:
234: DataObject myDBObj = this .getDataObject();
235: DataObjectMetaData metadata = myDBObj.getMetaData();
236:
237: String allKeys = URLUTF8Encoder.decode(StringUtil
238: .notNull(getParameter("key")));
239:
240: if (allKeys.equals("")) {
241: throw new ControllerException(
242: "Update command requires key value string to follow it");
243: }
244: try {
245:
246: myDBObj = this .retrieveMyDBObject();
247:
248: showNext = false;
249: showPrev = false;
250: if (myDBObj instanceof Securable) {
251: ((Securable) myDBObj).isAllowed("U");
252: } else {
253: if (getUid() == SecuredDBObject.SYSTEM_ACCOUNT
254: || User.getUserFromId(
255: getUid(),
256: this .getControllerRequest()
257: .getDataContext()).isAdmin()) {
258: // all access ok
259: } else {
260: String allowInsecure = Setup
261: .getValue(
262: req.getDataContext(),
263: com.jcorporate.expresso.core.ExpressoSchema.class
264: .getName(),
265: "insecureDBMaint");
266: if (!(StringUtil.toBoolean(allowInsecure))) {
267: throw new SecurityException(
268: "Access to unsecured Objects not allowed");
269: }
270: }
271: }
272: showForm();
273:
274: String keyParam = this .getKeyParameter(getDataObject());
275:
276: Transition update = new Transition("UpdateUpdate",
277: getController());
278: addParams(update);
279: update.addParam("key", keyParam);
280: add(update);
281:
282: Transition delete = new Transition("UpdateDelete",
283: getController());
284: addParams(delete);
285: delete.addParam("key", keyParam);
286: add(delete);
287:
288: if (!StringUtil.notNull(getParameter("details"))
289: .equals("y")) {
290:
291: /* If we are not already the detail record of some other parent... */
292: /* Now add a special block called "details". It contains */
293: /* a transition for each of the detail db objects to our */
294: /* current object */
295: Block detBlock = new Block("details");
296:
297: try {
298: Transition masterTrans = new Transition("Update",
299: getController());
300: String className = ((Object) myDBObj).getClass()
301: .getName();
302: masterTrans.setName("master");
303: detBlock.add(masterTrans);
304: masterTrans.setLabel(metadata.getDescription(req
305: .getLocale()));
306: masterTrans.setAttribute("dbobj", className);
307: masterTrans.addParam("dbobj", className);
308: masterTrans.addParam(Controller.STATE_PARAM_KEY,
309: "Update");
310: masterTrans.addParam("key", URLUTF8Encoder
311: .encode(keyParam));
312: masterTrans.addParam("fields", URLUTF8Encoder
313: .encode(getFieldsParam()));
314: masterTrans.addParam("search", URLUTF8Encoder
315: .encode(getSearchParam()));
316:
317: if (myDBObj instanceof com.jcorporate.expresso.core.dataobjects.Defineable) {
318: masterTrans.addParam("definition",
319: ((Defineable) myDBObj)
320: .getDefinitionName());
321: }
322:
323: String oneDet = null;
324:
325: for (Iterator ee = metadata.getDetailSet()
326: .iterator(); ee.hasNext();) {
327: oneDet = (String) ee.next();
328:
329: DataObject detDBObj = null;
330:
331: try {
332: detDBObj = (DataObject) Class.forName(
333: oneDet).newInstance();
334: detDBObj.setLocale(getControllerRequest()
335: .getLocale());
336: } catch (Exception e) {
337: throw new ControllerException(
338: "Unable to instantiate "
339: + "detail db object '"
340: + oneDet + "'", e);
341: }
342:
343: Transition oneTrans = new Transition(
344: "SearchList", getController());
345: detBlock.add(oneTrans);
346: oneTrans.setLabel(detDBObj.getMetaData()
347: .getDescription(req.getLocale()));
348: oneTrans.setAttribute("dbobj",
349: ((Object) detDBObj).getClass()
350: .getName());
351: oneTrans.addParam("dbobj", oneDet);
352: oneTrans.addParam(Controller.STATE_PARAM_KEY,
353: "SearchList");
354: oneTrans.addParam("details", "y");
355:
356: StringBuffer fieldsString = new StringBuffer();
357: String localFields = metadata
358: .getDetailFieldsLocal(oneDet);
359: String foreignFields = metadata
360: .getDetailFieldsForeign(oneDet);
361: StringTokenizer stkLocal = new StringTokenizer(
362: localFields, "|");
363: StringTokenizer stkForeign = new StringTokenizer(
364: foreignFields, "|");
365: boolean needsPipe = false;
366:
367: while (stkLocal.hasMoreTokens()) {
368: if (needsPipe) {
369: fieldsString.append("|");
370: } else {
371: needsPipe = true;
372: }
373:
374: String localField = stkLocal.nextToken();
375: String foreignField = stkForeign
376: .nextToken();
377: fieldsString.append(foreignField);
378: fieldsString.append("|");
379: fieldsString.append(myDBObj.getDataField(
380: localField).asString());
381: }
382:
383: oneTrans.addParam("search", fieldsString
384: .toString());
385: oneTrans.addParam("fields", fieldsString
386: .toString());
387: } /* for each detail record */
388:
389: } catch (DBException de) {
390: throw new ControllerException(de);
391: }
392: if (detBlock.getNumContents() > 1) {
393: add(detBlock);
394:
395: PersistentSession mySession = getSession();
396: mySession.setPersistentAttribute(masterObjKey,
397: detBlock);
398: }
399: }
400: } catch (DBException de) {
401: throw new ControllerException(de);
402: }
403: } /* run(ControllerRequest, ControllerResponse) */
404:
405: }
406:
407: /* Update */
|