public static <T extends ProcessNode<T, M>, M extends ProcessModelBase<T, M>> M deserialize(
      final DeserializationFactory<T, M> factory, final M processModel, final XmlReader in)
      throws XmlException {

    XmlReaderUtil.skipPreamble(in);
    final QName elementName = ELEMENTNAME;
    assert XmlReaderUtil.isElement(in, elementName)
        : "Expected " + elementName + " but found " + in.getLocalName();
    for (int i = in.getAttributeCount() - 1; i >= 0; --i) {
      processModel.deserializeAttribute(
          in.getAttributeNamespace(i), in.getAttributeLocalName(i), in.getAttributeValue(i));
    }

    EventType event = null;
    loop:
    while (in.hasNext() && event != XmlStreaming.END_ELEMENT) {
      switch ((event = in.next())) {
        case START_ELEMENT:
          if (processModel.deserializeChild(factory, in)) {
            continue loop;
          }
          XmlReaderUtil.unhandledEvent(in);
          break;
        case TEXT:
        case CDSECT:
          if (false) {
            continue loop;
          }
        default:
          XmlReaderUtil.unhandledEvent(in);
      }
    }

    for (final T node : processModel.getModelNodes()) {
      for (final Identifiable pred : node.getPredecessors()) {
        final T predNode = processModel.getNode(pred);
        if (predNode != null) {
          predNode.addSuccessor(node);
        }
      }
    }
    return processModel;
  }
 public boolean deserializeChild(
     final DeserializationFactory<T, M> factory, @NotNull final XmlReader in) throws XmlException {
   if (ProcessConsts.Engine.NAMESPACE.equals(in.getNamespaceUri())) {
     switch (in.getLocalName().toString()) {
       case EndNode.ELEMENTLOCALNAME:
         factory.deserializeEndNode(asM(), in);
         return true;
       case Activity.ELEMENTLOCALNAME:
         factory.deserializeActivity(asM(), in);
         return true;
       case StartNode.ELEMENTLOCALNAME:
         factory.deserializeStartNode(asM(), in);
         return true;
       case Join.ELEMENTLOCALNAME:
         factory.deserializeJoin(asM(), in);
         return true;
       case Split.ELEMENTLOCALNAME:
         factory.deserializeSplit(asM(), in);
         return true;
     }
   }
   return false;
 }