| /* |
| * 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; |
| |
| import java.io.IOException; |
| import java.net.URL; |
| import java.text.ParseException; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.apache.ivy.core.module.descriptor.Artifact; |
| import org.apache.ivy.core.module.descriptor.Configuration; |
| import org.apache.ivy.core.module.descriptor.DefaultArtifact; |
| import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; |
| import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; |
| import org.apache.ivy.core.module.descriptor.DependencyDescriptor; |
| import org.apache.ivy.core.module.descriptor.ModuleDescriptor; |
| import org.apache.ivy.core.module.id.ModuleRevisionId; |
| import org.apache.ivy.plugins.repository.Resource; |
| import org.apache.ivy.plugins.repository.ResourceHelper; |
| import org.apache.ivy.plugins.repository.url.URLResource; |
| import org.apache.ivy.util.Message; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| public abstract class AbstractModuleDescriptorParser implements ModuleDescriptorParser { |
| public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL, |
| boolean validate) throws ParseException, IOException { |
| return parseDescriptor(ivySettings, descriptorURL, new URLResource(descriptorURL), validate); |
| } |
| |
| public String getType() { |
| return "ivy"; |
| } |
| |
| public Artifact getMetadataArtifact(ModuleRevisionId mrid, Resource res) { |
| return DefaultArtifact.newIvyArtifact(mrid, new Date(res.getLastModified())); |
| } |
| |
| protected abstract static class AbstractParser extends DefaultHandler { |
| private static final String DEFAULT_CONF_MAPPING = "*->*"; |
| |
| private String defaultConf; // used only as defaultconf, not used for |
| |
| // guesssing right side part of a mapping |
| private String defaultConfMapping; // same as default conf but is used |
| |
| // for guesssing right side part of a mapping |
| private DefaultDependencyDescriptor defaultConfMappingDescriptor; |
| |
| private Resource res; |
| |
| private List<String> errors = new ArrayList<String>(); |
| |
| private DefaultModuleDescriptor md; |
| |
| private ModuleDescriptorParser parser; |
| |
| protected AbstractParser(ModuleDescriptorParser parser) { |
| this.parser = parser; |
| } |
| |
| public ModuleDescriptorParser getModuleDescriptorParser() { |
| return parser; |
| } |
| |
| protected void checkErrors() throws ParseException { |
| if (!errors.isEmpty()) { |
| throw new ParseException(errors.toString(), 0); |
| } |
| } |
| |
| public void setResource(Resource res) { |
| this.res = res; // used for log and date only |
| md = new DefaultModuleDescriptor(parser, res); |
| md.setLastModified(ResourceHelper.getLastModifiedOrDefault(res)); |
| } |
| |
| protected Resource getResource() { |
| return res; |
| } |
| |
| protected String getDefaultConfMapping() { |
| return defaultConfMapping; |
| } |
| |
| protected void setDefaultConfMapping(String defaultConf) { |
| defaultConfMapping = defaultConf; |
| getMd().setDefaultConfMapping(defaultConf); |
| } |
| |
| protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd) { |
| parseDepsConfs(confs, dd, defaultConfMapping != null); |
| } |
| |
| protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd, |
| boolean useDefaultMappingToGuessRightOperande) { |
| parseDepsConfs(confs, dd, useDefaultMappingToGuessRightOperande, true); |
| } |
| |
| protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd, |
| boolean useDefaultMappingToGuessRightOperande, boolean evaluateConditions) { |
| if (confs == null) { |
| return; |
| } |
| |
| String[] conf = confs.split(";"); |
| parseDepsConfs(conf, dd, useDefaultMappingToGuessRightOperande, evaluateConditions); |
| } |
| |
| protected void parseDepsConfs(String[] conf, DefaultDependencyDescriptor dd, |
| boolean useDefaultMappingToGuessRightOperande) { |
| parseDepsConfs(conf, dd, useDefaultMappingToGuessRightOperande, true); |
| } |
| |
| protected void parseDepsConfs(String[] conf, DefaultDependencyDescriptor dd, |
| boolean useDefaultMappingToGuessRightOperande, boolean evaluateConditions) { |
| replaceConfigurationWildcards(md); |
| for (int i = 0; i < conf.length; i++) { |
| String[] ops = conf[i].split("->"); |
| if (ops.length == 1) { |
| String[] modConfs = ops[0].split(","); |
| if (!useDefaultMappingToGuessRightOperande) { |
| for (int j = 0; j < modConfs.length; j++) { |
| dd.addDependencyConfiguration(modConfs[j].trim(), modConfs[j].trim()); |
| } |
| } else { |
| for (int j = 0; j < modConfs.length; j++) { |
| String[] depConfs = getDefaultConfMappingDescriptor() |
| .getDependencyConfigurations(modConfs[j]); |
| if (depConfs.length > 0) { |
| for (int k = 0; k < depConfs.length; k++) { |
| String mappedDependency = evaluateConditions ? evaluateCondition( |
| depConfs[k].trim(), dd) : depConfs[k].trim(); |
| if (mappedDependency != null) { |
| dd.addDependencyConfiguration(modConfs[j].trim(), |
| mappedDependency); |
| } |
| } |
| } else { |
| // no default mapping found for this configuration, map |
| // configuration to itself |
| dd.addDependencyConfiguration(modConfs[j].trim(), |
| modConfs[j].trim()); |
| } |
| } |
| } |
| } else if (ops.length == 2) { |
| String[] modConfs = ops[0].split(","); |
| String[] depConfs = ops[1].split(","); |
| for (int j = 0; j < modConfs.length; j++) { |
| for (int k = 0; k < depConfs.length; k++) { |
| String mappedDependency = evaluateConditions ? evaluateCondition( |
| depConfs[k].trim(), dd) : depConfs[k].trim(); |
| if (mappedDependency != null) { |
| dd.addDependencyConfiguration(modConfs[j].trim(), mappedDependency); |
| } |
| } |
| } |
| } else { |
| addError("invalid conf " + conf[i] + " for " + dd); |
| } |
| } |
| |
| if (md.isMappingOverride()) { |
| addExtendingConfigurations(conf, dd, useDefaultMappingToGuessRightOperande); |
| } |
| } |
| |
| /** |
| * Evaluate the optional condition in the given configuration, like "[org=MYORG]confX". If |
| * the condition evaluates to true, the configuration is returned, if the condition |
| * evaluatate to false, null is returned. If there are no conditions, the configuration |
| * itself is returned. |
| * |
| * @param conf |
| * the configuration to evaluate |
| * @param dd |
| * the dependencydescriptor to which the configuration will be added |
| * @return the evaluated condition |
| */ |
| private String evaluateCondition(String conf, DefaultDependencyDescriptor dd) { |
| if (conf.charAt(0) != '[') { |
| return conf; |
| } |
| |
| int endConditionIndex = conf.indexOf(']'); |
| if (endConditionIndex == -1) { |
| addError("invalid conf " + conf + " for " + dd); |
| return null; |
| } |
| |
| String condition = conf.substring(1, endConditionIndex); |
| |
| int notEqualIndex = condition.indexOf("!="); |
| if (notEqualIndex == -1) { |
| int equalIndex = condition.indexOf('='); |
| if (equalIndex == -1) { |
| addError("invalid conf " + conf + " for " + dd.getDependencyRevisionId()); |
| return null; |
| } |
| |
| String leftOp = condition.substring(0, equalIndex).trim(); |
| String rightOp = condition.substring(equalIndex + 1).trim(); |
| |
| // allow organisation synonyms, like 'org' or 'organization' |
| if (leftOp.equals("org") || leftOp.equals("organization")) { |
| leftOp = "organisation"; |
| } |
| |
| String attrValue = dd.getAttribute(leftOp); |
| if (!rightOp.equals(attrValue)) { |
| return null; |
| } |
| } else { |
| String leftOp = condition.substring(0, notEqualIndex).trim(); |
| String rightOp = condition.substring(notEqualIndex + 2).trim(); |
| |
| // allow organisation synonyms, like 'org' or 'organization' |
| if (leftOp.equals("org") || leftOp.equals("organization")) { |
| leftOp = "organisation"; |
| } |
| |
| String attrValue = dd.getAttribute(leftOp); |
| if (rightOp.equals(attrValue)) { |
| return null; |
| } |
| } |
| |
| return conf.substring(endConditionIndex + 1); |
| } |
| |
| private void addExtendingConfigurations(String[] confs, DefaultDependencyDescriptor dd, |
| boolean useDefaultMappingToGuessRightOperande) { |
| for (int i = 0; i < confs.length; i++) { |
| addExtendingConfigurations(confs[i], dd, useDefaultMappingToGuessRightOperande); |
| } |
| } |
| |
| private void addExtendingConfigurations(String conf, DefaultDependencyDescriptor dd, |
| boolean useDefaultMappingToGuessRightOperande) { |
| Set<String> configsToAdd = new HashSet<String>(); |
| Configuration[] configs = md.getConfigurations(); |
| for (int i = 0; i < configs.length; i++) { |
| String[] ext = configs[i].getExtends(); |
| for (int j = 0; j < ext.length; j++) { |
| if (conf.equals(ext[j])) { |
| String configName = configs[i].getName(); |
| configsToAdd.add(configName); |
| addExtendingConfigurations(configName, dd, |
| useDefaultMappingToGuessRightOperande); |
| } |
| } |
| } |
| |
| String[] confs = configsToAdd.toArray(new String[configsToAdd.size()]); |
| parseDepsConfs(confs, dd, useDefaultMappingToGuessRightOperande); |
| } |
| |
| protected DependencyDescriptor getDefaultConfMappingDescriptor() { |
| if (defaultConfMappingDescriptor == null) { |
| defaultConfMappingDescriptor = new DefaultDependencyDescriptor( |
| ModuleRevisionId.newInstance("", "", ""), false); |
| parseDepsConfs(defaultConfMapping, defaultConfMappingDescriptor, false, false); |
| } |
| return defaultConfMappingDescriptor; |
| } |
| |
| protected void addError(String msg) { |
| if (res != null) { |
| errors.add(msg + " in " + res + "\n"); |
| } else { |
| errors.add(msg + "\n"); |
| } |
| } |
| |
| @Override |
| public void warning(SAXParseException ex) { |
| Message.warn("xml parsing: " + getLocationString(ex) + ": " + ex.getMessage()); |
| } |
| |
| @Override |
| public void error(SAXParseException ex) { |
| addError("xml parsing: " + getLocationString(ex) + ": " + ex.getMessage()); |
| } |
| |
| @Override |
| public void fatalError(SAXParseException ex) throws SAXException { |
| addError("[Fatal Error] " + getLocationString(ex) + ": " + ex.getMessage()); |
| } |
| |
| /** Returns a string of the location. */ |
| private String getLocationString(SAXParseException ex) { |
| StringBuffer str = new StringBuffer(); |
| |
| String systemId = ex.getSystemId(); |
| if (systemId != null) { |
| int index = systemId.lastIndexOf('/'); |
| if (index != -1) { |
| systemId = systemId.substring(index + 1); |
| } |
| str.append(systemId); |
| } else if (getResource() != null) { |
| str.append(getResource().toString()); |
| } |
| str.append(':'); |
| str.append(ex.getLineNumber()); |
| str.append(':'); |
| str.append(ex.getColumnNumber()); |
| |
| return str.toString(); |
| |
| } // getLocationString(SAXParseException):String |
| |
| protected String getDefaultConf() { |
| return defaultConf != null ? defaultConf |
| : (defaultConfMapping != null ? defaultConfMapping : DEFAULT_CONF_MAPPING); |
| } |
| |
| protected void setDefaultConf(String defaultConf) { |
| this.defaultConf = defaultConf; |
| getMd().setDefaultConf(defaultConf); |
| } |
| |
| public ModuleDescriptor getModuleDescriptor() throws ParseException { |
| checkErrors(); |
| return md; |
| } |
| |
| protected Date getDefaultPubDate() { |
| return new Date(md.getLastModified()); |
| } |
| |
| private void replaceConfigurationWildcards(ModuleDescriptor md) { |
| Configuration[] configs = md.getConfigurations(); |
| for (int i = 0; i < configs.length; i++) { |
| configs[i].replaceWildcards(md); |
| } |
| } |
| |
| protected void setMd(DefaultModuleDescriptor md) { |
| this.md = md; |
| } |
| |
| protected DefaultModuleDescriptor getMd() { |
| return md; |
| } |
| } |
| |
| } |