Java tutorial
/* * Copyright (c) 2009, SQL Power Group Inc. * * This file is part of Wabit. * * Wabit is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Wabit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.wabit.dao.session; import java.beans.PropertyChangeEvent; import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; import org.apache.commons.beanutils.PropertyUtils; import org.apache.log4j.Logger; import ca.sqlpower.dao.PersistedObjectEntry; import ca.sqlpower.dao.PersistedPropertiesEntry; import ca.sqlpower.dao.PersistedSPOProperty; import ca.sqlpower.dao.PersistedSPObject; import ca.sqlpower.dao.PersisterUtils; import ca.sqlpower.dao.RemovedObjectEntry; import ca.sqlpower.dao.SPPersistenceException; import ca.sqlpower.dao.SPPersister; import ca.sqlpower.dao.SPPersister.DataType; import ca.sqlpower.enterprise.client.Grant; import ca.sqlpower.enterprise.client.GroupMember; import ca.sqlpower.enterprise.client.User; import ca.sqlpower.object.SPChildEvent; import ca.sqlpower.object.SPListener; import ca.sqlpower.object.SPObject; import ca.sqlpower.query.Item; import ca.sqlpower.query.QueryImpl; import ca.sqlpower.query.TableContainer; import ca.sqlpower.swingui.event.SessionLifecycleEvent; import ca.sqlpower.swingui.event.SessionLifecycleListener; import ca.sqlpower.util.SQLPowerUtils; import ca.sqlpower.util.TransactionEvent; import ca.sqlpower.wabit.WabitDataSource; import ca.sqlpower.wabit.WabitObject; import ca.sqlpower.wabit.WabitSession; import ca.sqlpower.wabit.WabitWorkspace; import ca.sqlpower.wabit.dao.WabitSessionPersister; import ca.sqlpower.wabit.enterprise.client.ReportTask; import ca.sqlpower.wabit.image.WabitImage; import ca.sqlpower.wabit.report.CellSetRenderer; import ca.sqlpower.wabit.report.ChartRenderer; import ca.sqlpower.wabit.report.ColumnInfo; import ca.sqlpower.wabit.report.ContentBox; import ca.sqlpower.wabit.report.Guide; import ca.sqlpower.wabit.report.ImageRenderer; import ca.sqlpower.wabit.report.WabitLabel; import ca.sqlpower.wabit.report.Page; import ca.sqlpower.wabit.report.ResultSetRenderer; import ca.sqlpower.wabit.report.WabitObjectReportRenderer; import ca.sqlpower.wabit.report.chart.Chart; import ca.sqlpower.wabit.report.chart.ChartColumn; import ca.sqlpower.wabit.report.selectors.ComboBoxSelector; import ca.sqlpower.wabit.report.selectors.DateSelector; import ca.sqlpower.wabit.report.selectors.TextBoxSelector; import ca.sqlpower.wabit.rs.ResultSetProducer; import ca.sqlpower.wabit.rs.olap.OlapQuery; import ca.sqlpower.wabit.rs.olap.WabitOlapAxis; import ca.sqlpower.wabit.rs.olap.WabitOlapSelection; import ca.sqlpower.wabit.rs.query.QueryCache; import ca.sqlpower.wabit.rs.query.WabitConstantItem; import ca.sqlpower.wabit.rs.query.WabitConstantsContainer; import ca.sqlpower.wabit.rs.query.WabitItem; import ca.sqlpower.wabit.rs.query.WabitJoin; import ca.sqlpower.wabit.rs.query.WabitTableContainer; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Multimap; /** * An implementation of {@link SPListener} used exclusively for listening to * a {@link WabitWorkspace} and its children. When an event is fired from an * object this listener will convert the event into persist calls. The persist * calls will be made on the target persister. */ public class WorkspacePersisterListener implements SPListener { private final static Logger logger = Logger.getLogger(WorkspacePersisterListener.class); private static class PropertyToIgnore { private final String propertyName; private final Class<? extends WabitObject> classType; public PropertyToIgnore(String propertyName, Class<? extends WabitObject> classType) { this.propertyName = propertyName; this.classType = classType; } public String getPropertyName() { return propertyName; } public Class<? extends WabitObject> getClassType() { return classType; } } /** * This list contains a description of all of the properties that fire * events in Wabit but are not be persisted in the server. These properties * are normally properties for use in a UI that are saved to a local file * but do not make sense to be saved to the server. */ private static final List<PropertyToIgnore> ignoreList; static { //Creating the ignore list here List<PropertyToIgnore> ignored = new ArrayList<PropertyToIgnore>(); ignored.add(new PropertyToIgnore("zoomLevel", WabitObject.class)); ignored.add(new PropertyToIgnore("editorPanelModel", WabitWorkspace.class)); ignored.add(new PropertyToIgnore("colBeingDragged", ResultSetRenderer.class)); ignored.add(new PropertyToIgnore("delegate", WabitConstantItem.class)); ignored.add(new PropertyToIgnore("modifiedOlapQuery", CellSetRenderer.class)); ignoreList = Collections.unmodifiableList(ignored); } /** * This will be the list we will use to rollback persisted properties */ private List<PersistedPropertiesEntry> persistedPropertiesRollbackList = new LinkedList<PersistedPropertiesEntry>(); /** * This will be the list we use to rollback persisted objects. * It contains UUIDs of objects that were created. */ private List<PersistedObjectEntry> persistedObjectsRollbackList = new LinkedList<PersistedObjectEntry>(); /** * This is the list we use to rollback object removal */ private List<RemovedObjectEntry> objectsToRemoveRollbackList = new LinkedList<RemovedObjectEntry>(); /** * Persisted property buffer, mapping of {@link WabitObject} UUIDs to each * individual persisted property */ private Multimap<String, PersistedSPOProperty> persistedProperties = LinkedListMultimap.create(); /** * Persisted {@link WabitObject} buffer, contains all the data that was * passed into the persistedObject call in the order of insertion */ private List<PersistedSPObject> persistedObjects = new LinkedList<PersistedSPObject>(); /** * {@link WabitObject} removal buffer, mapping of {@link WabitObject} UUIDs * to their parents */ private List<RemovedObjectEntry> objectsToRemove = new LinkedList<RemovedObjectEntry>(); private int transactionCount = 0; /** * This will connect a new instance of this listener to the workspace and * all of its descendants. When the children of a workspace change the * listener will be added to or removed from the children. When the session * is being disposed of the listener will be removed from the workspace * tree. * * @param session * The session to listen to for lifecycle changes and its * workspace will be listened to by a new persister listener. * @param targetPersister * This persister will have persist methods called on it when * events occur in the workspace in the given session. */ public static WorkspacePersisterListener attachListener(final WabitSession session, SPPersister targetPersister, WabitSessionPersister eventSource, boolean containerDoPopulate) { final WorkspacePersisterListener listener = new WorkspacePersisterListener(session, targetPersister, eventSource, containerDoPopulate); SQLPowerUtils.listenToHierarchy(session.getWorkspace(), listener); session.addSessionLifecycleListener(new SessionLifecycleListener<WabitSession>() { public void sessionClosing(SessionLifecycleEvent<WabitSession> e) { SQLPowerUtils.unlistenToHierarchy(session.getWorkspace(), listener); } public void sessionOpening(SessionLifecycleEvent<WabitSession> e) { // no op } }); return listener; } /** * This is the persister to call the appropriate persist methods on when an * event occurs signaling a change to the model. */ private final SPPersister target; /** * Converts any object into a simple type and converts any simple type back. */ private final WabitSessionPersisterSuperConverter converter; private final WabitSessionPersister eventSource; private final WabitSession session; private boolean headingToWinconsin; /** * This listener should be added through the static method for attaching a * listener to a session. * <p> * A new listener should only be created in testing. To properly add a * listener to a session see * {@link #attachListener(WabitSession, SPPersister)}. * * @param session * The session whose workspace will be listened to. * @param targetPersister * The persister that will have the events be forwarded to as * persist calls. */ public WorkspacePersisterListener(WabitSession session, SPPersister targetPersister, boolean containerDoPopulate) { this(session, targetPersister, null, containerDoPopulate); } /** * This listener should be added through the static method for attaching a * listener to a session. * <p> * A new listener should only be created in testing. To properly add a * listener to a session see * {@link #attachListener(WabitSession, SPPersister)}. * * @param session * The session whose workspace will be listened to. * @param targetPersister * The persister that will have the events be forwarded to as * persist calls. * @param eventSource * A {@link SPPersister} that this listener will consult in * order to perform 'echo-cancellation' of events. */ public WorkspacePersisterListener(WabitSession session, SPPersister targetPersister, WabitSessionPersister eventSource, boolean containerDoPopulate) { this.session = session; this.converter = new WabitSessionPersisterSuperConverter(session, session.getWorkspace(), containerDoPopulate); this.target = targetPersister; this.eventSource = eventSource; } /** * Returns true if the WabitSessionPersister that this listener complements * is currently in the middle of an update. In that case, none of the * WabitListener methods should make calls into the target persister. * * @return True if forwarding an event to the target persister would * constitute an echo. */ private boolean wouldEcho() { if (this.headingToWinconsin) return true; return eventSource != null && eventSource.isUpdatingWabitWorkspace(); } public void transactionEnded(TransactionEvent e) { if (wouldEcho()) return; try { logger.debug("transactionEnded " + ((e == null) ? null : e.getMessage())); this.commit(); } catch (SPPersistenceException e1) { throw new RuntimeException(e1); } } public void transactionRollback(TransactionEvent e) { if (wouldEcho()) return; logger.debug("transactionRollback " + ((e == null) ? null : e.getMessage())); this.rollback(); } public void transactionStarted(TransactionEvent e) { if (wouldEcho()) return; logger.debug("transactionStarted " + ((e == null) ? null : e.getMessage())); transactionCount++; } public void childAdded(SPChildEvent e) { SQLPowerUtils.listenToHierarchy(e.getChild(), this); if (wouldEcho()) return; logger.debug("wabitChildAdded " + e.getChildType() + " with UUID " + e.getChild().getUUID()); persistObject(e.getChild()); } /** * Persists the given object and all of its descendants to the next * persister. The root object and every descendant will be sent to the * persister as a persist object and all of its properties will be sent as * unconditional property persists. * * @param wo * The root of the tree of objects that will be persisted. This * object and all of its children will be persisted. */ public void persistObject(SPObject wo) { if (wouldEcho()) return; this.transactionStarted(TransactionEvent.createStartTransactionEvent(this, "Creating transaction started event from persistObject.")); int index = 0; SPObject parent = wo.getParent(); if (parent != null) { index = parent.getChildren().indexOf(wo) - parent.childPositionOffset(wo.getClass()); if (index < 0) { index = 0; } } persistChild(parent, wo, wo.getClass(), index); for (SPObject child : wo.getChildren()) { persistObject(child); } this.transactionEnded(TransactionEvent.createEndTransactionEvent(this)); } /** * Calls {@link SPPersister#persistObject(String, String, String, int)} * for the child object and * {@link SPPersister#persistProperty(String, String, DataType, Object)} * for each property on the object. * * @param parent * The parent of the object being persisted as added to this * object. * @param child * The child object that was added to its parent. * @param childClassType * The object type of the child added. * @param indexOfChild * The index of the child in the child list of the parent. */ protected void persistChild(SPObject parent, SPObject child, Class<? extends SPObject> childClassType, int indexOfChild) { if (wouldEcho()) return; this.transactionStarted(TransactionEvent.createStartTransactionEvent(this, "Creating transaction started event from persistChild.")); final String parentUUID; if (child instanceof WabitWorkspace) { parentUUID = null; } else if (parent == null) { this.rollback(); throw new NullPointerException( "Child is not a WabitWorkspace, " + "but has a null parent ID: " + child); } else { parentUUID = parent.getUUID(); } this.persistedObjects.add( new PersistedSPObject(parentUUID, child.getClass().getSimpleName(), child.getUUID(), indexOfChild)); logger.debug("Persisting " + child.getName() + " (" + child.getClass() + ")"); String uuid = child.getUUID(); logger.debug("persistChild on " + childClassType + " with UUID " + uuid); // Persist any properties required for WabitObject constructor if (child instanceof CellSetRenderer) { CellSetRenderer csRenderer = (CellSetRenderer) child; // Remaining properties this.persistProperty(uuid, "bodyAlignment", DataType.STRING, converter.convertToBasicType(csRenderer.getBodyAlignment())); this.persistProperty(uuid, "bodyFont", DataType.STRING, converter.convertToBasicType(csRenderer.getBodyFont())); this.persistProperty(uuid, "bodyFormat", DataType.STRING, converter.convertToBasicType(csRenderer.getBodyFormat())); this.persistProperty(uuid, "headerFont", DataType.STRING, converter.convertToBasicType(csRenderer.getHeaderFont())); } else if (child instanceof ChartColumn) { ChartColumn chartColumn = (ChartColumn) child; // Constructor arguments this.persistProperty(uuid, "columnName", DataType.STRING, converter.convertToBasicType(chartColumn.getColumnName())); this.persistProperty(uuid, "dataType", DataType.STRING, converter.convertToBasicType(chartColumn.getDataType())); // Remaining properties this.persistProperty(uuid, "roleInChart", DataType.STRING, converter.convertToBasicType(chartColumn.getRoleInChart())); this.persistProperty(uuid, "XAxisIdentifier", DataType.REFERENCE, converter.convertToBasicType(chartColumn.getXAxisIdentifier(), DataType.REFERENCE)); } else if (child instanceof Chart) { Chart chart = (Chart) child; // Remaining properties this.persistProperty(uuid, "gratuitouslyAnimated", DataType.BOOLEAN, converter.convertToBasicType(chart.isGratuitouslyAnimated())); this.persistProperty(uuid, "legendPosition", DataType.STRING, converter.convertToBasicType(chart.getLegendPosition())); ResultSetProducer rsProducer = chart.getQuery(); this.persistProperty(uuid, "query", DataType.REFERENCE, converter.convertToBasicType(rsProducer)); this.persistProperty(uuid, "type", DataType.STRING, converter.convertToBasicType(chart.getType())); this.persistProperty(uuid, "XAxisLabelRotation", DataType.DOUBLE, converter.convertToBasicType(chart.getXAxisLabelRotation())); this.persistProperty(uuid, "xaxisName", DataType.STRING, converter.convertToBasicType(chart.getXaxisName())); this.persistProperty(uuid, "yaxisName", DataType.STRING, converter.convertToBasicType(chart.getYaxisName())); this.persistProperty(uuid, "backgroundColour", DataType.STRING, converter.convertToBasicType(chart.getBackgroundColour())); this.persistProperty(uuid, "autoXAxisRange", DataType.BOOLEAN, converter.convertToBasicType(chart.isAutoXAxisRange())); this.persistProperty(uuid, "autoYAxisRange", DataType.BOOLEAN, converter.convertToBasicType(chart.isAutoYAxisRange())); this.persistProperty(uuid, "XAxisMaxRange", DataType.DOUBLE, converter.convertToBasicType(chart.getXAxisMaxRange())); this.persistProperty(uuid, "YAxisMaxRange", DataType.DOUBLE, converter.convertToBasicType(chart.getYAxisMaxRange())); this.persistProperty(uuid, "XAxisMinRange", DataType.DOUBLE, converter.convertToBasicType(chart.getXAxisMinRange())); this.persistProperty(uuid, "YAxisMinRange", DataType.DOUBLE, converter.convertToBasicType(chart.getYAxisMinRange())); } else if (child instanceof ChartRenderer) { //The only argument to this class is handled later by the //report content renderer section } else if (child instanceof ColumnInfo) { ColumnInfo columnInfo = (ColumnInfo) child; // Constructor argument this.persistProperty(uuid, ColumnInfo.COLUMN_ALIAS, DataType.STRING, converter.convertToBasicType(columnInfo.getColumnAlias())); Item item = columnInfo.getColumnInfoItem(); if (item != null) { this.persistProperty(uuid, ColumnInfo.COLUMN_INFO_ITEM_CHANGED, DataType.STRING, converter.convertToBasicType(item)); } // Remaining properties this.persistProperty(uuid, ColumnInfo.DATATYPE_CHANGED, DataType.STRING, converter.convertToBasicType(columnInfo.getDataType())); this.persistProperty(uuid, ColumnInfo.HORIZONAL_ALIGNMENT_CHANGED, DataType.STRING, converter.convertToBasicType(columnInfo.getHorizontalAlignment())); this.persistProperty(uuid, ColumnInfo.WIDTH_CHANGED, DataType.INTEGER, columnInfo.getWidth()); this.persistProperty(uuid, ColumnInfo.WILL_GROUP_OR_BREAK_CHANGED, DataType.STRING, converter.convertToBasicType(columnInfo.getWillGroupOrBreak())); this.persistProperty(uuid, ColumnInfo.WILL_SUBTOTAL_CHANGED, DataType.BOOLEAN, converter.convertToBasicType(columnInfo.getWillSubtotal())); this.persistProperty(uuid, "format", DataType.STRING, converter.convertToBasicType(columnInfo.getFormat())); } else if (child instanceof ContentBox) { ContentBox contentBox = (ContentBox) child; // Remaining arguments this.persistProperty(uuid, "font", DataType.STRING, converter.convertToBasicType(contentBox.getFont())); this.persistProperty(uuid, "height", DataType.DOUBLE, converter.convertToBasicType(contentBox.getHeight())); this.persistProperty(uuid, "width", DataType.DOUBLE, converter.convertToBasicType(contentBox.getWidth())); this.persistProperty(uuid, "x", DataType.DOUBLE, converter.convertToBasicType(contentBox.getX())); this.persistProperty(uuid, "y", DataType.DOUBLE, converter.convertToBasicType(contentBox.getY())); } else if (child instanceof Grant) { Grant grant = (Grant) child; // Constructor arguments this.persistProperty(uuid, "subject", DataType.STRING, converter.convertToBasicType(grant.getSubject())); this.persistProperty(uuid, "type", DataType.STRING, converter.convertToBasicType(grant.getType())); this.persistProperty(uuid, "createPrivilege", DataType.BOOLEAN, converter.convertToBasicType(grant.isCreatePrivilege())); this.persistProperty(uuid, "deletePrivilege", DataType.BOOLEAN, converter.convertToBasicType(grant.isDeletePrivilege())); this.persistProperty(uuid, "executePrivilege", DataType.BOOLEAN, converter.convertToBasicType(grant.isExecutePrivilege())); this.persistProperty(uuid, "grantPrivilege", DataType.BOOLEAN, converter.convertToBasicType(grant.isGrantPrivilege())); this.persistProperty(uuid, "modifyPrivilege", DataType.BOOLEAN, converter.convertToBasicType(grant.isModifyPrivilege())); } else if (child instanceof GroupMember) { GroupMember groupMember = (GroupMember) child; // Constructor argument this.persistProperty(uuid, "user", DataType.REFERENCE, converter.convertToBasicType(groupMember.getUser())); } else if (child instanceof Guide) { Guide guide = (Guide) child; // Constructor arguments this.persistProperty(uuid, "axis", DataType.STRING, converter.convertToBasicType(guide.getAxis())); this.persistProperty(uuid, "offset", DataType.DOUBLE, converter.convertToBasicType(guide.getOffset())); // Remaining properties } else if (child instanceof ImageRenderer) { ImageRenderer iRenderer = (ImageRenderer) child; // Remaining arguments this.persistProperty(uuid, "HAlign", DataType.STRING, converter.convertToBasicType(iRenderer.getHAlign())); this.persistProperty(uuid, "VAlign", DataType.STRING, converter.convertToBasicType(iRenderer.getVAlign())); this.persistProperty(uuid, "image", DataType.REFERENCE, converter.convertToBasicType(iRenderer.getImage())); this.persistProperty(uuid, "preserveAspectRatioWhenResizing", DataType.BOOLEAN, converter.convertToBasicType(iRenderer.isPreserveAspectRatioWhenResizing())); this.persistProperty(uuid, "preservingAspectRatio", DataType.BOOLEAN, converter.convertToBasicType(iRenderer.isPreservingAspectRatio())); } else if (child instanceof WabitLabel) { WabitLabel label = (WabitLabel) child; this.persistProperty(uuid, "font", DataType.STRING, converter.convertToBasicType(label.getFont())); this.persistProperty(uuid, "foregroundColour", DataType.STRING, converter.convertToBasicType(label.getForegroundColour())); this.persistProperty(uuid, "borderColour", DataType.STRING, converter.convertToBasicType(label.getBorderColour())); this.persistProperty(uuid, "padding", DataType.STRING, converter.convertToBasicType(label.getPadding())); this.persistProperty(uuid, "horizontalAlignment", DataType.STRING, converter.convertToBasicType(label.getHorizontalAlignment())); this.persistProperty(uuid, "text", DataType.STRING, converter.convertToBasicType(label.getText())); this.persistProperty(uuid, "verticalAlignment", DataType.STRING, converter.convertToBasicType(label.getVerticalAlignment())); this.persistProperty(uuid, "backgroundColour", DataType.STRING, converter.convertToBasicType(label.getBackgroundColour())); } else if (child instanceof OlapQuery) { OlapQuery olapQuery = (OlapQuery) child; // Constructor arguments this.persistProperty(uuid, "queryName", DataType.STRING, converter.convertToBasicType(olapQuery.getQueryName())); this.persistProperty(uuid, "catalogName", DataType.STRING, converter.convertToBasicType(olapQuery.getCatalogName())); this.persistProperty(uuid, "schemaName", DataType.STRING, converter.convertToBasicType(olapQuery.getSchemaName())); this.persistProperty(uuid, "cubeName", DataType.STRING, converter.convertToBasicType(olapQuery.getCubeName())); this.persistProperty(uuid, "modifiedOlapQuery", DataType.STRING, converter.convertToBasicType(olapQuery.getModifiedOlapQuery())); this.persistProperty(uuid, "olapDataSource", DataType.STRING, converter.convertToBasicType(olapQuery.getOlapDataSource())); // Remaining properties this.persistProperty(uuid, "nonEmpty", DataType.BOOLEAN, converter.convertToBasicType(olapQuery.isNonEmpty())); if (olapQuery.getCurrentCube() != null) { this.persistProperty(uuid, "currentCube", DataType.STRING, converter.convertToBasicType(olapQuery.getCurrentCube(), olapQuery.getOlapDataSource())); } } else if (child instanceof Page) { Page page = (Page) child; // Constructor arguments this.persistProperty(uuid, "width", DataType.INTEGER, converter.convertToBasicType(page.getWidth())); this.persistProperty(uuid, "height", DataType.INTEGER, converter.convertToBasicType(page.getHeight())); this.persistProperty(uuid, "orientation", DataType.STRING, converter.convertToBasicType(page.getOrientation())); // Remaining properties this.persistProperty(uuid, "defaultFont", DataType.STRING, converter.convertToBasicType(page.getDefaultFont())); } else if (child instanceof QueryCache) { QueryCache query = (QueryCache) child; // Constructor argument this.persistProperty(uuid, "dataSource", DataType.STRING, converter.convertToBasicType(query.getDataSource())); // Remaining properties // The zoom property is being ignored here because it does not make much // sense to have the query zoom change for all users working on it. this.persistProperty(uuid, "streaming", DataType.BOOLEAN, converter.convertToBasicType(query.isStreaming())); this.persistProperty(uuid, "streamingRowLimit", DataType.INTEGER, converter.convertToBasicType(query.getStreamingRowLimit())); this.persistProperty(uuid, QueryImpl.ROW_LIMIT, DataType.INTEGER, converter.convertToBasicType(query.getRowLimit())); this.persistProperty(uuid, QueryImpl.GROUPING_ENABLED, DataType.BOOLEAN, converter.convertToBasicType(query.isGroupingEnabled())); this.persistProperty(uuid, "promptForCrossJoins", DataType.BOOLEAN, converter.convertToBasicType(query.getPromptForCrossJoins())); this.persistProperty(uuid, "automaticallyExecuting", DataType.BOOLEAN, converter.convertToBasicType(query.isAutomaticallyExecuting())); this.persistProperty(uuid, QueryImpl.GLOBAL_WHERE_CLAUSE, DataType.STRING, converter.convertToBasicType(query.getGlobalWhereClause())); this.persistProperty(uuid, QueryImpl.USER_MODIFIED_QUERY, DataType.STRING, converter.convertToBasicType(query.getUserModifiedQuery())); this.persistProperty(uuid, "executeQueriesWithCrossJoins", DataType.BOOLEAN, converter.convertToBasicType(query.getExecuteQueriesWithCrossJoins())); } else if (child instanceof ReportTask) { ReportTask task = (ReportTask) child; // Remaining arguments this.persistProperty(uuid, "email", DataType.STRING, converter.convertToBasicType(task.getEmail())); this.persistProperty(uuid, "triggerType", DataType.STRING, converter.convertToBasicType(task.getTriggerType())); this.persistProperty(uuid, "triggerHourParam", DataType.INTEGER, converter.convertToBasicType(task.getTriggerHourParam(), DataType.INTEGER)); this.persistProperty(uuid, "triggerMinuteParam", DataType.INTEGER, converter.convertToBasicType(task.getTriggerMinuteParam(), DataType.INTEGER)); this.persistProperty(uuid, "triggerDayOfWeekParam", DataType.INTEGER, converter.convertToBasicType(task.getTriggerDayOfWeekParam(), DataType.INTEGER)); this.persistProperty(uuid, "triggerDayOfMonthParam", DataType.INTEGER, converter.convertToBasicType(task.getTriggerDayOfMonthParam(), DataType.INTEGER)); this.persistProperty(uuid, "triggerIntervalParam", DataType.INTEGER, converter.convertToBasicType(task.getTriggerIntervalParam(), DataType.INTEGER)); this.persistProperty(uuid, "report", DataType.REFERENCE, converter.convertToBasicType(task.getReport(), DataType.REFERENCE)); } else if (child instanceof ResultSetRenderer) { ResultSetRenderer renderer = (ResultSetRenderer) child; // Remaining properties this.persistProperty(uuid, "bodyFont", DataType.STRING, converter.convertToBasicType(renderer.getBodyFont())); this.persistProperty(uuid, "headerFont", DataType.STRING, converter.convertToBasicType(renderer.getHeaderFont())); this.persistProperty(uuid, "borderType", DataType.STRING, converter.convertToBasicType(renderer.getBorderType())); this.persistProperty(uuid, "nullString", DataType.STRING, converter.convertToBasicType(renderer.getNullString())); this.persistProperty(uuid, "printingGrandTotals", DataType.BOOLEAN, converter.convertToBasicType(renderer.isPrintingGrandTotals())); this.persistProperty(uuid, "backgroundColour", DataType.STRING, converter.convertToBasicType(renderer.getBackgroundColour())); this.persistProperty(uuid, "dataColour", DataType.STRING, converter.convertToBasicType(renderer.getDataColour())); this.persistProperty(uuid, "headerColour", DataType.STRING, converter.convertToBasicType(renderer.getHeaderColour())); } else if (child instanceof User) { User user = (User) child; // Constructor arguments this.persistProperty(uuid, "password", DataType.STRING, converter.convertToBasicType(user.getPassword())); this.persistProperty(uuid, "email", DataType.STRING, converter.convertToBasicType(user.getEmail())); this.persistProperty(uuid, "fullName", DataType.STRING, converter.convertToBasicType(user.getFullName())); } else if (child instanceof WabitConstantsContainer) { WabitConstantsContainer container = (WabitConstantsContainer) child; // Constructor argument this.persistProperty(uuid, "delegate", DataType.STRING, converter.convertToBasicType(container.getDelegate())); // Remaining properties this.persistProperty(uuid, "alias", DataType.STRING, converter.convertToBasicType(container.getAlias())); this.persistProperty(uuid, "position", DataType.STRING, converter.convertToBasicType(container.getPosition())); } else if (child instanceof WabitImage) { WabitImage image = (WabitImage) child; // Remaining properties this.persistProperty(uuid, "image", DataType.PNG_IMG, converter.convertToBasicType(image.getImage(), DataType.PNG_IMG)); } else if (child instanceof WabitItem) { WabitItem item = (WabitItem) child; // Constructor argument this.persistProperty(uuid, "delegate", DataType.STRING, converter.convertToBasicType(item.getDelegate())); // Remaining properties this.persistProperty(uuid, "alias", DataType.STRING, converter.convertToBasicType(item.getAlias())); this.persistProperty(uuid, "selected", DataType.INTEGER, converter.convertToBasicType(item.getSelected())); this.persistProperty(uuid, "where", DataType.STRING, converter.convertToBasicType(item.getWhere())); this.persistProperty(uuid, "groupBy", DataType.STRING, converter.convertToBasicType(item.getGroupBy())); this.persistProperty(uuid, "having", DataType.STRING, converter.convertToBasicType(item.getHaving())); this.persistProperty(uuid, "orderBy", DataType.STRING, converter.convertToBasicType(item.getOrderBy())); this.persistProperty(uuid, "orderByOrdering", DataType.INTEGER, converter.convertToBasicType(item.getOrderByOrdering())); this.persistProperty(uuid, "columnWidth", DataType.INTEGER, converter.convertToBasicType(item.getColumnWidth())); } else if (child instanceof WabitDataSource) { WabitDataSource ds = (WabitDataSource) child; // Constructor argument this.persistProperty(uuid, "SPDataSource", DataType.STRING, converter.convertToBasicType(ds.getSPDataSource())); } else if (child instanceof WabitJoin) { WabitJoin sqlJoin = ((WabitJoin) child); // Constructor arguments this.persistProperty(uuid, "query", DataType.REFERENCE, converter.convertToBasicType(sqlJoin.getQuery())); this.persistProperty(uuid, "delegate", DataType.STRING, converter.convertToBasicType(sqlJoin.getDelegate())); // Remaining properties this.persistProperty(uuid, "comparator", DataType.STRING, converter.convertToBasicType(sqlJoin.getComparator())); this.persistProperty(uuid, "leftColumnOuterJoin", DataType.BOOLEAN, converter.convertToBasicType(sqlJoin.isLeftColumnOuterJoin())); this.persistProperty(uuid, "rightColumnOuterJoin", DataType.BOOLEAN, converter.convertToBasicType(sqlJoin.isRightColumnOuterJoin())); } else if (child instanceof WabitOlapAxis) { WabitOlapAxis wabitOlapAxis = (WabitOlapAxis) child; // Constructor argument this.persistProperty(uuid, "ordinal", DataType.STRING, converter.convertToBasicType(wabitOlapAxis.getOrdinal())); // Remaining properties this.persistProperty(uuid, "nonEmpty", DataType.BOOLEAN, converter.convertToBasicType(wabitOlapAxis.isNonEmpty())); this.persistProperty(uuid, "sortEvaluationLiteral", DataType.STRING, converter.convertToBasicType(wabitOlapAxis.getSortEvaluationLiteral())); this.persistProperty(uuid, "sortOrder", DataType.STRING, converter.convertToBasicType(wabitOlapAxis.getSortOrder())); } else if (child instanceof WabitOlapSelection) { WabitOlapSelection wabitOlapSelection = (WabitOlapSelection) child; // Constructor argument this.persistProperty(uuid, "operator", DataType.STRING, converter.convertToBasicType(wabitOlapSelection.getOperator())); this.persistProperty(uuid, "uniqueMemberName", DataType.STRING, converter.convertToBasicType(wabitOlapSelection.getUniqueMemberName())); } else if (child instanceof WabitTableContainer) { WabitTableContainer wabitTableContainer = (WabitTableContainer) child; TableContainer tableContainer = (TableContainer) wabitTableContainer.getDelegate(); // Constructor arguments this.persistProperty(uuid, "delegate", DataType.STRING, converter.convertToBasicType(tableContainer)); // Remaining properties this.persistProperty(uuid, "alias", DataType.STRING, converter.convertToBasicType(tableContainer.getAlias())); this.persistProperty(uuid, "position", DataType.STRING, converter.convertToBasicType(tableContainer.getPosition())); } else if (child instanceof WabitWorkspace) { logger.info("Sending workspace created event"); //no current properties } else if (child instanceof ComboBoxSelector) { ComboBoxSelector cbs = (ComboBoxSelector) child; this.persistProperty(uuid, "sourceKey", DataType.STRING, converter.convertToBasicType(cbs.getSourceKey())); this.persistProperty(uuid, "staticValues", DataType.STRING, converter.convertToBasicType(cbs.getStaticValues())); this.persistProperty(uuid, "defaultValue", DataType.STRING, converter.convertToBasicType(cbs.getDefaultValue())); this.persistProperty(uuid, "alwaysIncludeDefaultValue", DataType.BOOLEAN, converter.convertToBasicType(cbs.isAlwaysIncludeDefaultValue())); } else if (child instanceof TextBoxSelector) { TextBoxSelector tbs = (TextBoxSelector) child; this.persistProperty(uuid, "defaultValue", DataType.STRING, converter.convertToBasicType(tbs.getDefaultValue())); } else if (child instanceof DateSelector) { DateSelector ds = (DateSelector) child; this.persistProperty(uuid, "defaultValue", DataType.STRING, converter.convertToBasicType((Date) ds.getDefaultValue())); } else { logger.debug("Cannot persist child of type " + child.getClass().getCanonicalName()); } if (child instanceof WabitObjectReportRenderer) { WabitObjectReportRenderer renderer = (WabitObjectReportRenderer) child; this.persistProperty(uuid, "content", DataType.REFERENCE, converter.convertToBasicType(renderer.getContent(), DataType.REFERENCE)); } // Persisting the name property last because WabitObjects such as ContentBox // have methods that calls setName on certain events or method calls. // We do not want those calls to affect the name property. However, this should // really only be a concern for reflective tests. this.persistProperty(uuid, "name", DataType.STRING, child.getName()); this.persistProperty(uuid, "parent", DataType.REFERENCE, converter.convertToBasicType(child.getParent())); this.transactionEnded(TransactionEvent.createEndTransactionEvent(this)); } public void childRemoved(SPChildEvent e) { logger.debug("wabitChildRemoved(" + e.getChildType() + ")"); e.getChild().removeSPListener(this); if (wouldEcho()) return; this.transactionStarted(TransactionEvent.createStartTransactionEvent(this, "Start of transaction triggered by wabitChildRemoved event")); this.objectsToRemove.add(new RemovedObjectEntry(e.getSource().getUUID(), e.getChild(), e.getIndex())); this.transactionEnded(TransactionEvent.createEndTransactionEvent(this)); } public void propertyChanged(PropertyChangeEvent evt) { if (wouldEcho()) return; this.transactionStarted(TransactionEvent.createStartTransactionEvent(this, "Creating start transaction event from propertyChange on object " + evt.getSource().getClass().getSimpleName() + " and property name " + evt.getPropertyName())); SPObject source = (SPObject) evt.getSource(); String uuid = source.getUUID(); String propertyName = evt.getPropertyName(); Object oldValue = evt.getOldValue(); Object newValue = evt.getNewValue(); PropertyDescriptor propertyDescriptor; try { propertyDescriptor = PropertyUtils.getPropertyDescriptor(source, propertyName); } catch (Exception ex) { this.rollback(); throw new RuntimeException(ex); } //Not persisting non-settable properties if (propertyDescriptor == null || propertyDescriptor.getWriteMethod() == null) { this.transactionEnded(TransactionEvent.createEndTransactionEvent(this)); return; } for (PropertyToIgnore ignoreProperty : ignoreList) { if (ignoreProperty.getPropertyName().equals(propertyName) && ignoreProperty.getClassType().isAssignableFrom(source.getClass())) { this.transactionEnded(TransactionEvent.createEndTransactionEvent(this)); return; } } //XXX special case that I want to remove even though I'm implementing it List<Object> additionalParams = new ArrayList<Object>(); if (source instanceof OlapQuery && propertyName.equals("currentCube")) { additionalParams.add(((OlapQuery) source).getOlapDataSource()); } DataType typeForClass = PersisterUtils.getDataType(newValue == null ? Void.class : newValue.getClass()); Object oldBasicType; Object newBasicType; oldBasicType = converter.convertToBasicType(oldValue, additionalParams.toArray()); newBasicType = converter.convertToBasicType(newValue, additionalParams.toArray()); logger.debug("Calling persistProperty on propertyChange"); this.persistProperty(uuid, propertyName, typeForClass, oldBasicType, newBasicType); this.transactionEnded(TransactionEvent.createEndTransactionEvent(this)); } private void persistProperty(String uuid, String propertyName, DataType propertyType, Object newValue) { logger.debug("persistProperty(" + uuid + ", " + propertyName + ", " + propertyType.name() + ", " + newValue + ", " + newValue + ")"); this.persistedProperties.put(uuid, new PersistedSPOProperty(uuid, propertyName, propertyType, newValue, newValue, true)); } private void persistProperty(String uuid, String propertyName, DataType propertyType, Object oldValue, Object newValue) { logger.debug("persistProperty(" + uuid + ", " + propertyName + ", " + propertyType.name() + ", " + oldValue + ", " + newValue + ")"); this.persistedProperties.put(uuid, new PersistedSPOProperty(uuid, propertyName, propertyType, oldValue, newValue, false)); } private void rollback() { if (this.headingToWinconsin) { // This happens when we pick up our own events. return; } if (eventSource == null || eventSource.isHeadingToWisconsin()) { // This means that the SessionPersister is cleaning his stuff and // we need to do the same. Close all current transactions... bla bla bla. this.objectsToRemoveRollbackList.clear(); this.persistedObjectsRollbackList.clear(); this.persistedPropertiesRollbackList.clear(); this.objectsToRemove.clear(); this.persistedObjects.clear(); this.persistedProperties.clear(); this.transactionCount = 0; target.rollback(); return; } this.headingToWinconsin = true; try { WabitSessionPersister.undoForSession(session, this.persistedObjectsRollbackList, this.persistedPropertiesRollbackList, this.objectsToRemoveRollbackList); } catch (SPPersistenceException e) { logger.error(e); } finally { this.objectsToRemoveRollbackList.clear(); this.persistedObjectsRollbackList.clear(); this.persistedPropertiesRollbackList.clear(); this.objectsToRemove.clear(); this.persistedObjects.clear(); this.persistedProperties.clear(); this.transactionCount = 0; this.headingToWinconsin = false; target.rollback(); } } private void commit() throws SPPersistenceException { logger.debug("commit(): transactionCount = " + transactionCount); if (transactionCount == 1) { try { logger.debug("Calling commit..."); //If nothing actually changed in the transaction do not send //the begin and commit to reduce server traffic. if (objectsToRemove.isEmpty() && persistedObjects.isEmpty() && persistedProperties.isEmpty()) return; this.objectsToRemoveRollbackList.clear(); this.persistedObjectsRollbackList.clear(); this.persistedPropertiesRollbackList.clear(); target.begin(); commitRemovals(); commitObjects(); commitProperties(); target.commit(); logger.debug("...commit completed."); } catch (Throwable t) { this.rollback(); throw new SPPersistenceException(null, t); } finally { this.objectsToRemove.clear(); this.objectsToRemoveRollbackList.clear(); this.persistedObjects.clear(); this.persistedObjectsRollbackList.clear(); this.persistedProperties.clear(); this.persistedPropertiesRollbackList.clear(); this.transactionCount = 0; } } else { transactionCount--; } } /** * Commits the persisted {@link WabitObject}s * * @throws SPPersistenceException */ private void commitObjects() throws SPPersistenceException { for (PersistedSPObject pwo : persistedObjects) { target.persistObject(pwo.getParentUUID(), pwo.getType(), pwo.getUUID(), pwo.getIndex()); this.persistedObjectsRollbackList.add(new PersistedObjectEntry(pwo.getParentUUID(), pwo.getUUID())); } } private void commitProperties() throws SPPersistenceException { logger.debug("commitProperties()"); for (Entry<String, PersistedSPOProperty> entry : persistedProperties.entries()) { PersistedSPOProperty wop = entry.getValue(); String uuid = entry.getKey(); if (wop.isUnconditional()) { target.persistProperty(uuid, wop.getPropertyName(), wop.getDataType(), wop.getNewValue()); } else { target.persistProperty(uuid, wop.getPropertyName(), wop.getDataType(), wop.getOldValue(), wop.getNewValue()); } this.persistedPropertiesRollbackList.add(new PersistedPropertiesEntry(uuid, wop.getPropertyName(), wop.getDataType(), wop.getOldValue())); } } private void commitRemovals() throws SPPersistenceException { logger.debug("commitRemovals()"); for (RemovedObjectEntry entry : this.objectsToRemove) { logger.debug("target.removeObject(" + entry.getParentUUID() + ", " + entry.getRemovedChild().getUUID() + ")"); target.removeObject(entry.getParentUUID(), entry.getRemovedChild().getUUID()); this.objectsToRemoveRollbackList.add(entry); } } }