001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: package org.jaffa.components.maint;
051:
052: import java.io.FileNotFoundException;
053: import java.io.InputStream;
054: import java.net.MalformedURLException;
055: import java.net.URL;
056: import java.util.*;
057: import org.apache.log4j.Logger;
058: import org.jaffa.presentation.portlet.component.Component;
059: import org.jaffa.components.dto.HeaderDto;
060: import org.jaffa.exceptions.ApplicationExceptions;
061: import org.jaffa.exceptions.DomainObjectChangedException;
062: import org.jaffa.exceptions.FrameworkException;
063: import org.jaffa.presentation.portlet.FormKey;
064: import org.jaffa.security.VariationContext;
065: import org.jaffa.util.BeanHelper;
066: import org.jaffa.util.URLHelper;
067:
068: /** This is the base class for all Maintenance components created by using the object_maintenance_2_0 pattern.
069: * It has the following properties -
070: * 1- mode : Indicates if the component is in Create, Update or Delete mode.
071: * 2- refreshData : Indicates if the data needs to be refreshed. This happens when the data is modified by another user.
072: * 3- currentScreenCounter : A maintenance component may consist of more than one screen. This counter is used to identify the current screen being displayed. It will start with count=0
073: *
074: * A Maintenance class will have to provide an implementation for the doPrevalidateCreate(), doCreate(), doPrevalidateUpdate(), doUpdate(), doDelete(), doRetrieve(), addScreens() methods.
075: * @author GautamJ
076: */
077: public abstract class MaintComponent2 extends Component implements
078: IMaintComponent {
079:
080: private static final Logger log = Logger
081: .getLogger(MaintComponent2.class);
082:
083: private static final String PROPERTIES_FILE_NAME = "ComponentDefaultValues.properties";
084: private static final String PACKAGE_SUFFIX_TO_REMOVE = "/ui";
085: private static final String APPEND_TO_PACKAGE = '/' + PROPERTIES_FILE_NAME;
086:
087: private int m_mode;
088: private boolean m_refreshData;
089: private List m_screens;
090: private int m_currentScreenCounter = 0;
091: private Collection m_displayOnlyFields;
092:
093: private Collection m_createListeners;
094: private Collection m_updateListeners;
095: private Collection m_deleteListeners;
096: private HeaderDto m_headerDto = null;
097:
098: // **************************************************************
099: // Component Properties
100: // **************************************************************
101:
102: /** Getter for property mode.
103: * @return Value of property mode.
104: */
105: public int getMode() {
106: return m_mode;
107: }
108:
109: /** Setter for property mode.
110: * @param mode New value of property mode.
111: */
112: public void setMode(int mode) {
113: m_mode = mode;
114: }
115:
116: /** Returns true if this is create mode.
117: * @return true if this is create mode.
118: */
119: public boolean isCreateMode() {
120: return getMode() == MODE_CREATE;
121: }
122:
123: /** Returns true if this is update mode.
124: * @return true if this is update mode.
125: */
126: public boolean isUpdateMode() {
127: return getMode() == MODE_UPDATE;
128: }
129:
130: /** Returns true if this is delete mode.
131: * @return true if this is delete mode.
132: */
133: public boolean isDeleteMode() {
134: return getMode() == MODE_DELETE;
135: }
136:
137: /** Getter for property refreshData.
138: * @return Value of property refreshData.
139: */
140: public boolean isRefreshData() {
141: return m_refreshData;
142: }
143:
144: /** Setter for property refreshData.
145: * @param refreshData New value of property refreshData.
146: */
147: protected void setRefreshData(boolean refreshData) {
148: m_refreshData = refreshData;
149: }
150:
151: /** Getter for property currentScreenCounter.
152: * @return Value of property currentScreenCounter.
153: */
154: public int getCurrentScreenCounter() {
155: return m_currentScreenCounter;
156: }
157:
158: /** Setter for property currentScreenCounter.
159: * @param currentScreenCounter New value of property currentScreenCounter.
160: */
161: public void setCurrentScreenCounter(int currentScreenCounter) {
162: m_currentScreenCounter = currentScreenCounter;
163: }
164:
165: /** Getter for the Screens.
166: * @return the screens.
167: */
168: public MaintComponent2.Screen[] getScreens() {
169: return (MaintComponent2.Screen[]) m_screens
170: .toArray(new MaintComponent2.Screen[0]);
171: }
172:
173: /** Getter for the current Screen.
174: * @return the current screen.
175: */
176: public MaintComponent2.Screen determineCurrentScreen() {
177: return (MaintComponent2.Screen) m_screens
178: .get(m_currentScreenCounter);
179: }
180:
181: /** Getter for the next Screen.
182: * This takes into account the mode and if the following screen is available in create or update modes.
183: * A null will be returned in case no appropriate next screen is available.
184: * @return the next screen.
185: */
186: public MaintComponent2.Screen determineNextScreen() {
187: return determineAndSetNextScreen(false);
188: }
189:
190: /** This sets the currentScreenCounter to point to the next screen.
191: * This takes into account the mode and if the following screen is available in create or update modes.
192: * A null will be returned in case no appropriate next screen is available.
193: * @return the next screen.
194: */
195: public MaintComponent2.Screen determineAndSetNextScreen() {
196: return determineAndSetNextScreen(true);
197: }
198:
199: private MaintComponent2.Screen determineAndSetNextScreen(
200: boolean setCurrentScreenCounter) {
201: MaintComponent2.Screen screen = null;
202: for (int i = m_currentScreenCounter + 1; i < m_screens.size(); i++) {
203: screen = (MaintComponent2.Screen) m_screens.get(i);
204: if (isCreateMode()
205: && screen.isAvailableInCreateMode()
206: || (isUpdateMode() && screen
207: .isAvailableInUpdateMode())) {
208: if (setCurrentScreenCounter)
209: m_currentScreenCounter = i;
210: break;
211: } else
212: screen = null;
213: }
214: return screen;
215: }
216:
217: /** Getter for the previous Screen.
218: * This takes into account the mode and if the previous screen is available in create or update modes.
219: * A null will be returned in case no appropriate previous screen is available.
220: * @return the previous screen.
221: */
222: public MaintComponent2.Screen determinePreviousScreen() {
223: return determineAndSetPreviousScreen(false);
224: }
225:
226: /** This sets the currentScreenCounter to point to the previous screen.
227: * This takes into account the mode and if the previous screen is available in create or update modes.
228: * A null will be returned in case no appropriate previous screen is available.
229: * @return the previous screen.
230: */
231: public MaintComponent2.Screen determineAndSetPreviousScreen() {
232: return determineAndSetPreviousScreen(true);
233: }
234:
235: private MaintComponent2.Screen determineAndSetPreviousScreen(
236: boolean setCurrentScreenCounter) {
237: MaintComponent2.Screen screen = null;
238: for (int i = m_currentScreenCounter - 1; i >= 0; i--) {
239: screen = (MaintComponent2.Screen) m_screens.get(i);
240: if (isCreateMode()
241: && screen.isAvailableInCreateMode()
242: || (isUpdateMode() && screen
243: .isAvailableInUpdateMode())) {
244: if (setCurrentScreenCounter)
245: m_currentScreenCounter = i;
246: break;
247: } else
248: screen = null;
249: }
250: return screen;
251: }
252:
253: /** Getter for the current screen's FormKey.
254: * @return the FormKey for the current screen.
255: */
256: public FormKey determineFormKey() {
257: return new FormKey(determineCurrentScreen().getFormName(),
258: getComponentId());
259: }
260:
261: /** This will mark a field as 'DisplayOnly'.
262: * @param fieldName The field to be marked as 'DisplayOnly'.
263: */
264: public void addDisplayOnlyField(String fieldName) {
265: if (m_displayOnlyFields == null)
266: m_displayOnlyFields = new HashSet();
267: m_displayOnlyFields.add(fieldName);
268: }
269:
270: /** Returns a true if a field has been marked as 'DisplayOnly'.
271: * @param fieldName The field to be checked.
272: * @return a true if a field has been marked as 'DisplayOnly'
273: */
274: public boolean isDisplayOnlyField(String fieldName) {
275: return m_displayOnlyFields != null ? m_displayOnlyFields
276: .contains(fieldName) : false;
277: }
278:
279: // **************************************************************
280: // Additional methods
281: // **************************************************************
282:
283: /** Adds a listener.
284: * @param listener the listener.
285: */
286: public void addCreateListener(ICreateListener listener) {
287: if (m_createListeners == null)
288: m_createListeners = new HashSet();
289: m_createListeners.add(listener);
290: }
291:
292: /** Removes a listener.
293: * @param listener the listener.
294: * @return true if the listener was removed.
295: */
296: public boolean removeCreateListener(ICreateListener listener) {
297: if (m_createListeners != null)
298: return m_createListeners.remove(listener);
299: else
300: return false;
301: }
302:
303: /** Adds a listener.
304: * @param listener the listener.
305: */
306: public void addUpdateListener(IUpdateListener listener) {
307: if (m_updateListeners == null)
308: m_updateListeners = new HashSet();
309: m_updateListeners.add(listener);
310: }
311:
312: /** Removes a listener.
313: * @param listener the listener.
314: * @return true if the listener was removed.
315: */
316: public boolean removeUpdateListener(IUpdateListener listener) {
317: if (m_updateListeners != null)
318: return m_updateListeners.remove(listener);
319: else
320: return false;
321: }
322:
323: /** Adds a listener.
324: * @param listener the listener.
325: */
326: public void addDeleteListener(IDeleteListener listener) {
327: if (m_deleteListeners == null)
328: m_deleteListeners = new HashSet();
329: m_deleteListeners.add(listener);
330: }
331:
332: /** Removes a listener.
333: * @param listener the listener.
334: * @return true if the listener was removed.
335: */
336: public boolean removeDeleteListener(IDeleteListener listener) {
337: if (m_deleteListeners != null)
338: return m_deleteListeners.remove(listener);
339: else
340: return false;
341: }
342:
343: /** Based on the mode and input parameters, this will either delete the domain object, or initialize the screen for updates, or bring up a blank screen.
344: * @throws ApplicationExceptions Indicates some functional error.
345: * @throws FrameworkException Indicates some system error.
346: * @return The FormKey.
347: */
348: public FormKey display() throws ApplicationExceptions,
349: FrameworkException {
350: if (m_screens == null) {
351: m_screens = new ArrayList();
352: addScreens(m_screens);
353:
354: // move to next screen, if the current screen is unavailable in current-mode
355: MaintComponent2.Screen screen = determineCurrentScreen();
356: if (isCreateMode()
357: && !screen.isAvailableInCreateMode()
358: || (isUpdateMode() && !screen
359: .isAvailableInUpdateMode()))
360: determineAndSetNextScreen();
361: }
362:
363: if (isDeleteMode()) {
364: delete(false);
365: } else if (isUpdateMode()) {
366: initDropDownCodes();
367: retrieve();
368: } else {
369: initDropDownCodes();
370: initializeData();
371: }
372: if (isDeleteMode())
373: return quitAndReturnToCallingScreen();
374: else
375: return determineFormKey();
376: }
377:
378: /** This clears the internal collection of listeners.
379: * It then invokes the quit() method of the base class.
380: */
381: public void quit() {
382: if (m_createListeners != null) {
383: m_createListeners.clear();
384: m_createListeners = null;
385: }
386: if (m_updateListeners != null) {
387: m_updateListeners.clear();
388: m_updateListeners = null;
389: }
390: if (m_deleteListeners != null) {
391: m_deleteListeners.clear();
392: m_deleteListeners = null;
393: }
394: super .quit();
395: }
396:
397: /** This will invoke the doPrevalidateCreate() method to perform prevalidations before creating a domain object.
398: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
399: * @throws FrameworkException Indicates some system error.
400: */
401: public void prevalidateCreate() throws ApplicationExceptions,
402: FrameworkException {
403: doPrevalidateCreate();
404: }
405:
406: /** This will invoke the doCreate() method to create a new domain object. It will then invoke all the Create Listeners.
407: * @throws ApplicationExceptions Indicates some functional error.
408: * @throws FrameworkException Indicates some system error.
409: */
410: public void create() throws ApplicationExceptions,
411: FrameworkException {
412: doCreate();
413: invokeCreateListeners();
414: }
415:
416: /** This will invoke the doPrevalidateUpdate() method to perform prevalidations before updating a domain object.
417: * @param performDirtyReadCheck this will determine if the Dirty Read check if to be performed prior to an update.
418: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
419: * @throws FrameworkException Indicates some system error.
420: */
421: public void prevalidateUpdate(boolean performDirtyReadCheck)
422: throws ApplicationExceptions, FrameworkException {
423: try {
424: doPrevalidateUpdate(performDirtyReadCheck);
425: } catch (ApplicationExceptions e) {
426: // check for the DomainObjectChangedException and then rethrow the ApplicationExceptions
427: for (Iterator i = e.iterator(); i.hasNext();) {
428: if (i.next() instanceof DomainObjectChangedException) {
429: if (log.isDebugEnabled())
430: log
431: .debug("DomainObjectChangedException has been thrown during the update. The JSP should now show the Refresh button instead of the Save/Delete/Finish buttons");
432: setRefreshData(true);
433: break;
434: }
435: }
436: throw e;
437: }
438: }
439:
440: /** This will invoke the doUpdate() method to update the domain object. It will then invoke all the Update Listeners.
441: * @param performDirtyReadCheck this will determine if the Dirty Read check if to be performed prior to an update.
442: * @throws ApplicationExceptions Indicates some functional error.
443: * @throws FrameworkException Indicates some system error.
444: */
445: public void update(boolean performDirtyReadCheck)
446: throws ApplicationExceptions, FrameworkException {
447: try {
448: doUpdate(performDirtyReadCheck);
449: } catch (ApplicationExceptions e) {
450: // check for the DomainObjectChangedException and then rethrow the ApplicationExceptions
451: for (Iterator i = e.iterator(); i.hasNext();) {
452: if (i.next() instanceof DomainObjectChangedException) {
453: if (log.isDebugEnabled())
454: log
455: .debug("DomainObjectChangedException has been thrown during the update. The JSP should now show the Refresh button instead of the Save/Delete/Finish buttons");
456: setRefreshData(true);
457: break;
458: }
459: }
460: throw e;
461: }
462: invokeUpdateListeners();
463: }
464:
465: /** This will invoke the doDelete() method to delete the domain object. It will then invoke all the Delete Listeners.
466: * @param performDirtyReadCheck this will determine if the Dirty Read check if to be performed prior to a delete.
467: * @throws ApplicationExceptions Indicates some functional error.
468: * @throws FrameworkException Indicates some system error.
469: */
470: public void delete(boolean performDirtyReadCheck)
471: throws ApplicationExceptions, FrameworkException {
472: try {
473: doDelete(performDirtyReadCheck);
474: } catch (ApplicationExceptions e) {
475: // check for the DomainObjectChangedException and then rethrow the ApplicationExceptions
476: for (Iterator i = e.iterator(); i.hasNext();) {
477: if (i.next() instanceof DomainObjectChangedException) {
478: if (log.isDebugEnabled())
479: log
480: .debug("DomainObjectChangedException has been thrown during the delete. The JSP should now show the Refresh button instead of the Save/Delete/Finish buttons");
481: setRefreshData(true);
482: break;
483: }
484: }
485: throw e;
486: }
487: invokeDeleteListeners();
488: }
489:
490: /** This will invoke the doRetrieve() method to retrieve the domain object.
491: * @throws ApplicationExceptions Indicates some functional error.
492: * @throws FrameworkException Indicates some system error.
493: */
494: public void retrieve() throws ApplicationExceptions,
495: FrameworkException {
496: doRetrieve();
497: }
498:
499: /** Returns a Collection of ICreateListener objects.
500: * @return a Collection of ICreateListener objects.
501: */
502: protected Collection getCreateListeners() {
503: return m_createListeners;
504: }
505:
506: /** Returns a Collection of IUpdateListener objects.
507: * @return a Collection of IUpdateListener objects.
508: */
509: protected Collection getUpdateListeners() {
510: return m_updateListeners;
511: }
512:
513: /** Returns a Collection of IDeleteListener objects.
514: * @return a Collection of IDeleteListener objects.
515: */
516: protected Collection getDeleteListeners() {
517: return m_deleteListeners;
518: }
519:
520: /** Invokes the createDone() method of the registered ICreateListener objects in the same thread.
521: */
522: protected void invokeCreateListeners() {
523: invokeCreateListeners(null);
524: }
525:
526: /** Invokes the createDone() method of the registered ICreateListener objects in the same thread.
527: * @param eventObject The EventObject which will probably contain the component itself.
528: */
529: protected void invokeCreateListeners(EventObject eventObject) {
530: if (m_createListeners != null) {
531: if (eventObject == null)
532: eventObject = new EventObject(this );
533:
534: for (Iterator i = m_createListeners.iterator(); i.hasNext();)
535: ((ICreateListener) i.next()).createDone(eventObject);
536: }
537: }
538:
539: /** Invokes the updateDone() method of the registered IUpdateListener objects in the same thread.
540: */
541: protected void invokeUpdateListeners() {
542: invokeUpdateListeners(null);
543: }
544:
545: /** Invokes the updateDone() method of the registered IUpdateListener objects in the same thread.
546: * @param eventObject The EventObject which will probably contain the component itself.
547: */
548: protected void invokeUpdateListeners(EventObject eventObject) {
549: if (m_updateListeners != null) {
550: if (eventObject == null)
551: eventObject = new EventObject(this );
552:
553: for (Iterator i = m_updateListeners.iterator(); i.hasNext();)
554: ((IUpdateListener) i.next()).updateDone(eventObject);
555: }
556: }
557:
558: /** Invokes the deleteDone() method of the registered IDeleteListener objects in the same thread.
559: */
560: protected void invokeDeleteListeners() {
561: invokeDeleteListeners(null);
562: }
563:
564: /** Invokes the deleteDone() method of the registered IDeleteListener objects in the same thread.
565: * @param eventObject The EventObject which will probably contain the component itself.
566: */
567: protected void invokeDeleteListeners(EventObject eventObject) {
568: if (m_deleteListeners != null) {
569: if (eventObject == null)
570: eventObject = new EventObject(this );
571:
572: for (Iterator i = m_deleteListeners.iterator(); i.hasNext();)
573: ((IDeleteListener) i.next()).deleteDone(eventObject);
574: }
575: }
576:
577: /** Clears the WidgetCache, removing all the WidgetModels. It also resets the flags.
578: */
579: protected void uncacheWidgetModels() {
580: getUserSession().getWidgetCache(getComponentId()).clear();
581: setRefreshData(false);
582: }
583:
584: /** Returns the HeaderDto. This can be used for passing the header info to the Tx, where required.
585: * @return the HeaderDto.
586: */
587: protected HeaderDto getHeaderDto() {
588: if (m_headerDto == null) {
589: m_headerDto = new HeaderDto();
590: m_headerDto.setUserId(getUserSession().getUserId());
591: m_headerDto.setVariation(VariationContext.getVariation());
592: }
593: return m_headerDto;
594: }
595:
596: /** This method is invoked by the display() method when the component is run in the CREATE_MODE.
597: * It sets the default values in the component by reading them from the ComponentDefaultValues.properties file.
598: * This file should be in the base package of the component.
599: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
600: * @throws FrameworkException Indicates some system error.
601: */
602: protected void initializeData() throws ApplicationExceptions,
603: FrameworkException {
604: // NOTE: This can be enhanced to load the default values for a base component too !!
605:
606: InputStream inStream = null;
607: try {
608: // Load the file containing the default values for the component
609: try {
610: URL defaultValuesUrl = determineDefaultValuesUrl(getClass());
611: inStream = defaultValuesUrl.openStream();
612: } catch (Exception e) {
613: if (log.isDebugEnabled())
614: log
615: .debug("File to load the default component values was not found");
616: return;
617: }
618: Properties defaultValues = new Properties();
619: defaultValues.load(inStream);
620:
621: // Iterate through the properties and set the value on this component
622: if (defaultValues.isEmpty()) {
623: if (log.isDebugEnabled())
624: log.debug("No default component values found");
625: } else {
626: for (Iterator i = defaultValues.entrySet().iterator(); i
627: .hasNext();) {
628: Map.Entry defaultValueEntry = (Map.Entry) i.next();
629: String fieldName = (String) defaultValueEntry
630: .getKey();
631: String defaultValue = (String) defaultValueEntry
632: .getValue();
633: BeanHelper.setField(this , fieldName, defaultValue);
634: if (log.isDebugEnabled())
635: log.debug("Initialized " + fieldName + " to "
636: + defaultValue);
637: }
638: }
639: } catch (Exception e) {
640: log.warn("Error in initializing data on the component", e);
641: } finally {
642: try {
643: if (inStream != null)
644: inStream.close();
645: } catch (Exception e) {
646: log.warn("Error in initializing data on the component",
647: e);
648: }
649: }
650: }
651:
652: /** The Component should override this method to retrieve the set of codes for dropdowns in a screen, if any are required.
653: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
654: * @throws FrameworkException Indicates some system error.
655: */
656: protected void initDropDownCodes() throws ApplicationExceptions,
657: FrameworkException {
658: }
659:
660: /** The Component should provide an implementation for this method to perform prevalidations before creating a domain object.
661: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
662: * @throws FrameworkException Indicates some system error.
663: */
664: protected abstract void doPrevalidateCreate()
665: throws ApplicationExceptions, FrameworkException;
666:
667: /** The Component should provide an implementation for this method to create a domain object.
668: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
669: * @throws FrameworkException Indicates some system error.
670: */
671: protected abstract void doCreate() throws ApplicationExceptions,
672: FrameworkException;
673:
674: /** The Component should provide an implementation for this method to perform prevalidations before updating a domain object.
675: * @param performDirtyReadCheck this will determine if the Dirty Read check if to be performed prior to an update.
676: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
677: * @throws FrameworkException Indicates some system error.
678: */
679: protected abstract void doPrevalidateUpdate(
680: boolean performDirtyReadCheck)
681: throws ApplicationExceptions, FrameworkException;
682:
683: /** The Component should provide an implementation for this method to update the domain object.
684: * @param performDirtyReadCheck this will determine if the Dirty Read check if to be performed prior to an update.
685: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
686: * @throws FrameworkException Indicates some system error.
687: */
688: protected abstract void doUpdate(boolean performDirtyReadCheck)
689: throws ApplicationExceptions, FrameworkException;
690:
691: /** The Component should provide an implementation for this method to delete the domain object.
692: * @param performDirtyReadCheck this will determine if the Dirty Read check if to be performed prior to a delete.
693: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
694: * @throws FrameworkException Indicates some system error.
695: */
696: protected abstract void doDelete(boolean performDirtyReadCheck)
697: throws ApplicationExceptions, FrameworkException;
698:
699: /** The Component should provide an implementation for this method to retrieve the domain object.
700: * @throws ApplicationExceptions This will be thrown in case any invalid data has been set.
701: * @throws FrameworkException Indicates some system error.
702: */
703: protected abstract void doRetrieve() throws ApplicationExceptions,
704: FrameworkException;
705:
706: /** The Component should provide an implementation for this method to provide the screen information.
707: * @param screens The component should add MaintComponent2.Screen objects to this list.
708: */
709: protected abstract void addScreens(List screens);
710:
711: /** A maintenance component may consist of more than one screen. An instance of this class will represent each screen of the component
712: */
713: public class Screen {
714: private String m_formName;
715: private boolean m_availableInUpdateMode;
716: private boolean m_availableInCreateMode;
717: private boolean m_saveActionAvailableInCreateMode;
718: private boolean m_performTxValidationOnNextAction;
719:
720: /** This will create an instance of a maintenance Screen.
721: * @param formName the Struts GlobalForward for the screen.
722: * @param availableInUpdateMode determines if this screen is available in update mode.
723: * @param availableInCreateMode determines if this screen is available in create mode.
724: * @param saveActionAvailableInCreateMode determines if save action is available for this screen.
725: * @param performTxValidationOnNextAction determines if Tx validation will be performed when the Next action is invoked on this screen.
726: */
727: public Screen(String formName, boolean availableInUpdateMode,
728: boolean availableInCreateMode,
729: boolean saveActionAvailableInCreateMode,
730: boolean performTxValidationOnNextAction) {
731: m_formName = formName;
732: m_availableInUpdateMode = availableInUpdateMode;
733: m_availableInCreateMode = availableInCreateMode;
734: m_saveActionAvailableInCreateMode = saveActionAvailableInCreateMode;
735: m_performTxValidationOnNextAction = performTxValidationOnNextAction;
736: }
737:
738: /** Getter for property formName.
739: * @return Value of property formName.
740: */
741: public String getFormName() {
742: return m_formName;
743: }
744:
745: /** Getter for property availableInUpdateMode.
746: * @return Value of property availableInUpdateMode.
747: */
748: public boolean isAvailableInUpdateMode() {
749: return m_availableInUpdateMode;
750: }
751:
752: /** Getter for property availableInCreateMode.
753: * @return Value of property availableInCreateMode.
754: */
755: public boolean isAvailableInCreateMode() {
756: return m_availableInCreateMode;
757: }
758:
759: /** Getter for property saveActionAvailableInCreateMode.
760: * @return Value of property saveActionAvailableInCreateMode.
761: */
762: public boolean isSaveActionAvailableInCreateMode() {
763: return m_saveActionAvailableInCreateMode;
764: }
765:
766: /** Getter for property performTxValidationOnNextAction.
767: * @return Value of property performTxValidationOnNextAction.
768: */
769: public boolean isPerformTxValidationOnNextAction() {
770: return m_performTxValidationOnNextAction;
771: }
772: }
773:
774: /** A helper routine to return the URL for the properties file containing default values for a component.
775: * The properties file is assumed to be in the base package of the component with the name ComponentDefaultValues.properties'.
776: * This method will try to locate the file on the filesystem.
777: * This allows the application to pick up any changes to the file.
778: * However, if the file is part of a jar, then it'll be loaded by the classloader.
779: * A null will be returned if no file is found.
780: * @param componentClass The component class.
781: * @return the URL for the properties file containing default values for a component.
782: */
783: public static URL determineDefaultValuesUrl(Class componentClass) {
784: URL url = null;
785:
786: // Determine the name of the file containing the default values
787: String defaultValuesFileName = null;
788: String packageName = componentClass.getPackage().getName()
789: .replace('.', '/');
790: if (packageName.endsWith(PACKAGE_SUFFIX_TO_REMOVE))
791: defaultValuesFileName = packageName.substring(0,
792: packageName.lastIndexOf(PACKAGE_SUFFIX_TO_REMOVE))
793: + APPEND_TO_PACKAGE;
794: else
795: defaultValuesFileName = packageName + APPEND_TO_PACKAGE;
796:
797: // Obtain the URL for the file by locating it relative to the classpath
798: try {
799: url = URLHelper.newExtendedURL(defaultValuesFileName);
800: } catch (MalformedURLException e) {
801: // do nothing
802: }
803:
804: return url;
805: }
806:
807: }
|