/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, 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. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.server.domain.xml; import java.io.IOException; import java.util.List; import java.util.Map; import com.thoughtworks.go.config.materials.AbstractMaterial; import com.thoughtworks.go.config.materials.PackageMaterial; import com.thoughtworks.go.config.materials.PluggableSCMMaterial; import com.thoughtworks.go.config.materials.ScmMaterial; import com.thoughtworks.go.config.materials.dependency.DependencyMaterial; import com.thoughtworks.go.domain.MaterialRevision; import com.thoughtworks.go.domain.PipelineTimelineEntry; import com.thoughtworks.go.domain.XmlRepresentable; import com.thoughtworks.go.domain.XmlWriterContext; import com.thoughtworks.go.domain.materials.Material; import com.thoughtworks.go.domain.materials.Modification; import com.thoughtworks.go.domain.materials.Modifications; import com.thoughtworks.go.domain.materials.ModifiedFile; import com.thoughtworks.go.presentation.pipelinehistory.NullStageHistoryItem; import com.thoughtworks.go.presentation.pipelinehistory.PipelineInstanceModel; import com.thoughtworks.go.presentation.pipelinehistory.StageInstanceModel; import com.thoughtworks.go.util.DateUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.dom.DOMDocument; import org.dom4j.dom.DOMElement; /** * @understands rendering xml representation of Pipeline */ public class PipelineXmlViewModel implements XmlRepresentable { private final PipelineInstanceModel pipeline; public PipelineXmlViewModel(PipelineInstanceModel pipeline) { this.pipeline = pipeline; } public Document toXml(XmlWriterContext writerContext) throws DocumentException, IOException { DOMElement root = new DOMElement("pipeline"); root.addAttribute("name", pipeline.getName()).addAttribute("counter", String.valueOf(pipeline.getCounter())).addAttribute("label", pipeline.getLabel()); Document document = new DOMDocument(root); String baseUrl = writerContext.getBaseUrl(); root.addElement("link").addAttribute("rel", "self").addAttribute("href", httpUrl(baseUrl)); root.addElement("id").addCDATA(pipeline.getPipelineIdentifier().asURN()); PipelineTimelineEntry pipelineAfter = pipeline.getPipelineAfter(); if (pipelineAfter != null) { addTimelineLink(root, baseUrl, "insertedBefore", pipelineAfter); } PipelineTimelineEntry pipelineBefore = pipeline.getPipelineBefore(); if (pipelineBefore != null) { addTimelineLink(root, baseUrl, "insertedAfter", pipelineBefore); } root.addElement("scheduleTime").addText(DateUtils.formatISO8601(pipeline.getScheduledDate())); Element materials = root.addElement("materials"); for (MaterialRevision materialRevision : pipeline.getCurrentRevisions()) { populateXml(materials, materialRevision, writerContext); } Element stages = root.addElement("stages"); for (StageInstanceModel stage : pipeline.getStageHistory()) { if (! (stage instanceof NullStageHistoryItem)) { stages.addElement("stage").addAttribute("href", StageXmlViewModel.httpUrlFor(writerContext.getBaseUrl(), stage.getId())); } } root.addElement("approvedBy").addCDATA(pipeline.getApprovedBy()); return document; } public abstract static class MaterialXmlViewModel { final AbstractMaterial material; static MaterialXmlViewModel viewModelFor(Material material) { if(material instanceof ScmMaterial || material instanceof PluggableSCMMaterial) return new ScmXmlViewModel(material); if(material instanceof DependencyMaterial) return new DependencyXmlViewModel(material); if(material instanceof PackageMaterial) return new PackageXmlViewModel(material); throw new RuntimeException("Unknown material type"); } MaterialXmlViewModel(Material material) { this.material = (AbstractMaterial) material; } void populateXml(Element materials, Modifications modifications, XmlWriterContext writerContext) { Element materialElement = materials.addElement("material"); materialElement.addAttribute("materialUri", writerContext.getBaseUrl() + "/api/materials/" + material.getId() + ".xml"); for (Map.Entry<String, Object> criterion : material.getAttributesForXml().entrySet()) { if (criterion.getValue() != null) { materialElement.addAttribute(criterion.getKey(), criterion.getValue().toString()); } } Element modificationsTag = materialElement.addElement("modifications"); populateXmlForModifications(modifications, writerContext, modificationsTag); } abstract void populateXmlForModifications(Modifications modifications, XmlWriterContext writerContext, Element modificationsTag); } public static class ScmXmlViewModel extends MaterialXmlViewModel { ScmXmlViewModel(Material material) { super(material); } @Override void populateXmlForModifications(Modifications modifications, XmlWriterContext writerContext, Element modificationsTag) { for (Modification modification : modifications) { Element changeset = modificationsTag.addElement("changeset"); changeset.addAttribute("changesetUri", ScmMaterial.changesetUrl(modification, writerContext.getBaseUrl(), material.getId())); changeset.addElement("user").addCDATA(modification.getUserDisplayName()); changeset.addElement("checkinTime").addText(DateUtils.formatISO8601(modification.getModifiedTime())); changeset.addElement("revision").addCDATA(modification.getRevision()); changeset.addElement("message").addCDATA(modification.getComment()); List<ModifiedFile> modifiedFiles = modification.getModifiedFiles(); for (ModifiedFile modifiedFile : modifiedFiles) { changeset.addElement("file").addAttribute("name", modifiedFile.getFileName()).addAttribute("action", modifiedFile.getAction().toString()); } } } } static class PackageXmlViewModel extends MaterialXmlViewModel { PackageXmlViewModel(Material material) { super(material); } @Override void populateXmlForModifications(Modifications modifications, XmlWriterContext writerContext, Element modificationsTag) { for (Modification modification : modifications) { Element changeset = modificationsTag.addElement("changeset"); changeset.addAttribute("changesetUri", ScmMaterial.changesetUrl(modification, writerContext.getBaseUrl(), material.getId())); changeset.addElement("user").addCDATA(modification.getUserDisplayName()); changeset.addElement("checkinTime").addText(DateUtils.formatISO8601(modification.getModifiedTime())); changeset.addElement("revision").addCDATA(modification.getRevision()); changeset.addElement("message").addCDATA(modification.getComment()); } } } private static class DependencyXmlViewModel extends MaterialXmlViewModel { DependencyXmlViewModel(Material material) { super(material); } @Override void populateXmlForModifications(Modifications modifications, XmlWriterContext writerContext, Element modificationsTag) { Modification firstModification = modifications.first(); Element changeset = modificationsTag.addElement("changeset"); String revision = firstModification.getRevision(); changeset.addAttribute("changesetUri", StageXmlViewModel.httpUrlFor(writerContext.getBaseUrl(), writerContext.stageIdForLocator(revision))); changeset.addElement("checkinTime").addText(DateUtils.formatISO8601(firstModification.getModifiedTime())); changeset.addElement("revision").addText(revision); } } private void populateXml(Element materials, MaterialRevision materialRevision, XmlWriterContext writerContext) { MaterialXmlViewModel.viewModelFor(materialRevision.getMaterial()).populateXml(materials, materialRevision.getModifications(), writerContext); } public String httpUrl(String baseUrl) { return httpUrlForPipeline(baseUrl, pipeline.getId(), pipeline.getName()); } private void addTimelineLink(DOMElement root, String baseUrl, final String rel, final PipelineTimelineEntry entry) { root.addElement("link").addAttribute("rel", rel).addAttribute("href", httpUrlForPipeline(baseUrl, entry.getId(), pipeline.getName())); } public static String httpUrlForPipeline(String baseUrl, long id, final String name) { return baseUrl + "/api/pipelines/" + name + "/" + id + ".xml"; } }