org.linkedin.glu.provisioner.plan.api.Plan.java Source code

Java tutorial

Introduction

Here is the source code for org.linkedin.glu.provisioner.plan.api.Plan.java

Source

/*
 * Copyright (c) 2010-2010 LinkedIn, Inc
 *
 * 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 org.linkedin.glu.provisioner.plan.api;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.linkedin.util.xml.XMLIndent;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.LinkedHashMap;

/**
 * A plan is represented by the step to execute and the dependency graph (between leaves).
 *
 * @author ypujante@linkedin.com
 */
public class Plan<T> {
    private final Map<String, Object> _metadata = new LinkedHashMap<String, Object>();
    private final IStep<T> _step;

    // cache
    private volatile Collection<LeafStep<T>> _leafSteps = null;

    /**
     * Constructor
     */
    public Plan(Map<String, Object> metadata, IStep<T> step) {
        if (metadata == null && step != null)
            metadata = step.getMetadata();
        if (metadata != null)
            _metadata.putAll(metadata);
        _step = step;
    }

    /**
     * Builds an empty plan
     */
    public Plan() {
        this(null, null);
    }

    /**
     * Constructor
     */
    public Plan(IStep<T> step) {
        this(step == null ? null : step.getMetadata(), step);
    }

    public void setMetadata(String name, Object value) {
        _metadata.put(name, value);
    }

    public Map<String, Object> getMetadata() {
        return _metadata;
    }

    public void setMetadata(Map<String, Object> metadata) {
        if (metadata != null) {
            _metadata.putAll(metadata);
        }
    }

    public String getName() {
        return (String) _metadata.get("name");
    }

    /**
     * Change the name of a plan
     */
    public void setName(String name) {
        _metadata.put("name", name);
    }

    /**
     * Change the name of a plan
     */
    public void setId(String id) {
        _metadata.put("id", id);
    }

    public String getId() {
        String id = (String) _metadata.get("id");

        if (id == null) {
            if (_step == null)
                id = Integer.toHexString(System.identityHashCode(this));
            else
                id = getStep().getId();
        }

        return id;
    }

    public IStep<T> getStep() {
        return _step;
    }

    /**
     * @return all the leaf steps of this plan.
     */
    public Collection<LeafStep<T>> getLeafSteps() {
        // implementation note: not synchronized on purpose. The variable is volatile so if 2 threads
        // happens to call this at the same time, they may compute the result twice but since the
        // object is immutable it is not an issue.
        if (_leafSteps == null) {
            _leafSteps = doGetLeafSteps();
        }
        return _leafSteps;
    }

    /**
     * @return all the leaf steps of this plan.
     */
    private Collection<LeafStep<T>> doGetLeafSteps() {
        final Collection<LeafStep<T>> leaves = new ArrayList<LeafStep<T>>();

        if (_step != null) {
            _step.acceptVisitor(new IStepVisitor<T>() {
                @Override
                public void startVisit() {
                }

                @Override
                public void visitLeafStep(LeafStep<T> tLeafStep) {
                    leaves.add(tLeafStep);
                }

                @Override
                public IStepVisitor<T> visitSequentialStep(SequentialStep<T> tSequentialStep) {
                    return this;
                }

                @Override
                public IStepVisitor<T> visitParallelStep(ParallelStep<T> parallelStep) {
                    return this;
                }

                @Override
                public void endVisit() {
                }
            });
        }

        return leaves;
    }

    /**
     * @return <code>true</code> if this plan has any leaf step
     */
    public boolean hasLeafSteps() {
        return !getLeafSteps().isEmpty();
    }

    /**
     * @return the number of leaf steps
     */
    public int getLeafStepsCount() {
        return getLeafSteps().size();
    }

    /**
     * @return a plan builder representing this plan (usually used to do minor modifications to the
     *         plan, like adding some steps or removing some).
     */
    public IPlanBuilder<T> toPlanBuilder() {
        return toPlanBuilder(StepFilters.<T>acceptAll());
    }

    /**
     * Same as {@link #toPlanBuilder()} except it also filters out unwanted steps.
     *
     * @param filter the filter to filter out unwanted steps
     * @return a new plan builder
     */
    public IPlanBuilder<T> toPlanBuilder(IStepFilter<T> filter) {
        PlanBuilder<T> builder = new PlanBuilder<T>();
        builder.setMetadata(_metadata);

        if (_step != null)
            _step.acceptVisitor(new CompositeStepBuilderVisitor<T>(builder, filter));

        return builder;
    }

    /**
     * @return an empty plan builder based of the dependencies in this plan.
     */
    public IPlanBuilder<T> createEmptyPlanBuilder() {
        return new PlanBuilder<T>();
    }

    /**
     * @return an xml representation of the plan
     */
    public String toXml() {
        return toXml(null);
    }

    /**
     * @return an xml representation of the plan
     */
    public String toXml(Map<String, Object> context) {
        XmlStepVisitor<T> visitor = new XmlStepVisitor<T>();

        XMLIndent xml = visitor.getXml();

        xml.addXMLDecl("1.0");

        Map<String, Object> attributes = new LinkedHashMap<String, Object>();
        attributes.putAll(_metadata);

        if (context != null) {
            attributes.putAll(context);
        }

        if (_step != null) {
            xml.addOpeningTag("plan", attributes);
            _step.acceptVisitor(visitor);
            xml.addClosingTag("plan");
        } else {
            xml.addEmptyTag("plan", attributes);
        }

        return xml.getXML();
    }

    public JSONObject toJson() {
        JSONObject json = new JSONObject();

        try {
            json.put("metadata", getMetadata());
            if (_step != null) {
                JsonStepVisitor<T> visitor = new JsonStepVisitor<T>(json);
                _step.acceptVisitor(visitor);
            }
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }

        return json;
    }

    @Override
    public String toString() {
        return toXml();
    }
}