/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.ivy.plugins.parser.xml;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.ivy.core.IvyPatternHelper;
import org.apache.ivy.core.module.descriptor.Artifact;
import org.apache.ivy.core.module.descriptor.Configuration;
import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor;
import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
import org.apache.ivy.core.module.descriptor.DependencyDescriptorMediator;
import org.apache.ivy.core.module.descriptor.ExcludeRule;
import org.apache.ivy.core.module.descriptor.ExtendsDescriptor;
import org.apache.ivy.core.module.descriptor.ExtraInfoHolder;
import org.apache.ivy.core.module.descriptor.IncludeRule;
import org.apache.ivy.core.module.descriptor.License;
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.plugins.matcher.MapMatcher;
import org.apache.ivy.util.DateUtil;
import org.apache.ivy.util.Message;
import org.apache.ivy.util.StringUtils;
import org.apache.ivy.util.XMLHelper;
import org.apache.ivy.util.extendable.ExtendableItem;
/**
*
*/
public final class XmlModuleDescriptorWriter {
private XmlModuleDescriptorWriter() {
// Utility class
}
public static void write(ModuleDescriptor md, File output) throws IOException {
write(md, null, output);
}
public static void write(ModuleDescriptor md, String licenseHeader, File output)
throws IOException {
if (output.getParentFile() != null) {
output.getParentFile().mkdirs();
}
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output),
"UTF-8"));
try {
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
if (licenseHeader != null) {
out.print(licenseHeader);
}
StringBuffer xmlNamespace = new StringBuffer();
Map namespaces = md.getExtraAttributesNamespaces();
for (Iterator iter = namespaces.entrySet().iterator(); iter.hasNext();) {
Entry ns = (Entry) iter.next();
xmlNamespace.append(" xmlns:").append(ns.getKey()).append("=\"")
.append(ns.getValue()).append("\"");
}
String version = "2.0";
if (md.getInheritedDescriptors().length > 0) {
version = "2.2";
}
out.println("<ivy-module version=\"" + version + "\"" + xmlNamespace + ">");
printInfoTag(md, out);
printConfigurations(md, out);
printPublications(md, out);
printDependencies(md, out);
out.println("</ivy-module>");
} finally {
out.close();
}
}
private static void printDependencies(ModuleDescriptor md, PrintWriter out) {
DependencyDescriptor[] dds = md.getDependencies();
if (dds.length > 0) {
out.println("\t<dependencies>");
for (int i = 0; i < dds.length; i++) {
DependencyDescriptor dep = dds[i];
out.print("\t\t");
printDependency(md, dep, out);
}
printAllExcludes(md, out);
printAllMediators(md, out);
out.println("\t</dependencies>");
}
}
protected static void printDependency(ModuleDescriptor md, DependencyDescriptor dep,
PrintWriter out) {
out.print("<dependency");
out.print(" org=\"" + XMLHelper.escape(dep.getDependencyRevisionId().getOrganisation())
+ "\"");
out.print(" name=\"" + XMLHelper.escape(dep.getDependencyRevisionId().getName()) + "\"");
if (dep.getDependencyRevisionId().getBranch() != null) {
out.print(" branch=\"" + XMLHelper.escape(dep.getDependencyRevisionId().getBranch())
+ "\"");
}
out.print(" rev=\"" + XMLHelper.escape(dep.getDependencyRevisionId().getRevision()) + "\"");
if (!dep.getDynamicConstraintDependencyRevisionId().equals(dep.getDependencyRevisionId())) {
if (dep.getDynamicConstraintDependencyRevisionId().getBranch() != null) {
out.print(" branchConstraint=\""
+ XMLHelper.escape(dep.getDynamicConstraintDependencyRevisionId()
.getBranch()) + "\"");
}
out.print(" revConstraint=\""
+ XMLHelper
.escape(dep.getDynamicConstraintDependencyRevisionId().getRevision())
+ "\"");
}
if (dep.isForce()) {
out.print(" force=\"" + dep.isForce() + "\"");
}
if (dep.isChanging()) {
out.print(" changing=\"" + dep.isChanging() + "\"");
}
if (!dep.isTransitive()) {
out.print(" transitive=\"" + dep.isTransitive() + "\"");
}
out.print(" conf=\"");
String[] modConfs = dep.getModuleConfigurations();
for (int j = 0; j < modConfs.length; j++) {
String[] depConfs = dep.getDependencyConfigurations(modConfs[j]);
out.print(XMLHelper.escape(modConfs[j]) + "->");
for (int k = 0; k < depConfs.length; k++) {
out.print(XMLHelper.escape(depConfs[k]));
if (k + 1 < depConfs.length) {
out.print(",");
}
}
if (j + 1 < modConfs.length) {
out.print(";");
}
}
out.print("\"");
printExtraAttributes(dep, out, " ");
DependencyArtifactDescriptor[] depArtifacts = dep.getAllDependencyArtifacts();
if (depArtifacts.length > 0) {
out.println(">");
}
printDependencyArtefacts(md, out, depArtifacts);
IncludeRule[] includes = dep.getAllIncludeRules();
if (includes.length > 0 && depArtifacts.length == 0) {
out.println(">");
}
printDependencyIncludeRules(md, out, includes);
ExcludeRule[] excludes = dep.getAllExcludeRules();
if (excludes.length > 0 && includes.length == 0 && depArtifacts.length == 0) {
out.println(">");
}
printDependencyExcludeRules(md, out, excludes);
if (includes.length + excludes.length + depArtifacts.length == 0) {
out.println("/>");
} else {
out.println("\t\t</dependency>");
}
}
private static void printAllMediators(ModuleDescriptor md, PrintWriter out) {
Map/* <MapMatcher, DependencyDescriptorMediator> */mediators = md
.getAllDependencyDescriptorMediators().getAllRules();
for (Iterator iterator = mediators.entrySet().iterator(); iterator.hasNext();) {
Map.Entry mediatorRule = (Map.Entry) iterator.next();
MapMatcher matcher = (MapMatcher) mediatorRule.getKey();
DependencyDescriptorMediator mediator = (DependencyDescriptorMediator) mediatorRule
.getValue();
if (mediator instanceof OverrideDependencyDescriptorMediator) {
OverrideDependencyDescriptorMediator oddm = (OverrideDependencyDescriptorMediator) mediator;
out.print("\t\t<override");
out.print(" org=\""
+ XMLHelper.escape((String) matcher.getAttributes().get(
IvyPatternHelper.ORGANISATION_KEY)) + "\"");
out.print(" module=\""
+ XMLHelper.escape((String) matcher.getAttributes().get(
IvyPatternHelper.MODULE_KEY)) + "\"");
out.print(" matcher=\"" + XMLHelper.escape(matcher.getPatternMatcher().getName())
+ "\"");
if (oddm.getBranch() != null) {
out.print(" branch=\"" + XMLHelper.escape(oddm.getBranch()) + "\"");
}
if (oddm.getVersion() != null) {
out.print(" rev=\"" + XMLHelper.escape(oddm.getVersion()) + "\"");
}
out.println("/>");
} else {
Message.verbose("ignoring unhandled DependencyDescriptorMediator: "
+ mediator.getClass());
}
}
}
private static void printAllExcludes(ModuleDescriptor md, PrintWriter out) {
ExcludeRule[] excludes = md.getAllExcludeRules();
if (excludes.length > 0) {
for (int j = 0; j < excludes.length; j++) {
out.print("\t\t<exclude");
out.print(" org=\""
+ XMLHelper.escape(excludes[j].getId().getModuleId().getOrganisation())
+ "\"");
out.print(" module=\""
+ XMLHelper.escape(excludes[j].getId().getModuleId().getName()) + "\"");
out.print(" artifact=\"" + XMLHelper.escape(excludes[j].getId().getName()) + "\"");
out.print(" type=\"" + XMLHelper.escape(excludes[j].getId().getType()) + "\"");
out.print(" ext=\"" + XMLHelper.escape(excludes[j].getId().getExt()) + "\"");
String[] ruleConfs = excludes[j].getConfigurations();
if (!Arrays.asList(ruleConfs).equals(Arrays.asList(md.getConfigurationsNames()))) {
out.print(" conf=\"");
for (int k = 0; k < ruleConfs.length; k++) {
out.print(XMLHelper.escape(ruleConfs[k]));
if (k + 1 < ruleConfs.length) {
out.print(",");
}
}
out.print("\"");
}
out.print(" matcher=\"" + XMLHelper.escape(excludes[j].getMatcher().getName())
+ "\"");
out.println("/>");
}
}
}
private static void printDependencyExcludeRules(ModuleDescriptor md, PrintWriter out,
ExcludeRule[] excludes) {
if (excludes.length > 0) {
for (int j = 0; j < excludes.length; j++) {
out.print("\t\t\t<exclude");
out.print(" org=\""
+ XMLHelper.escape(excludes[j].getId().getModuleId().getOrganisation())
+ "\"");
out.print(" module=\""
+ XMLHelper.escape(excludes[j].getId().getModuleId().getName()) + "\"");
out.print(" name=\"" + XMLHelper.escape(excludes[j].getId().getName()) + "\"");
out.print(" type=\"" + XMLHelper.escape(excludes[j].getId().getType()) + "\"");
out.print(" ext=\"" + XMLHelper.escape(excludes[j].getId().getExt()) + "\"");
String[] ruleConfs = excludes[j].getConfigurations();
if (!Arrays.asList(ruleConfs).equals(Arrays.asList(md.getConfigurationsNames()))) {
out.print(" conf=\"");
for (int k = 0; k < ruleConfs.length; k++) {
out.print(XMLHelper.escape(ruleConfs[k]));
if (k + 1 < ruleConfs.length) {
out.print(",");
}
}
out.print("\"");
}
out.print(" matcher=\"" + XMLHelper.escape(excludes[j].getMatcher().getName())
+ "\"");
out.println("/>");
}
}
}
private static void printDependencyIncludeRules(ModuleDescriptor md, PrintWriter out,
IncludeRule[] includes) {
if (includes.length > 0) {
for (int j = 0; j < includes.length; j++) {
out.print("\t\t\t<include");
out.print(" name=\"" + XMLHelper.escape(includes[j].getId().getName()) + "\"");
out.print(" type=\"" + XMLHelper.escape(includes[j].getId().getType()) + "\"");
out.print(" ext=\"" + XMLHelper.escape(includes[j].getId().getExt()) + "\"");
String[] ruleConfs = includes[j].getConfigurations();
if (!Arrays.asList(ruleConfs).equals(Arrays.asList(md.getConfigurationsNames()))) {
out.print(" conf=\"");
for (int k = 0; k < ruleConfs.length; k++) {
out.print(XMLHelper.escape(ruleConfs[k]));
if (k + 1 < ruleConfs.length) {
out.print(",");
}
}
out.print("\"");
}
out.print(" matcher=\"" + XMLHelper.escape(includes[j].getMatcher().getName())
+ "\"");
out.println("/>");
}
}
}
private static void printDependencyArtefacts(ModuleDescriptor md, PrintWriter out,
DependencyArtifactDescriptor[] depArtifacts) {
if (depArtifacts.length > 0) {
for (int j = 0; j < depArtifacts.length; j++) {
out.print("\t\t\t<artifact");
out.print(" name=\"" + XMLHelper.escape(depArtifacts[j].getName()) + "\"");
out.print(" type=\"" + XMLHelper.escape(depArtifacts[j].getType()) + "\"");
out.print(" ext=\"" + XMLHelper.escape(depArtifacts[j].getExt()) + "\"");
String[] dadconfs = depArtifacts[j].getConfigurations();
if (!Arrays.asList(dadconfs).equals(Arrays.asList(md.getConfigurationsNames()))) {
out.print(" conf=\"");
for (int k = 0; k < dadconfs.length; k++) {
out.print(XMLHelper.escape(dadconfs[k]));
if (k + 1 < dadconfs.length) {
out.print(",");
}
}
out.print("\"");
}
printExtraAttributes(depArtifacts[j], out, " ");
out.println("/>");
}
}
}
/**
* Writes the extra attributes of the given {@link ExtendableItem} to the given
* <tt>PrintWriter</tt>.
*
* @param item
* the {@link ExtendableItem}, cannot be <tt>null</tt>
* @param out
* the writer to use
* @param prefix
* the string to write before writing the attributes (if any)
*/
private static void printExtraAttributes(ExtendableItem item, PrintWriter out, String prefix) {
printExtraAttributes(item.getQualifiedExtraAttributes(), out, prefix);
}
/**
* Writes the specified <tt>Map</tt> containing the extra attributes to the given
* <tt>PrintWriter</tt>.
*
* @param extra
* the extra attributes, can be <tt>null</tt>
* @param out
* the writer to use
* @param prefix
* the string to write before writing the attributes (if any)
*/
private static void printExtraAttributes(Map extra, PrintWriter out, String prefix) {
if (extra == null) {
return;
}
String delim = prefix;
for (Iterator iter = extra.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
out.print(delim + entry.getKey() + "=\""
+ XMLHelper.escape(entry.getValue().toString()) + "\"");
delim = " ";
}
}
private static void printPublications(ModuleDescriptor md, PrintWriter out) {
out.println("\t<publications>");
Artifact[] artifacts = md.getAllArtifacts();
for (int i = 0; i < artifacts.length; i++) {
out.print("\t\t<artifact");
out.print(" name=\"" + XMLHelper.escape(artifacts[i].getName()) + "\"");
out.print(" type=\"" + XMLHelper.escape(artifacts[i].getType()) + "\"");
out.print(" ext=\"" + XMLHelper.escape(artifacts[i].getExt()) + "\"");
out.print(" conf=\"" + XMLHelper.escape(getConfs(md, artifacts[i])) + "\"");
printExtraAttributes(artifacts[i], out, " ");
out.println("/>");
}
out.println("\t</publications>");
}
private static void printConfigurations(ModuleDescriptor md, PrintWriter out) {
Configuration[] confs = md.getConfigurations();
if (confs.length > 0) {
out.println("\t<configurations>");
for (int i = 0; i < confs.length; i++) {
Configuration conf = confs[i];
out.print("\t\t");
printConfiguration(conf, out);
}
out.println("\t</configurations>");
}
}
protected static void printConfiguration(Configuration conf, PrintWriter out) {
out.print("<conf");
out.print(" name=\"" + XMLHelper.escape(conf.getName()) + "\"");
out.print(" visibility=\"" + XMLHelper.escape(conf.getVisibility().toString()) + "\"");
if (conf.getDescription() != null) {
out.print(" description=\"" + XMLHelper.escape(conf.getDescription()) + "\"");
}
String[] exts = conf.getExtends();
if (exts.length > 0) {
out.print(" extends=\"");
for (int j = 0; j < exts.length; j++) {
out.print(XMLHelper.escape(exts[j]));
if (j + 1 < exts.length) {
out.print(",");
}
}
out.print("\"");
}
if (!conf.isTransitive()) {
out.print(" transitive=\"false\"");
}
if (conf.getDeprecated() != null) {
out.print(" deprecated=\"" + XMLHelper.escape(conf.getDeprecated()) + "\"");
}
printExtraAttributes(conf, out, " ");
out.println("/>");
}
private static void printInfoTag(ModuleDescriptor md, PrintWriter out) {
out.println("\t<info organisation=\""
+ XMLHelper.escape(md.getModuleRevisionId().getOrganisation()) + "\"");
out.println("\t\tmodule=\"" + XMLHelper.escape(md.getModuleRevisionId().getName()) + "\"");
String branch = md.getResolvedModuleRevisionId().getBranch();
if (branch != null) {
out.println("\t\tbranch=\"" + XMLHelper.escape(branch) + "\"");
}
String revision = md.getResolvedModuleRevisionId().getRevision();
if (revision != null) {
out.println("\t\trevision=\"" + XMLHelper.escape(revision) + "\"");
}
out.println("\t\tstatus=\"" + XMLHelper.escape(md.getStatus()) + "\"");
out.println("\t\tpublication=\"" + DateUtil.format(md.getResolvedPublicationDate()) + "\"");
if (md.isDefault()) {
out.println("\t\tdefault=\"true\"");
}
if (md instanceof DefaultModuleDescriptor) {
DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) md;
if (dmd.getNamespace() != null && !dmd.getNamespace().getName().equals("system")) {
out.println("\t\tnamespace=\"" + XMLHelper.escape(dmd.getNamespace().getName())
+ "\"");
}
}
if (!md.getExtraAttributes().isEmpty()) {
printExtraAttributes(md, out, "\t\t");
out.println();
}
if (requireInnerInfoElement(md)) {
out.println("\t>");
ExtendsDescriptor[] parents = md.getInheritedDescriptors();
for (int i = 0; i < parents.length; i++) {
ExtendsDescriptor parent = parents[i];
ModuleRevisionId mrid = parent.getParentRevisionId();
out.print("\t\t<extends organisation=\"" + XMLHelper.escape(mrid.getOrganisation())
+ "\"" + " module=\"" + XMLHelper.escape(mrid.getName()) + "\""
+ " revision=\"" + XMLHelper.escape(mrid.getRevision()) + "\"");
String location = parent.getLocation();
if (location != null) {
out.print(" location=\"" + XMLHelper.escape(location) + "\"");
}
out.print(" extendType=\"" + StringUtils.join(parent.getExtendsTypes(), ",") + "\"");
out.println("/>");
}
License[] licenses = md.getLicenses();
for (int i = 0; i < licenses.length; i++) {
License license = licenses[i];
out.print("\t\t<license ");
if (license.getName() != null) {
out.print("name=\"" + XMLHelper.escape(license.getName()) + "\" ");
}
if (license.getUrl() != null) {
out.print("url=\"" + XMLHelper.escape(license.getUrl()) + "\" ");
}
out.println("/>");
}
if (md.getHomePage() != null || md.getDescription() != null) {
out.print("\t\t<description");
if (md.getHomePage() != null) {
out.print(" homepage=\"" + XMLHelper.escape(md.getHomePage()) + "\"");
}
if (md.getDescription() != null && md.getDescription().trim().length() > 0) {
out.println(">");
out.println("\t\t" + XMLHelper.escape(md.getDescription()));
out.println("\t\t</description>");
} else {
out.println(" />");
}
}
for (ExtraInfoHolder extraInfo : md.getExtraInfos()) {
printExtraInfoElement(out, extraInfo, 2);
}
out.println("\t</info>");
} else {
out.println("\t/>");
}
}
private static void printExtraInfoElement(PrintWriter out, ExtraInfoHolder extraInfo, int indent) {
for (int i = 1; i <= indent; i++) {
out.print("\t");
}
out.print("<");
out.print(extraInfo.getName());
for (Entry<String, String> entry : extraInfo.getAttributes().entrySet()) {
out.print(" ");
out.print(entry.getKey());
out.print("=");
out.print("\"");
out.print(entry.getValue());
out.print("\"");
}
boolean requireClosingTag = false;
if (extraInfo.getContent() != null && extraInfo.getContent().trim().length() > 0) {
out.print(">");
out.print(XMLHelper.escape(extraInfo.getContent()));
requireClosingTag = true;
}
if (!extraInfo.getNestedExtraInfoHolder().isEmpty()) {
out.println(">");
for (ExtraInfoHolder nestedElement : extraInfo.getNestedExtraInfoHolder()) {
printExtraInfoElement(out, nestedElement, indent + 1);
}
requireClosingTag = true;
// prepare indentation for closing tag
for (int i = 1; i <= indent; i++) {
out.print("\t");
}
}
if (requireClosingTag) {
out.print("</");
out.print(extraInfo.getName());
out.println(">");
} else {
out.println("/>");
}
}
private static boolean requireInnerInfoElement(ModuleDescriptor md) {
return md.getExtraInfo().size() > 0 || md.getExtraInfos().size() > 0
|| md.getHomePage() != null
|| (md.getDescription() != null && md.getDescription().trim().length() > 0)
|| md.getLicenses().length > 0 || md.getInheritedDescriptors().length > 0;
}
private static String getConfs(ModuleDescriptor md, Artifact artifact) {
StringBuffer ret = new StringBuffer();
String[] confs = md.getConfigurationsNames();
for (int i = 0; i < confs.length; i++) {
if (Arrays.asList(md.getArtifacts(confs[i])).contains(artifact)) {
ret.append(confs[i]).append(",");
}
}
if (ret.length() > 0) {
ret.setLength(ret.length() - 1);
}
return ret.toString();
}
}