2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.ivy.plugins.parser;
20
import java.io.IOException;
22
import java.text.ParseException;
23
import java.util.ArrayList;
24
import java.util.Date;
25
import java.util.HashSet;
26
import java.util.List;
29
import org.apache.ivy.core.module.descriptor.Artifact;
30
import org.apache.ivy.core.module.descriptor.Configuration;
31
import org.apache.ivy.core.module.descriptor.DefaultArtifact;
32
import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
33
import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
34
import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
35
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
36
import org.apache.ivy.core.module.id.ModuleRevisionId;
37
import org.apache.ivy.plugins.repository.Resource;
38
import org.apache.ivy.plugins.repository.ResourceHelper;
39
import org.apache.ivy.plugins.repository.url.URLResource;
40
import org.apache.ivy.util.Message;
41
import org.xml.sax.SAXException;
42
import org.xml.sax.SAXParseException;
43
import org.xml.sax.helpers.DefaultHandler;
45
public abstract class AbstractModuleDescriptorParser implements ModuleDescriptorParser {
46
public ModuleDescriptor parseDescriptor(ParserSettings ivySettings, URL descriptorURL,
47
boolean validate) throws ParseException, IOException {
48
return parseDescriptor(ivySettings, descriptorURL,
49
new URLResource(descriptorURL), validate);
52
public String getType() {
56
public Artifact getMetadataArtifact(ModuleRevisionId mrid, Resource res) {
57
return DefaultArtifact.newIvyArtifact(mrid, new Date(res.getLastModified()));
60
protected abstract static class AbstractParser extends DefaultHandler {
61
private static final String DEFAULT_CONF_MAPPING = "*->*";
63
private String defaultConf; // used only as defaultconf, not used for
65
// guesssing right side part of a mapping
66
private String defaultConfMapping; // same as default conf but is used
68
// for guesssing right side part of a mapping
69
private DefaultDependencyDescriptor defaultConfMappingDescriptor;
73
private List errors = new ArrayList();
75
private DefaultModuleDescriptor md;
77
private ModuleDescriptorParser parser;
79
protected AbstractParser(ModuleDescriptorParser parser) {
83
public ModuleDescriptorParser getModuleDescriptorParser() {
87
protected void checkErrors() throws ParseException {
88
if (!errors.isEmpty()) {
89
throw new ParseException(errors.toString(), 0);
93
public void setResource(Resource res) {
94
this.res = res; // used for log and date only
95
md = new DefaultModuleDescriptor(parser, res);
96
md.setLastModified(ResourceHelper.getLastModifiedOrDefault(res));
99
protected Resource getResource() {
103
protected String getDefaultConfMapping() {
104
return defaultConfMapping;
107
protected void setDefaultConfMapping(String defaultConf) {
108
defaultConfMapping = defaultConf;
111
protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd) {
112
parseDepsConfs(confs, dd, defaultConfMapping != null);
115
protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd,
116
boolean useDefaultMappingToGuessRightOperande) {
117
parseDepsConfs(confs, dd, useDefaultMappingToGuessRightOperande, true);
120
protected void parseDepsConfs(String confs, DefaultDependencyDescriptor dd,
121
boolean useDefaultMappingToGuessRightOperande, boolean evaluateConditions) {
126
String[] conf = confs.split(";");
127
parseDepsConfs(conf, dd, useDefaultMappingToGuessRightOperande, evaluateConditions);
130
protected void parseDepsConfs(String[] conf, DefaultDependencyDescriptor dd,
131
boolean useDefaultMappingToGuessRightOperande) {
132
parseDepsConfs(conf, dd, useDefaultMappingToGuessRightOperande, true);
135
protected void parseDepsConfs(String[] conf, DefaultDependencyDescriptor dd,
136
boolean useDefaultMappingToGuessRightOperande, boolean evaluateConditions) {
137
replaceConfigurationWildcards(md);
138
for (int i = 0; i < conf.length; i++) {
139
String[] ops = conf[i].split("->");
140
if (ops.length == 1) {
141
String[] modConfs = ops[0].split(",");
142
if (!useDefaultMappingToGuessRightOperande) {
143
for (int j = 0; j < modConfs.length; j++) {
144
dd.addDependencyConfiguration(modConfs[j].trim(), modConfs[j].trim());
147
for (int j = 0; j < modConfs.length; j++) {
148
String[] depConfs = getDefaultConfMappingDescriptor()
149
.getDependencyConfigurations(modConfs[j]);
150
if (depConfs.length > 0) {
151
for (int k = 0; k < depConfs.length; k++) {
152
String mappedDependency = evaluateConditions
153
? evaluateCondition(depConfs[k].trim(), dd)
154
: depConfs[k].trim();
155
if (mappedDependency != null) {
156
dd.addDependencyConfiguration(modConfs[j].trim(),
161
// no default mapping found for this configuration, map
162
// configuration to itself
163
dd.addDependencyConfiguration(modConfs[j].trim(), modConfs[j]
168
} else if (ops.length == 2) {
169
String[] modConfs = ops[0].split(",");
170
String[] depConfs = ops[1].split(",");
171
for (int j = 0; j < modConfs.length; j++) {
172
for (int k = 0; k < depConfs.length; k++) {
173
String mappedDependency = evaluateConditions ? evaluateCondition(
174
depConfs[k].trim(), dd) : depConfs[k].trim();
175
if (mappedDependency != null) {
176
dd.addDependencyConfiguration(modConfs[j].trim(), mappedDependency);
181
addError("invalid conf " + conf[i] + " for " + dd);
185
if (md.isMappingOverride()) {
186
addExtendingConfigurations(conf, dd, useDefaultMappingToGuessRightOperande);
191
* Evaluate the optional condition in the given configuration, like "[org=MYORG]confX". If
192
* the condition evaluates to true, the configuration is returned, if the condition
193
* evaluatate to false, null is returned. If there are no conditions, the configuration
194
* itself is returned.
197
* the configuration to evaluate
199
* the dependencydescriptor to which the configuration will be added
200
* @return the evaluated condition
202
private String evaluateCondition(String conf, DefaultDependencyDescriptor dd) {
203
if (conf.charAt(0) != '[') {
207
int endConditionIndex = conf.indexOf(']');
208
if (endConditionIndex == -1) {
209
addError("invalid conf " + conf + " for " + dd);
213
String condition = conf.substring(1, endConditionIndex);
215
int notEqualIndex = condition.indexOf("!=");
216
if (notEqualIndex == -1) {
217
int equalIndex = condition.indexOf('=');
218
if (equalIndex == -1) {
219
addError("invalid conf " + conf + " for " + dd.getDependencyRevisionId());
223
String leftOp = condition.substring(0, equalIndex).trim();
224
String rightOp = condition.substring(equalIndex + 1).trim();
226
// allow organisation synonyms, like 'org' or 'organization'
227
if (leftOp.equals("org") || leftOp.equals("organization")) {
228
leftOp = "organisation";
231
String attrValue = dd.getAttribute(leftOp);
232
if (!rightOp.equals(attrValue)) {
236
String leftOp = condition.substring(0, notEqualIndex).trim();
237
String rightOp = condition.substring(notEqualIndex + 2).trim();
239
// allow organisation synonyms, like 'org' or 'organization'
240
if (leftOp.equals("org") || leftOp.equals("organization")) {
241
leftOp = "organisation";
244
String attrValue = dd.getAttribute(leftOp);
245
if (rightOp.equals(attrValue)) {
250
return conf.substring(endConditionIndex + 1);
253
private void addExtendingConfigurations(String[] confs, DefaultDependencyDescriptor dd,
254
boolean useDefaultMappingToGuessRightOperande) {
255
for (int i = 0; i < confs.length; i++) {
256
addExtendingConfigurations(confs[i], dd, useDefaultMappingToGuessRightOperande);
260
private void addExtendingConfigurations(String conf, DefaultDependencyDescriptor dd,
261
boolean useDefaultMappingToGuessRightOperande) {
262
Set configsToAdd = new HashSet();
263
Configuration[] configs = md.getConfigurations();
264
for (int i = 0; i < configs.length; i++) {
265
String[] ext = configs[i].getExtends();
266
for (int j = 0; j < ext.length; j++) {
267
if (conf.equals(ext[j])) {
268
String configName = configs[i].getName();
269
configsToAdd.add(configName);
270
addExtendingConfigurations(configName, dd,
271
useDefaultMappingToGuessRightOperande);
276
String[] confs = (String[]) configsToAdd.toArray(new String[configsToAdd.size()]);
277
parseDepsConfs(confs, dd, useDefaultMappingToGuessRightOperande);
280
protected DependencyDescriptor getDefaultConfMappingDescriptor() {
281
if (defaultConfMappingDescriptor == null) {
282
defaultConfMappingDescriptor = new DefaultDependencyDescriptor(ModuleRevisionId
283
.newInstance("", "", ""), false);
284
parseDepsConfs(defaultConfMapping, defaultConfMappingDescriptor, false, false);
286
return defaultConfMappingDescriptor;
289
protected void addError(String msg) {
291
errors.add(msg + " in " + res + "\n");
293
errors.add(msg + "\n");
297
public void warning(SAXParseException ex) {
298
Message.warn("xml parsing: " + getLocationString(ex) + ": " + ex.getMessage());
301
public void error(SAXParseException ex) {
302
addError("xml parsing: " + getLocationString(ex) + ": " + ex.getMessage());
305
public void fatalError(SAXParseException ex) throws SAXException {
306
addError("[Fatal Error] " + getLocationString(ex) + ": " + ex.getMessage());
309
/** Returns a string of the location. */
310
private String getLocationString(SAXParseException ex) {
311
StringBuffer str = new StringBuffer();
313
String systemId = ex.getSystemId();
314
if (systemId != null) {
315
int index = systemId.lastIndexOf('/');
317
systemId = systemId.substring(index + 1);
319
str.append(systemId);
320
} else if (getResource() != null) {
321
str.append(getResource().toString());
324
str.append(ex.getLineNumber());
326
str.append(ex.getColumnNumber());
328
return str.toString();
330
} // getLocationString(SAXParseException):String
332
protected String getDefaultConf() {
333
return defaultConfMapping != null ? defaultConfMapping
334
: (defaultConf != null ? defaultConf : DEFAULT_CONF_MAPPING);
337
protected void setDefaultConf(String defaultConf) {
338
this.defaultConf = defaultConf;
341
public ModuleDescriptor getModuleDescriptor() throws ParseException {
346
protected Date getDefaultPubDate() {
347
return new Date(md.getLastModified());
350
private void replaceConfigurationWildcards(ModuleDescriptor md) {
351
Configuration[] configs = md.getConfigurations();
352
for (int i = 0; i < configs.length; i++) {
353
configs[i].replaceWildcards(md);
357
protected void setMd(DefaultModuleDescriptor md) {
361
protected DefaultModuleDescriptor getMd() {