Package org.projectforge.gantt

Source Code of org.projectforge.gantt.GanttChartDao$MyRootElement

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition 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; version 3 of the License.
//
// This community edition 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 org.projectforge.gantt;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.projectforge.common.BeanHelper;
import org.projectforge.common.NumberHelper;
import org.projectforge.core.BaseDao;
import org.projectforge.task.TaskDO;
import org.projectforge.task.TaskDao;
import org.projectforge.task.TaskTree;
import org.projectforge.user.PFUserContext;
import org.projectforge.user.PFUserDO;
import org.projectforge.user.UserDao;
import org.projectforge.user.UserRightId;
import org.projectforge.xml.stream.AliasMap;
import org.projectforge.xml.stream.ProjectForgeRootElement;
import org.projectforge.xml.stream.Status;
import org.projectforge.xml.stream.XmlConstants;
import org.projectforge.xml.stream.XmlField;
import org.projectforge.xml.stream.XmlHelper;
import org.projectforge.xml.stream.XmlObject;
import org.projectforge.xml.stream.XmlObjectReader;
import org.projectforge.xml.stream.XmlObjectWriter;
import org.projectforge.xml.stream.XmlRegistry;
import org.projectforge.xml.stream.converter.ISODateConverter;

/**
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
public class GanttChartDao extends BaseDao<GanttChartDO>
{
  public static final UserRightId USER_RIGHT_ID = UserRightId.PM_GANTT;

  private static final String[] ADDITIONAL_SEARCH_FIELDS = new String[] { "task.title", "task.taskpath", "owner.username",
      "owner.firstname", "owner.lastname"};

  private TaskDao taskDao;

  private UserDao userDao;

  private Field[] taskFields = BeanHelper.getDeclaredPropertyFields(TaskDO.class);

  /**
   * Mapping of GanttTask fields to TaskDO fields.
   */
  private Map<String, String> fieldMapping;

  private AliasMap xmlGanttObjectAliasMap;

  public GanttChartDao()
  {
    super(GanttChartDO.class);
    userRightId = USER_RIGHT_ID;
    AccessibleObject.setAccessible(taskFields, true);
    fieldMapping = new HashMap<String, String>();
    fieldMapping.put("predecessor", "ganttPredecessor");
    fieldMapping.put("predecessorOffset", "ganttPredecessorOffset");
    fieldMapping.put("relationType", "ganttRelationType");
    fieldMapping.put("type", "ganttObjectType");
  }

  @Override
  protected String[] getAdditionalSearchFields()
  {
    return ADDITIONAL_SEARCH_FIELDS;
  }

  @Override
  protected void onSaveOrModify(final GanttChartDO obj)
  {
    final String styleAsXml = XmlObjectWriter.writeAsXml(obj.getStyle());
    obj.setStyleAsXml(styleAsXml);
    final String settingsAsXml = XmlObjectWriter.writeAsXml(obj.getSettings());
    obj.setSettingsAsXml(settingsAsXml);
  }

  public String exportAsXml(final GanttChart ganttChart)
  {
    return exportAsXml(ganttChart, false);
  }

  @XmlObject(alias = "ProjectForge")
  public class MyRootElement extends ProjectForgeRootElement
  {
    @SuppressWarnings("unused")
    private GanttChart ganttChart;
  }

  public String exportAsXml(final GanttChart ganttChart, final boolean prettyFormat)
  {
    final Document document = DocumentHelper.createDocument();
    final XmlObjectWriter writer = getXmlGanttObjectWriter();
    final XmlRegistry xmlRegistry = new XmlRegistry();
    xmlRegistry.registerConverter(Date.class, new ISODateConverter());
    writer.setXmlRegistry(xmlRegistry);
    final MyRootElement root = new MyRootElement();
    root.ganttChart = ganttChart;
    root.setCreated().setTimeZone(PFUserContext.getTimeZone()).setVersion("1.0");
    final Element element = writer.write(document, root);
    // Now, remove all elements with no information from the DOM:
    final String xml;
    if (removeUnnecessaryElements(element) == true) {
      // Nothing to write (no further information in the GanttObject tree given).
      xml = "";
    } else {
      xml = XmlHelper.toString(element, prettyFormat);
    }
    return XmlHelper.XML_HEADER + xml;
  }

  /**
   * Writes all Gantt objects as tree as xml. Writes only those values which are different to the original values of the task with the same
   * id.
   * @param obj
   * @param rootObject
   */
  public void writeGanttObjects(final GanttChartDO obj, final GanttTask rootObject)
  {
    final Document document = DocumentHelper.createDocument();
    final Element element = getXmlGanttObjectWriter().write(document, rootObject);
    // Now, remove all elements with no information from the DOM:
    final String xml;
    if (removeUnnecessaryElements(element) == true) {
      // Nothing to write (no further information in the GanttObject tree given).
      xml = "";
    } else {
      xml = XmlHelper.toString(element);
    }
    obj.setGanttObjectsAsXml(xml);
  }

  /**
   * Removes all unnecessary GanttObject elements from the DOM (those without any information rather than the id).
   */
  private boolean removeUnnecessaryElements(final Element element)
  {
    if (CollectionUtils.isNotEmpty(element.elements()) == true) {
      for (final Object childObj : element.elements()) {
        final Element child = (Element) childObj;
        if (removeUnnecessaryElements(child) == true) {
          element.remove(child);
        }
      }
    }
    if (CollectionUtils.isNotEmpty(element.elements()) == true) {
      // Element has descendants.
      return false;
    }
    if (StringUtils.isBlank(element.getText()) == false) {
      // Element has non blank content.
      return false;
    }
    // Element has no descendants:
    if (CollectionUtils.isEmpty(element.attributes()) == true) {
      // Element has no attributes.
      return true;
    }
    if ("predecessor".equals(element.getName()) == true) {
      if (element.attribute(XmlObjectWriter.ATTR_ID) != null) {
        // Describes a complete Gantt task which is referenced, so full output is needed.
        return false;
      } else {
        final Attribute idAttr = element.attribute("id");
        final Attribute refIdAttr = element.attribute(XmlObjectWriter.ATTR_REF_ID);
        element.setAttributes(null);
        if (refIdAttr != null) {
          element.addAttribute(XmlObjectWriter.ATTR_REF_ID, refIdAttr.getValue());
        } else if (idAttr != null) {
          // External reference (no ref-id, but task id):
          element.addAttribute("id", idAttr.getValue());
        } else {
          // Should not occur.
          return true;
        }
        return false;
      }
    } else if (element.attributes().size() == 1 && element.attribute("id") != null) {
      // Element has only id attribute and is not a predecessor definition for tasks outside the current Gantt object tree.
      return true;
    }
    return false;
  }

  /**
   * Reads all Gantt objects as tree from xml and TaskTree.
   * @param obj
   * @return The root object of the read xml data.
   */
  public GanttChartData readGanttObjects(final GanttChartDO obj)
  {
    final TaskTree taskTree = taskDao.getTaskTree();
    final GanttChartData ganttChartData = Task2GanttTaskConverter.convertToGanttObjectTree(taskTree, obj.getTask());
    final XmlObjectReader reader = new XmlObjectReader() {
      @Override
      protected Object newInstance(final Class< ? > clazz, final Element el, final String attrName, final String attrValue)
      {
        if ("predecessor".equals(attrName) == true && XmlConstants.NULL_IDENTIFIER.equals(attrValue) == true) {
          // Field should set to null.
          return Status.IGNORE;
        }
        if (GanttTask.class.isAssignableFrom(clazz) == true) {
          final GanttTask ganttObject = getGanttObject(taskTree, ganttChartData, el);
          if (ganttObject == null) {
            return new GanttTaskImpl(); // Gantt task not related to a ProjectForge task.
          }
          return ganttObject;
        } else if (Collection.class.isAssignableFrom(clazz) == true) {
          final GanttTask ganttObject = getGanttObject(taskTree, ganttChartData, el.getParent());
          if (ganttObject != null && ganttObject.getChildren() != null) {
            return ganttObject.getChildren();
          }
        }
        return null;
      }

      @Override
      protected boolean addCollectionEntry(final Collection< ? > col, final Object obj, final Element el)
      {
        if (obj instanceof GanttTask == false) {
          return false;
        }
        final GanttTask ganttTask = (GanttTask)obj;
        if (ganttChartData.findById(ganttTask.getId()) != null) {
          // GanttTask already added to the Gantt object tree.
          return true;
        }
        if (taskTree.getTaskById((Integer)ganttTask.getId()) != null) {
          // External task, so ignore it:
          return true;
        }
        return false;
      }

      @Override
      protected void setField(final Field field, final Object obj, final Object value, final Element element, final String key,
          final String attrValue)
      {
        if (XmlConstants.NULL_IDENTIFIER.equals(attrValue) == true) {
          // Overwrite value from task with null.
          setField(field, obj, null);
          return;
        }
        super.setField(field, obj, value, element, key, attrValue);
      }

    };
    reader.setAliasMap(getXmlGanttObjectAliasMap()).setIgnoreEmptyCollections(true);
    reader.read(obj.getGanttObjectsAsXml()); // Ignore the return value. If the task tree has changed, the task tree of root rules.
    return ganttChartData;
  }

  private GanttTask getGanttObject(final TaskTree taskTree, final GanttChartData ganttChartData, final Element el)
  {
    final String idString = el.attributeValue("id");
    final Integer id = NumberHelper.parseInteger(idString);
    GanttTask ganttObject = ganttChartData.findById(id);
    if (ganttObject == null) {
      ganttObject = ganttChartData.ensureAndGetExternalGanttObject(taskTree.getTaskById(id));
    }
    return ganttObject;
  }

  @Override
  protected void afterLoad(final GanttChartDO obj)
  {
    final XmlObjectReader reader = new XmlObjectReader();
    reader.initialize(GanttChartStyle.class);
    reader.initialize(GanttChartSettings.class);
    final String styleAsXml = obj.getStyleAsXml();
    final GanttChartStyle style;
    if (StringUtils.isEmpty(styleAsXml) == true) {
      style = new GanttChartStyle();
    } else {
      style = (GanttChartStyle) reader.read(styleAsXml);
    }
    obj.setStyle(style);
    final String settingsAsXml = obj.getSettingsAsXml();
    final GanttChartSettings settings;
    if (StringUtils.isEmpty(settingsAsXml) == true) {
      settings = new GanttChartSettings();
    } else {
      settings = (GanttChartSettings) reader.read(settingsAsXml);
    }
    obj.setSettings(settings);
  }

  private AliasMap getXmlGanttObjectAliasMap()
  {
    if (this.xmlGanttObjectAliasMap == null) {
      this.xmlGanttObjectAliasMap = new AliasMap();
      this.xmlGanttObjectAliasMap.put(GanttTaskImpl.class, "ganttObject");
    }
    return this.xmlGanttObjectAliasMap;
  }

  /**
   * Ignores all field values in output which are equal to the values of the corresponding task.
   */
  private XmlObjectWriter getXmlGanttObjectWriter()
  {
    final XmlObjectWriter xmlGanttObjectWriter = new XmlObjectWriter() {
      @Override
      protected boolean ignoreField(final Object obj, final Field field)
      {
        if (super.ignoreField(obj, field) == true) {
          return true;
        }
        if (obj instanceof GanttTask) {
          final TaskTree taskTree = taskDao.getTaskTree();
          final String fieldName = field.getName();
          if ("id".equals(fieldName) == true) {
            // Id should always be equals and needed in output for the identification of the gantt object.
            return false;
          }
          if ("description".equals(fieldName) == true) {
            return true;
          }
          final GanttTask ganttObject = (GanttTask) obj;
          final TaskDO task = taskTree.getTaskById((Integer) ganttObject.getId());
          if (task != null) {
            if ("predecessor".equals(field.getName()) == true) {
              // Predecessor unmodified?
              return NumberHelper.isEqual((Integer) ganttObject.getPredecessorId(), task.getGanttPredecessorId());
            }
            String taskFieldname = fieldMapping.get(fieldName);
            if (taskFieldname == null) {
              taskFieldname = fieldName;
            }
            for (final Field taskField : taskFields) {
              if (taskFieldname.equals(taskField.getName()) == true) {
                final Object value = BeanHelper.getFieldValue(obj, field);
                final Object taskValue = BeanHelper.getFieldValue(task, taskField);
                if (value instanceof BigDecimal) {
                  // Needed, because 10.0 is not equal to 10.000 (if scale is different).
                  return NumberHelper.isEqual((BigDecimal) value, (BigDecimal) taskValue);
                }
                return ObjectUtils.equals(value, taskValue) == true;
              }
            }
          }
        }
        return false;
      }

      @Override
      protected void writeField(final Field field, final Object obj, final Object fieldValue, final XmlField annotation,
          final Element element)
      {
        if (GanttTask.class.isAssignableFrom(field.getDeclaringClass()) == true) {
          final String fieldName = field.getName();
          if ("id".equals(fieldName) == false) {
            final TaskTree taskTree = taskDao.getTaskTree();
            final GanttTask ganttObject = (GanttTask) obj;
            final TaskDO task = taskTree.getTaskById((Integer) ganttObject.getId());
            if (task != null) {
              String taskFieldname = fieldMapping.get(fieldName);
              if (taskFieldname == null) {
                taskFieldname = fieldName;
              }
              for (final Field taskField : taskFields) {
                if (taskFieldname.equals(taskField.getName()) == true) {
                  final Object value = BeanHelper.getFieldValue(obj, field);
                  final Object taskValue = BeanHelper.getFieldValue(task, taskField);
                  if (taskValue != null && value == null) {
                    // Reader should interpret this as null, so value from task will be overwritten by null.
                    element.addAttribute(field.getName(), XmlConstants.NULL_IDENTIFIER);
                    return;
                  }
                }
              }
            }
          }
        }
        super.writeField(field, obj, fieldValue, annotation, element);
      }
    };
    xmlGanttObjectWriter.setAliasMap(getXmlGanttObjectAliasMap());
    return xmlGanttObjectWriter;
  }

  /**
   * @param ganttChart
   * @param taskId If null, then task will be set to null;
   * @see TaskTree#getTaskById(Integer)
   */
  public void setTask(final GanttChartDO ganttChart, final Integer taskId)
  {
    final TaskDO task = taskDao.getOrLoad(taskId);
    ganttChart.setTask(task);
  }

  /**
   * @param sheet
   * @param userId If null, then task will be set to null;
   * @see BaseDao#getOrLoad(Integer)
   */
  public void setOwner(final GanttChartDO ganttChart, final Integer userId)
  {
    final PFUserDO user = userDao.getOrLoad(userId);
    ganttChart.setOwner(user);
  }

  @Override
  public GanttChartDO newInstance()
  {
    return new GanttChartDO().setSettings(new GanttChartSettings()).setStyle(new GanttChartStyle());
  }

  public void setTaskDao(TaskDao taskDao)
  {
    this.taskDao = taskDao;
  }

  public void setUserDao(final UserDao userDao)
  {
    this.userDao = userDao;
  }
}
TOP

Related Classes of org.projectforge.gantt.GanttChartDao$MyRootElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.