Java tutorial
/** This file is part of the Zeidon Java Object Engine (Zeidon JOE). Zeidon JOE is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Zeidon JOE 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Zeidon JOE. If not, see <http://www.gnu.org/licenses/>. Copyright 2009-2015 QuinSoft */ package com.quinsoft.zeidon.standardoe; import java.io.IOException; import java.io.Writer; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import com.quinsoft.zeidon.EntityCursor.CursorStatus; import com.quinsoft.zeidon.SelectSet; import com.quinsoft.zeidon.SerializeOi; import com.quinsoft.zeidon.StreamWriter; import com.quinsoft.zeidon.View; import com.quinsoft.zeidon.WriteOiFlags; import com.quinsoft.zeidon.ZeidonException; import com.quinsoft.zeidon.objectdefinition.AttributeDef; import com.quinsoft.zeidon.objectdefinition.EntityDef; /** * @author DG * */ public class WriteOisToXmlStream implements StreamWriter { private ViewImpl currentView; private Writer writer; private EnumSet<WriteOiFlags> control; private boolean incremental; private final Set<ObjectInstance> ois = new HashSet<ObjectInstance>(); private int currentIndent; private SerializeOi options; @Override public void writeToStream(SerializeOi options, Writer writer) { List<View> viewList = options.getViewList(); // Create a set of all the OIs and turn off the record owner flag. The record owner // flag will be used to determine if a linked EI has been written to the stream. for (View view : viewList) { ObjectInstance oi = ((InternalView) view).getViewImpl().getObjectInstance(); ois.add(oi); for (EntityInstanceImpl ei = oi.getRootEntityInstance(); ei != null; ei = ei.getNextTwin()) ei.setRecordOwner(false); } currentView = ((InternalView) viewList.get(0)).getViewImpl(); this.options = options; this.writer = writer; control = options.getFlags(); incremental = this.control.contains(WriteOiFlags.INCREMENTAL); if (viewList.size() > 1) { startElement("zOIs"); currentIndent++; } for (View view : viewList) { currentView = ((InternalView) view).getViewImpl(); writeViewToStream(); } if (viewList.size() > 1) { currentIndent--; endElement("zOIs"); } } private void write(String string) { try { writer.write(string); } catch (IOException e) { throw ZeidonException.wrapException(e).appendMessage("Attempting to write: %s", StringUtils.substring(string, 0, 100)); } } private void write(String format, Object... strings) { if (strings == null || strings.length == 0) { write(format); } else { write(String.format(format, strings)); } } private void writeIndent() { if (options.isCompressed()) return; for (int i = 0; i < currentIndent; i++) write(" "); } private void startElement(final String elementName, final Object... attributes) { startElement(elementName, null, false, attributes); } private void startElement(final String elementName, final String value, final boolean close, final Object... attributes) { assert attributes.length % 2 == 0 : "Illegal number of attributes; should be an even number."; writeIndent(); write("<"); write(elementName); if (attributes != null && attributes.length > 0) { for (int i = 0; i < attributes.length; i += 2) { // Don't bother printing null attributes. if (attributes[i + 1] == null) continue; String esc = StringEscapeUtils.escapeXml(attributes[i + 1].toString()); // Don't bother printing if it's empty. if (!StringUtils.isBlank(esc)) write(" %s=\"%s\"", attributes[i], esc); } } if (value != null) { String esc = StringEscapeUtils.escapeXml(value); write(">%s</%s>", esc, elementName); if (!options.isCompressed()) write("\n"); } else { if (close) write("/>"); else write(">"); if (!options.isCompressed()) write("\n"); } } private void endElement(final String elementName) { writeIndent(); write("</%s>", elementName); if (!options.isCompressed()) write("\n"); } /** * If this EI is linked with another EI in the OI set then this returns the record owner. * If no record owner, returns EI. * * @param ei * @return */ private EntityInstanceImpl findLinkedRecordOwner(EntityInstanceImpl ei) { // Keep track of whether we found another EI linked with this one. boolean foundLinked = false; // Run through the list of the other linked instances. for (EntityInstanceImpl linked : ei.getLinkedInstances()) { if (ois.contains(linked.getObjectInstance())) { foundLinked = true; if (linked.isRecordOwner()) return linked; } } // If we get here then we didn't find a record owner. if foundLinked is true // then we did find a linked EI. if (foundLinked) return ei; // Didn't find any EI's that are linked with ei. return null; } private void writeEntity(final EntityInstanceImpl ei) { final EntityDef entityDef = ei.getEntityDef(); currentIndent = entityDef.getDepth(); boolean writeAttributes = true; if (incremental) { EntityCursorImpl cursor = currentView.cursor(entityDef); // Check to see if the current ei is the selected EI. We first check the status because // calling getEntityInstance() could potentially trigger a lazy-load. boolean selected = options.isWithCursors() && cursor.getStatus() == CursorStatus.SET && cursor.getEntityInstance() == ei; EntityInstanceImpl recordOwner = findLinkedRecordOwner(ei); String entityKey = null; String isLinkedSource = null; if (recordOwner != null) { if (recordOwner == ei) { // TODO: validate that ei.entityDef has all the attributes in the shared // attribute hash. ei.setRecordOwner(true); isLinkedSource = "Y"; entityKey = Long.toString(ei.getEntityKey()); } else { // Write the entity key of the record owner. entityKey = Long.toString(ei.getEntityKey()); writeAttributes = false; } } StringBuilder lazyLoaded = new StringBuilder(); if (ei.hasLoadedLazyChildren()) { for (EntityDef def : ei.getEntitiesLoadedLazily()) lazyLoaded.append(",").append(def.getName()); lazyLoaded.deleteCharAt(0); } startElement(entityDef.getName(), "created", yesNull(ei.isCreated()), "delete", yesNull(ei.isDeleted()), "updated", yesNull(ei.isUpdated()), "included", yesNull(ei.isIncluded()), "excluded", yesNull(ei.isExcluded()), "incomplete", yesNull(ei.isIncomplete()), "selected", yesNull(selected), "readonly", yesNull(currentView.isReadOnly()), "isLinkedSource", isLinkedSource, "entityKey", entityKey, "lazyLoaded", lazyLoaded.toString()); } else startElement(entityDef.getName()); currentIndent++; Object[] attrIncr = new Object[] { "updated", null }; if (writeAttributes) { for (AttributeDef attributeDef : ei.getNonNullAttributeList()) { AttributeValue attrib = ei.getInternalAttribute(attributeDef); String value; value = attrib.getString(currentView.getTask(), attributeDef); if (incremental) { attrIncr[1] = yesNull(attrib.isUpdated()); startElement(attributeDef.getName(), value, true, attrIncr); } else startElement(attributeDef.getName(), value, true, (Object[]) null); } } // Loop through the children and add them. If 'incremental' is true then // we want hidden entities. boolean first = true; for (EntityInstanceImpl child : ei.getDirectChildren(incremental, false)) { if (first) { if (!options.isCompressed()) write("\n"); first = false; } writeEntity(child); } currentIndent--; endElement(entityDef.getName()); } private void writeViewToStream() { SelectSet rootSelectSet = null; Map<Long, SelectSet> sets = options.getRootSelectSets(); if (sets != null) rootSelectSet = sets.get(currentView.getOiId()); // write( "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" ); startElement("zOI", "objectName", currentView.getLodDef().getName(), "appName", currentView.getApplication().getName(), "increFlags", yesNo(incremental), "totalRootCount", currentView.getTotalRootCount()); currentIndent++; for (EntityInstanceImpl ei = currentView.getObjectInstance().getRootEntityInstance(); ei != null; ei = ei .getNextTwin()) { // If we have a root select set and the EI is not selected then skip it. if (rootSelectSet != null && rootSelectSet.isSelected(ei)) continue; if (incremental || !ei.isHidden()) writeEntity(ei); } currentIndent--; endElement("zOI"); } private String yesNull(boolean b) { return b ? "Y" : ""; } private String yesNo(boolean b) { return b ? "Y" : "N"; } }