001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 *
012 * $Id$
013 */
014
015package org.nuxeo.runtime.deploy;
016
017import org.apache.commons.logging.Log;
018import org.apache.commons.logging.LogFactory;
019
020/**
021 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
022 */
023public abstract class ExtensibleContribution extends Contribution {
024
025    private static final Log log = LogFactory.getLog(ExtensibleContribution.class);
026
027    protected ExtensibleContribution baseContribution;
028
029    protected String baseContributionId;
030
031    /**
032     * Copy this contribution data over the given one.
033     * <p>
034     * Warn that the copy must be done deeply - you should clone every element in any collection you have. This is to
035     * avoid merging data you copy into the base contribution and breaking subsequent merging operations.
036     * <p>
037     * The baseContributionId and contributionId fields should not be copied since their are copied by the base classes
038     * implementation.
039     */
040    protected abstract void copyOver(ExtensibleContribution contrib);
041
042    public String getBaseContributionId() {
043        return baseContributionId;
044    }
045
046    public void setBaseContribution(ExtensibleContribution baseContribution) {
047        this.baseContribution = baseContribution;
048    }
049
050    public void setBaseContributionId(String baseContributionId) {
051        this.baseContributionId = baseContributionId;
052    }
053
054    @Override
055    public void resolve(ContributionManager mgr) {
056        if (baseContributionId != null) {
057            baseContribution = (ExtensibleContribution) mgr.getResolved(baseContributionId);
058        }
059    }
060
061    @Override
062    public void unresolve(ContributionManager mgr) {
063        baseContribution = null;
064    }
065
066    public ExtensibleContribution getBaseContribution() {
067        return baseContribution;
068    }
069
070    public ExtensibleContribution getRootContribution() {
071        return baseContribution == null ? this : baseContribution.getRootContribution();
072    }
073
074    public boolean isRootContribution() {
075        return baseContribution == null;
076    }
077
078    protected ExtensibleContribution getMergedContribution() {
079        if (baseContribution == null) {
080            return clone();
081        }
082        ExtensibleContribution mc = baseContribution.getMergedContribution();
083        copyOver(mc);
084        mc.contributionId = contributionId;
085        mc.baseContributionId = baseContributionId;
086        return mc;
087    }
088
089    @Override
090    public void install(ManagedComponent comp) {
091        install(comp, getMergedContribution());
092    }
093
094    @Override
095    public void uninstall(ManagedComponent comp) {
096        uninstall(comp, getMergedContribution());
097    }
098
099    /**
100     * perform a deep clone to void sharing collection elements between clones
101     */
102    @Override
103    public ExtensibleContribution clone() {
104        ExtensibleContribution clone;
105        try {
106            clone = getClass().newInstance();
107        } catch (ReflectiveOperationException e) {
108            throw new RuntimeException("Failed to instantiate the contribution class. "
109                    + "Contribution classes must have a trivial constructor", e);
110        }
111        copyOver(clone);
112        clone.contributionId = contributionId;
113        clone.baseContributionId = baseContributionId;
114        return clone;
115    }
116
117}