/* * The MIT License * * Copyright 2011 Sony Ericsson Mobile Communications. All rights reserved. * Copyright 2012 Sony Mobile Communications AB. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sonyericsson.hudson.plugins.metadata.model; import com.sonyericsson.hudson.plugins.metadata.Messages; import com.sonyericsson.hudson.plugins.metadata.MetadataUpdateListener; import com.sonyericsson.hudson.plugins.metadata.model.values.AbstractMetadataValue; import com.sonyericsson.hudson.plugins.metadata.model.values.MetadataValue; import com.sonyericsson.hudson.plugins.metadata.model.values.ParentUtil; import com.thoughtworks.xstream.annotations.XStreamAlias; import hudson.Extension; import hudson.ExtensionList; import hudson.model.Computer; import hudson.model.Hudson; import hudson.model.Node; import hudson.security.ACL; import hudson.slaves.NodeProperty; import hudson.slaves.NodePropertyDescriptor; import net.sf.json.JSON; import net.sf.json.JSONObject; import org.kohsuke.stapler.Ancestor; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; import java.io.IOException; import java.util.Collection; import java.util.LinkedList; import java.util.List; import static com.sonyericsson.hudson.plugins.metadata.Constants.REQUEST_ATTR_METADATA_CONTAINER; /** * Stores metadata about Nodes. * * @author Robert Sandell <robert.sandell@sonyericsson.com> */ @edu.umd.cs.findbugs.annotations.SuppressWarnings( value = "UG_SYNC_SET_UNSYNC_GET", justification = "It is synchronized") @XStreamAlias("node-metadata") @ExportedBean public class MetadataNodeProperty extends NodeProperty<Node> implements MetadataContainer<MetadataValue> { private List<MetadataValue> values; /** * Standard Constructor. * * @param values the metadata for a Node. */ @DataBoundConstructor public MetadataNodeProperty(List<MetadataValue> values) { if (values == null) { values = new LinkedList<MetadataValue>(); } this.values = values; for (MetadataValue value : this.values) { value.setParent(this); } } /** * Default constructor. <strong>Do not use this unless you are a serializer.</strong> */ public MetadataNodeProperty() { this.values = new LinkedList<MetadataValue>(); } /** * The list of metadata values. * * @return the values. * * @see #getChildren() */ public synchronized List<MetadataValue> getValues() { if (values == null) { values = new LinkedList<MetadataValue>(); } return values; } @Override public synchronized MetadataValue getChild(String name) { return ParentUtil.getChildValue(values, name); } @Override public synchronized int indexOf(String name) { return ParentUtil.getChildIndex(values, name); } @Override public synchronized MetadataValue setChild(int index, MetadataValue value) { value.setParent(this); return values.set(index, value); } @Override public synchronized Collection<MetadataValue> addChild(MetadataValue value) { return ParentUtil.addChildValue(this, values, value); } @Override public synchronized Collection<MetadataValue> addChildren(Collection<MetadataValue> children) { return ParentUtil.addChildValues(this, this.values, children); } @Override @Exported public synchronized Collection<MetadataValue> getChildren() { return getValues(); } @Override public Collection<String> getChildNames() { return ParentUtil.getChildNames(this); } @Override public String getFullName() { return ""; } @Override public String getFullName(String separator) { return ""; } @Override public String getFullNameFrom(MetadataParent base) { return ""; } @Override public synchronized JSON toJson() { return ParentUtil.toJson(this); } @Override public boolean requiresReplacement() { return false; } /** * Jenkins likes to display both the master's properties summary.jelly and the node's summary.jelly on the computer * page. This method determines if the request really represents the Node that this property is tied to. * * @param request the request. * @return true if the request is for this Node and the summary should be displayed. */ public boolean shouldDisplaySummary(StaplerRequest request) { List<Ancestor> ancestors = request.getAncestors(); Ancestor ancestor = ancestors.get(ancestors.size() - 1); if (ancestor.getObject() instanceof Computer) { Computer computer = (Computer)ancestor.getObject(); return computer.getNode().getNodeProperties().get(MetadataNodeProperty.class) == this; } return false; } @Override public void save() throws IOException { Hudson.getInstance().save(); } @Override public ACL getACL() { if (this.node != null) { return this.node.getACL(); } else { return Hudson.getInstance().getACL(); } } /** * Descriptor for {@link MetadataNodeProperty}. */ @Extension public static class MetadataNodePropertyDescriptor extends NodePropertyDescriptor { @Override public String getDisplayName() { return Messages.MetadataNodeProperty_DisplayName(); } /** * All registered meta data descriptors that applies to jobs. To be used by a hetero-list. * * @param request the current http request. * @return a list. */ public List<AbstractMetadataValue.AbstractMetaDataValueDescriptor> getValueDescriptors(StaplerRequest request) { request.setAttribute(REQUEST_ATTR_METADATA_CONTAINER, this); List<AbstractMetadataValue.AbstractMetaDataValueDescriptor> list = new LinkedList<AbstractMetadataValue.AbstractMetaDataValueDescriptor>(); ExtensionList<AbstractMetadataValue.AbstractMetaDataValueDescriptor> extensionList = Hudson.getInstance().getExtensionList(AbstractMetadataValue.AbstractMetaDataValueDescriptor.class); for (AbstractMetadataValue.AbstractMetaDataValueDescriptor d : extensionList) { if (d.appliesTo(this)) { list.add(d); } } return list; } /** * Gives the {@link MetadataNodeProperty} for the given Node. If no metadata is available on the node the * property will be created and added to the node. * * @param node the node. * @return the property created or found. * * @throws IOException if an error occurs when adding the property to the node. */ public static MetadataNodeProperty instanceFor(Node node) throws IOException { if (node.getNodeProperties().get(MetadataNodeProperty.class) != null) { return node.getNodeProperties().get(MetadataNodeProperty.class); } else { MetadataNodeProperty property = new MetadataNodeProperty(); property.setNode(node); node.getNodeProperties().add(property); return property; } } @Override public MetadataNodeProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException { MetadataNodeProperty metadataNodeProperty = (MetadataNodeProperty)super.newInstance(req, formData); MetadataUpdateListener.notifyMetadaNodePropertyChanged(metadataNodeProperty); return metadataNodeProperty; } } }