All Downloads are FREE. Search and download functionalities are using the official Maven repository.

juzu.impl.metamodel.MetaModelObject Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright 2013 eXo Platform SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package juzu.impl.metamodel;

import juzu.impl.common.JSON;
import juzu.impl.compiler.ProcessingContext;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/** @author Julien Viet */
public class MetaModelObject implements Serializable {

  /** The children. */
  private final HashMap, MetaModelObject> children = new HashMap, MetaModelObject>();

  /** The parents. */
  private final HashMap> parents = new HashMap>();

  /** . */
  protected MetaModel metaModel;

  public MetaModelObject() {
  }

  public final Collection getParents() {
    return parents.keySet();
  }

  public final  O getChild(Key key) {
    MetaModelObject child = children.get(key);
    if (child != null) {
      return key.getType().cast(child);
    }
    else {
      return null;
    }
  }

  public final Collection getChildren() {
    return getChildren(MetaModelObject.class);
  }

  public final  Collection> getKeys(Class filter) {
    ArrayList> list = new ArrayList>(children.size());
    for (Key key : children.keySet()) {
      if (filter.isAssignableFrom(key.getType())) {
        // Yes : not great
        list.add((Key)key);
      }
    }
    return list;
  }

  public final  Collection getChildren(Class filter) {
    ArrayList list = new ArrayList(children.size());
    for (MetaModelObject child : children.values()) {
      if (filter.isInstance(child)) {
        list.add(filter.cast(child));
      }
    }
    return list;
  }

  public final  O addChild(Key key, O child) throws IllegalArgumentException, IllegalStateException {
    return (O)_addChild(key, child);
  }

  private MetaModelObject _addChild(Key key, MetaModelObject child) throws IllegalArgumentException, IllegalStateException {
    if (closure(child, new HashSet()).contains(this)) {
      throw new IllegalStateException("Cycle detected");
    }
    else {
      if (child.parents.containsKey(this)) {
        throw new IllegalArgumentException("Child " + child + " cannot be added for key " + key + " because parent already contains it");
      } else {
        if (children.containsKey(key)) {
          throw new IllegalArgumentException("Object " + this + " has already a child named "  + key);
        }

        if (child.parents.size() == 0) {

          // Context
          if (this instanceof MetaModel) {
            child.metaModel = (MetaModel)this;
          } else {
            child.metaModel = metaModel;
          }

          // Post construct
          child.postConstruct();
        }

        // Wire
        children.put(key, child);
        child.parents.put(this, key);


        // Post attach
        child.postAttach(this);

        //
        return child;
      }
    }
  }

  public final  O removeChild(Key key) {
    MetaModelObject child = children.get(key);
    if (child != null) {
      if (child.parents.containsKey(this)) {

        // Detect orphan
        boolean remove = child.parents.size() == 1;

        //
        if (remove) {

          // Remove children recursively
          if (child.children.size() > 0) {
            for (Key key2 : new ArrayList>(child.children.keySet())) {
              child.removeChild(key2);
            }
          }
        }

        // Pre detach
        child.preDetach(this);

        // Break relationship
        if (children.remove(key) == null) {
          throw new AssertionError("Internal bug");
        }
        if (child.parents.remove(this) == null) {
          throw new AssertionError("Internal bug");
        }

        //
        if (remove) {
          // Remove callback
          child.preRemove();

          // Set model to null
          child.metaModel = null;
        }

        //
        return key.getType().cast(child);
      }
      else {
        throw new AssertionError("Internal bug");
      }
    }
    else {
      throw new IllegalArgumentException("The element is not child of this node");
    }
  }

  public final void remove() {
    // We remove a node by detaching it from all its parents
    while (parents.size() > 0) {
      Iterator>> iterator = parents.entrySet().iterator();
      Map.Entry> entry = iterator.next();
      MetaModelObject parent = entry.getKey();
      Key key = entry.getValue();
      parent.removeChild(key);
    }
  }

  public void queue(MetaModelEvent event) {
    metaModel.queue(event);
  }

  protected void postConstruct() {
  }

  protected void preDetach(MetaModelObject parent) {
  }

  protected void postAttach(MetaModelObject parent) {
  }

  protected void preRemove() {
  }

  public JSON toJSON() {
    return new JSON();
  }

  @Override
  public String toString() {
    return getClass().getSimpleName() + "[" + toJSON() + "]";
  }

  private Set closure(MetaModelObject node, Set closure) {
    if (!closure.contains(node)) {
      closure.add(node);
      for (MetaModelObject child : node.children.values()) {
        closure(child, closure);
      }
    }
    return closure;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy