Java tutorial
/* * Copyright (c) 2000-2004 Netspective Communications LLC. All rights reserved. * * Netspective Communications LLC ("Netspective") permits redistribution, modification and use of this file in source * and binary form ("The Software") under the Netspective Source License ("NSL" or "The License"). The following * conditions are provided as a summary of the NSL but the NSL remains the canonical license and must be accepted * before using The Software. Any use of The Software indicates agreement with the NSL. * * 1. Each copy or derived work of The Software must preserve the copyright notice and this notice unmodified. * * 2. Redistribution of The Software is allowed in object code form only (as Java .class files or a .jar file * containing the .class files) and only as part of an application that uses The Software as part of its primary * functionality. No distribution of the package is allowed as part of a software development kit, other library, * or development tool without written consent of Netspective. Any modified form of The Software is bound by these * same restrictions. * * 3. Redistributions of The Software in any form must include an unmodified copy of The License, normally in a plain * ASCII text file unless otherwise agreed to, in writing, by Netspective. * * 4. The names "Netspective", "Axiom", "Commons", "Junxion", and "Sparx" are trademarks of Netspective and may not be * used to endorse or appear in products derived from The Software without written consent of Netspective. * * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, * ARE HEREBY DISCLAIMED. * * NETSPECTIVE AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A * RESULT OF USING OR DISTRIBUTING THE SOFTWARE. IN NO EVENT WILL NETSPECTIVE OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN * IF IT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ package com.netspective.sparx.panel.editor; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.netspective.commons.value.ValueSources; import com.netspective.commons.value.source.RedirectValueSource; import com.netspective.commons.value.source.StaticValueSource; import com.netspective.commons.xdm.XmlDataModelSchema; import com.netspective.sparx.Project; import com.netspective.sparx.command.PanelEditorCommand; import com.netspective.sparx.form.DialogContext; import com.netspective.sparx.navigate.NavigationContext; import com.netspective.sparx.panel.AbstractPanel; import com.netspective.sparx.panel.BasicHtmlPanelValueContext; import com.netspective.sparx.panel.HtmlPanelAction; import com.netspective.sparx.panel.HtmlPanelAction.Flags; import com.netspective.sparx.panel.HtmlPanelActionStates; import com.netspective.sparx.panel.HtmlPanelActions; import com.netspective.sparx.panel.HtmlPanelBanner; import com.netspective.sparx.panel.HtmlPanelFrame; import com.netspective.sparx.panel.HtmlPanelSkin; import com.netspective.sparx.panel.HtmlPanelValueContext; import com.netspective.sparx.theme.Theme; /** * Base class for custom panel editors. This class is meant to be EXTENDED to create new panel editor types. This does not * define a complete panel editor behavior since the content editing will be up to the child class to implement. The * constructor's of this class are all protected and only meant to be instantiated by the PanelEditorsPackage. */ public class PanelEditor extends AbstractPanel { public static final XmlDataModelSchema.Options XML_DATA_MODEL_SCHEMA_OPTIONS = new XmlDataModelSchema.Options() .setIgnorePcData(true); public static final String PANEL_RECORD_EDIT_ACTION = "Edit"; public static final String PANEL_CONTENT_ADD_ACTION = "Add"; public static final String PANEL_CONTENT_MANAGE_ACTION = "Manage"; public static final String PANEL_RECORD_DONE_ACTION = "Done"; public static final String PANEL_CONTENT_DELETE_ACTION = "Delete"; public static final StaticValueSource CAPTION_MANAGE_ACTION = new StaticValueSource( PANEL_CONTENT_MANAGE_ACTION); public static final StaticValueSource CAPTION_DONE_ACTION = new StaticValueSource(PANEL_RECORD_DONE_ACTION); // the following are all the possible displaymodes that the editor panel can be in public static final int UNKNOWN_MODE = -1; public static final int MODE_DISPLAY = 1; /* default display report mode */ public static final int MODE_EDIT = 2; /* editing panel content mode (dialog and current content (e.g. report)) */ public static final int MODE_DELETE = 3; /* deleting panel content mode (dialog and current content) */ public static final int MODE_ADD = 4; /* add content mode (dialog and current content) */ public static final int MODE_MANAGE = 5; /* managing content (report only but different from default) */ public static final int PANELACTIONFLAG_ISMANAGEACTION = HtmlPanelAction.Flags.FIRST_AVAILABLE_FLAG; /* default skin to use to display query report panel */ public static final String DEFAULT_EDITOR_SKIN = "panel-editor"; /* default name assigned to the dialog defined in the panel editor */ public static final String DEFAULT_DIALOG_NAME = "panel-editor-dialog"; /* a request attribute name used to save the name of the panel editor */ public static final String PANEL_EDITOR_REQ_ATTRIBUTE_PREFIX = "com.netspective.sparx.panel.editor.PanelEditor"; /* the display mode is passed to the panel using a request attribute with this name */ public static final String CURRENT_MODE_CONTEXT_ATTRIBUTE = "panel-editor-mode"; /* the primary key of the record that is to be edited/deleted is passed to the dialog context using this attribute name */ public static final String POPULATE_KEY_CONTEXT_ATTRIBUTE = "panel-editor-key"; /* the previous mode of the panel passed using the request attribute */ public static final String PREV_MODE_REQ_ATTRIBUTE = "com.netspective.sparx.panel.editor.PanelEditor.previousMode"; protected static final Log log = LogFactory.getLog(PanelEditor.class); /* associated project */ protected Project project; /* the package that the panel belongs to */ private PanelEditorsPackage nameSpace; /* name of the panel */ private String name; /* flag to indicate if the record actions for this panel have been prepared or not */ private boolean initialized = false; /* indicates what request parameter is required for this panel */ private String requireRequestParam = null; /* child elements for content */ private Map elements = new HashMap(); /* whether or not the add action should always be shown or only when in Manage mode */ private boolean alwaysShowAddAction; public PanelEditor(Project project) { this.project = project; } /** * */ public PanelEditor(Project project, PanelEditorsPackage pkg) { this(project); setNameSpace(pkg); } /** * @return */ public String getNameForRequestAttribute() { return PANEL_EDITOR_REQ_ATTRIBUTE_PREFIX + getName(); } /** * Create the state object for the panel editor */ public PanelEditorState constructPanelEditorState(NavigationContext nc) { return new PanelEditorState(getQualifiedName()); } /** * Creates a child content element */ public PanelEditorContentElement createElement() { return new PanelEditorContentElement(); } public PanelEditorContentElement createElement(Class cls) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { if (PanelEditorContentElement.class.isAssignableFrom(cls)) { return (PanelEditorContentElement) cls.newInstance(); } else throw new RuntimeException("Don't know what to do with with class: " + cls); } /** * Adds a child content element */ public void addElement(PanelEditorContentElement element) { element.setParent(this); elements.put(element.getName(), element); } /** * Gets the content elements */ public Map getElementsAsMap() { return elements; } public PanelEditorContentElement getElement(String name) { return (PanelEditorContentElement) elements.get(name); } /** * Gets the content elements */ public PanelEditorContentElement[] getElementsAsArray() { int i = 0; PanelEditorContentElement[] list = new PanelEditorContentElement[elements.keySet().size()]; Iterator itr = elements.keySet().iterator(); while (itr.hasNext()) { list[i++] = (PanelEditorContentElement) elements.get(itr.next()); } return list; } public boolean isAlwaysShowAddAction() { return alwaysShowAddAction; } public void setAlwaysShowAddAction(boolean alwaysShowAddAction) { this.alwaysShowAddAction = alwaysShowAddAction; } /** * Calculate the mode the record editor panel is in and also set the * * @return the current mode of the panel editor */ public static int validatePanelEditorMode(String panelMode, String recordKey) { int mode = translateMode(panelMode); // if mode is supposed to be in add, edit, or delete then the recordKey should have been provided. if ((mode == PanelEditor.MODE_EDIT || mode == MODE_DELETE) && recordKey == null) { mode = UNKNOWN_MODE; } return mode; } /** * Translates the mode name into a mode value. This doesn't do any validation checking of the mode. */ public static int translateMode(String modeName) { int mode = MODE_DISPLAY; if (modeName == null || modeName.equals("display")) mode = MODE_DISPLAY; else if (modeName.equals("add")) mode = MODE_ADD; else if (modeName.equals("edit")) mode = MODE_EDIT; else if (modeName.equals("delete")) mode = MODE_DELETE; else if (modeName.equals("manage")) mode = MODE_MANAGE; else mode = UNKNOWN_MODE; return mode; } /** * Translates the mode integer to its string version */ public static String translateModeToString(int mode) { String modeName = null; if (mode == MODE_DISPLAY) modeName = "display"; else if (mode == MODE_ADD) modeName = "add"; else if (mode == MODE_EDIT) modeName = "edit"; else if (mode == MODE_DELETE) modeName = "delete"; else if (mode == MODE_MANAGE) modeName = "manage"; return modeName; } /** * Gets the associated project * * @return associated project */ public Project getProject() { return project; } /** * Gets the request parameter that is required for this panel editor * * @return request parameter name */ public String getRequireRequestParam() { return requireRequestParam; } /** * Sets the request parameter that is required for this panel editor */ public void setRequireRequestParam(String requireRequestParam) { this.requireRequestParam = requireRequestParam; } /** * Gets the name of the panel * * @return name of the panel */ public String getName() { return name; } /** * Sets the name of the panel * * @param name name of the panel */ public void setName(String name) { this.name = name; } public String getQualifiedName() { return nameSpace != null ? nameSpace.getNameSpaceId() + "." + name : name; } /** * Gets the namespace (package name) * * @return namespace */ public PanelEditorsPackage getNameSpace() { return nameSpace; } /** * Sets the namespace (package name) * * @param nameSpace package name */ public void setNameSpace(PanelEditorsPackage nameSpace) { this.nameSpace = nameSpace; } /** * Gets the name to use when saving this panel editor in a collection map */ public String getNameForMapKey() { return translateNameForMapKey(getQualifiedName()); } /** * Translate name of the panel editor to a key name suitable for use in a map * * @param name name of the panel editor * * @return translated key name */ public static final String translateNameForMapKey(String name) { return name != null ? name.toUpperCase() : null; } public void setInitialized(boolean initialized) { this.initialized = initialized; } /** * Generates the URL string for the panel editor's associated actions. This URL is set only once and any dynamic * information needs to be passed using value sources. * * @param actionMode the mode for which the URL is being calculated * * @return url string (containing context sensitive elements) used to construct a redirect value source */ public String generatePanelActionUrl(int actionMode) { String url = "active-page:"; if (actionMode == PanelEditor.MODE_EDIT) { url = url + PanelEditorCommand.PANEL_EDITOR_COMMAND_REQUEST_PARAM_NAME + "=" + getQualifiedName() + ",edit,${request-attr:" + PREV_MODE_REQ_ATTRIBUTE + "}"; } else if (actionMode == MODE_DELETE) { url = url + PanelEditorCommand.PANEL_EDITOR_COMMAND_REQUEST_PARAM_NAME + "=" + this.getQualifiedName() + ",delete,${request-attr:" + PREV_MODE_REQ_ATTRIBUTE + "}"; } else if (actionMode == MODE_ADD) { url = url + PanelEditorCommand.PANEL_EDITOR_COMMAND_REQUEST_PARAM_NAME + "=" + this.getQualifiedName() + ",add,${request-attr:" + PREV_MODE_REQ_ATTRIBUTE + "}"; } else if (actionMode == MODE_MANAGE) url = url + PanelEditorCommand.PANEL_EDITOR_COMMAND_REQUEST_PARAM_NAME + "=" + this.getQualifiedName() + ",manage,${request-attr:" + PREV_MODE_REQ_ATTRIBUTE + "}"; return url; } public static String calculateNextModeUrl(DialogContext dc, String panelName, int panelMode, int previousMode, String panelRecordKey) { String url = "active-page:"; String currentUrl = dc.getNavigationContext().getActivePage().getUrl(dc); if (previousMode != MODE_DISPLAY) url = url + PanelEditorCommand.PANEL_EDITOR_COMMAND_REQUEST_PARAM_NAME + "=" + panelName + ",manage"; else url = currentUrl; String urlStr = ValueSources.getInstance().getValueSourceOrStatic(url).getTextValue(dc); return urlStr; } /** * Creates all the panel actions for the panel editor. This method SHOULD only be called once to populate the * panel editor. */ public void initialize() { createPanelBannerActions(); createPanelFrameActions(); initialized = true; } /** * @param writer * @param dc * @param theme * @param flags * * @throws IOException */ public void render(Writer writer, DialogContext dc, Theme theme, int flags) throws IOException { } /** * @param writer * @param nc * @param theme * @param flags * * @throws IOException */ public void render(Writer writer, NavigationContext nc, Theme theme, int flags) throws IOException { PanelEditorState state = (PanelEditorState) nc.getAttribute(""); if (state != null) render(writer, nc, state); } /** * Renders the panel editor. When the panel editor is in ADD, EDIT, or DELETE modes, it has an active element * and the display of the editor is broken into two columns. The left column is for display of the * active element's "action" item while the right column contains all the elements in their inactive display * mode. * * @param writer writer to render the output to * @param nc current navigation context */ public void render(Writer writer, NavigationContext nc, PanelEditorState state) throws IOException { if (getRequireRequestParam() != null) { if (nc.getHttpRequest().getParameter(getRequireRequestParam()) == null) throw new RuntimeException("Record editor panel '" + getQualifiedName() + "' requires the request " + "parameter '" + getRequireRequestParam() + "'."); } if (!isInitialized()) initialize(); int mode = state.getCurrentMode(); BasicHtmlPanelValueContext pvc = new BasicHtmlPanelValueContext(nc, this); // only when the mode is in DISPLAY mode, the panel editor is displayed HtmlPanelSkin skin = null; skin = nc.getActiveTheme().getTemplateSkin("panel-editor-full"); /* if (mode != PanelEditor.MODE_DISPLAY && mode != PanelEditor.MODE_MANAGE) { skin = nc.getActiveTheme().getTemplateSkin("panel-editor-compressed"); } else { skin = nc.getActiveTheme().getTemplateSkin("panel-editor-full"); } */ nc.getHttpRequest().setAttribute(PREV_MODE_REQ_ATTRIBUTE, translateModeToString(state.getCurrentMode())); String activeElement = state.getActiveElement(); StringWriter activeEditorWriter = new StringWriter(); StringWriter activeDisplayWriter = new StringWriter(); StringWriter inactiveWriter = new StringWriter(); PanelEditorContentElement[] elements = getElementsAsArray(); for (int i = 0; i < elements.length; i++) { if (activeElement != null && elements[i].getName().equals(activeElement)) { elements[i].renderEditorContent(activeEditorWriter, nc, state); elements[i].renderDisplayContent(activeDisplayWriter, nc, state); } else { elements[i].renderDisplayContent(inactiveWriter, nc, state); } } preparePanelActionStates(nc, pvc, state, mode); if (mode != PanelEditor.MODE_DISPLAY) writer.write("<table class=\"panel-editor-table-manage\"><tr>\n"); else writer.write("<table class=\"panel-editor-table\"><tr>\n"); if (activeElement != null) writer.write("<td class=\"active-content\">" + activeEditorWriter.getBuffer().toString() + "</td>"); writer.write("<td class=\"display-content\">"); skin.renderPanelRegistration(writer, pvc); skin.renderFrameBegin(writer, pvc); writer.write((activeElement != null ? activeDisplayWriter.getBuffer().toString() : "") + inactiveWriter.getBuffer().toString()); skin.renderFrameEnd(writer, pvc); writer.write("</td></tr></table>\n"); } /** * Calculate and process the state of the all the panel actions based on current context * * @param nc current navigation context * @param vc current report panel context * @param mode panel mode */ public void preparePanelActionStates(NavigationContext nc, HtmlPanelValueContext vc, PanelEditorState state, int mode) { HtmlPanelActionStates actionStates = vc.getPanelActionStates(); if (mode == MODE_DISPLAY) { actionStates.getState(PANEL_RECORD_DONE_ACTION).getStateFlags().setFlag(HtmlPanelAction.Flags.HIDDEN); PanelEditorContentElement[] elements = getElementsAsArray(); String caption = null; for (int i = 0; i < elements.length; i++) { caption = elements[i].getCaption(); PanelEditorContentElement.PanelEditorContentState elementState = state .getElementState(elements[i].getName()); // hide the ADD action only if there is content in the content element and we're not always showing add action if (!alwaysShowAddAction && !elementState.isEmptyContent()) actionStates.getState("Add " + (caption != null ? caption : "")).getStateFlags() .setFlag(HtmlPanelAction.Flags.HIDDEN); } } else if (mode == MODE_ADD || mode == MODE_EDIT || mode == MODE_DELETE) { actionStates.getState(PANEL_CONTENT_MANAGE_ACTION).getStateFlags() .setFlag(HtmlPanelAction.Flags.HIDDEN); } else if (mode == MODE_MANAGE) { actionStates.getState(PANEL_CONTENT_MANAGE_ACTION).getStateFlags() .setFlag(HtmlPanelAction.Flags.HIDDEN); } } /** * Creates the frame actions for the panel editor. They are MANAGE, DONE. */ public void createPanelFrameActions() { HtmlPanelFrame frame = getFrame(); if (frame == null) { setFrame(createFrame()); } HtmlPanelActions actions = new HtmlPanelActions(); HtmlPanelAction manageAction = frame.createAction(); String manageUrl = generatePanelActionUrl(PanelEditor.MODE_MANAGE); manageAction.setCaption(CAPTION_MANAGE_ACTION); manageAction.setRedirect(new RedirectValueSource(manageUrl)); manageAction.getFlags().setFlag(PANELACTIONFLAG_ISMANAGEACTION | Flags.HIDDEN); // the skin renders the heading of the panel editor as the "manage" button actions.add(manageAction); String doneUrl = generatePanelActionUrl(PanelEditor.MODE_DISPLAY); HtmlPanelAction doneAction = frame.createAction(); doneAction.setCaption(CAPTION_DONE_ACTION); doneAction.setRedirect(new RedirectValueSource(doneUrl)); actions.add(doneAction); frame.setActions(actions); } public void createPanelBannerActions() { // Calculate what to display in the banner if (getBanner() == null) setBanner(new HtmlPanelBanner()); HtmlPanelBanner banner = getBanner(); HtmlPanelActions actions = new HtmlPanelActions(); PanelEditorContentElement[] elements = getElementsAsArray(); for (int i = 0; i < elements.length; i++) { HtmlPanelAction addAction = banner.createAction(); PanelEditorContentElement element = elements[i]; String addUrl = generatePanelActionUrl(PanelEditor.MODE_ADD); addUrl = element.appendElementInfoToActionUrl(addUrl, PanelEditor.MODE_ADD); String caption = element.getCaption(); addAction.setCaption(new StaticValueSource("Add " + (caption != null ? caption : ""))); addAction.setRedirect(new RedirectValueSource(addUrl)); actions.add(addAction); } banner.setActions(actions); } /** * Check to see if all the actions needed for the panel edito have been ADDED. The * adding of the actions need to be done only once and this flag is set * once the addition is done. * * @return True if all required actions have been added */ public boolean isInitialized() { return initialized; } }