001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.core;
019:
020: import java.util.ArrayList;
021: import java.util.Collections;
022: import java.util.HashMap;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Stack;
026: import java.util.regex.Matcher;
027: import java.util.regex.Pattern;
028:
029: import org.apache.ivy.core.cache.ArtifactOrigin;
030: import org.apache.ivy.core.cache.RepositoryCacheManager;
031: import org.apache.ivy.core.module.descriptor.Artifact;
032: import org.apache.ivy.core.module.descriptor.DefaultArtifact;
033: import org.apache.ivy.core.module.id.ModuleRevisionId;
034: import org.apache.ivy.core.settings.IvyVariableContainer;
035: import org.apache.ivy.core.settings.IvyVariableContainerImpl;
036: import org.apache.ivy.util.Message;
037:
038: /**
039: */
040: public final class IvyPatternHelper {
041:
042: private IvyPatternHelper() {
043: //Helper class
044: }
045:
046: public static final String CONF_KEY = "conf";
047:
048: public static final String TYPE_KEY = "type";
049:
050: public static final String EXT_KEY = "ext";
051:
052: public static final String ARTIFACT_KEY = "artifact";
053:
054: public static final String BRANCH_KEY = "branch";
055:
056: public static final String REVISION_KEY = "revision";
057:
058: public static final String MODULE_KEY = "module";
059:
060: public static final String ORGANISATION_KEY = "organisation";
061:
062: public static final String ORGANISATION_KEY2 = "organization";
063:
064: public static final String ORIGINAL_ARTIFACTNAME_KEY = "originalname";
065:
066: private static final Pattern PARAM_PATTERN = Pattern
067: .compile("\\@\\{(.*?)\\}");
068:
069: private static final Pattern VAR_PATTERN = Pattern
070: .compile("\\$\\{(.*?)\\}");
071:
072: public static String substitute(String pattern,
073: ModuleRevisionId moduleRevision) {
074: return substitute(pattern, moduleRevision.getOrganisation(),
075: moduleRevision.getName(), moduleRevision.getRevision(),
076: "ivy", "ivy", "xml", null, moduleRevision
077: .getAttributes());
078: }
079:
080: public static String substitute(String pattern,
081: ModuleRevisionId moduleRevision, String artifact,
082: String type, String ext) {
083: return substitute(pattern, moduleRevision, new DefaultArtifact(
084: moduleRevision, null, artifact, type, ext), null);
085: }
086:
087: public static String substitute(String pattern, Artifact artifact) {
088: return substitute(pattern, artifact, (String) null);
089: }
090:
091: public static String substitute(String pattern, Artifact artifact,
092: ArtifactOrigin origin) {
093: return substitute(pattern, artifact.getModuleRevisionId(),
094: artifact, null, origin);
095: }
096:
097: public static String substitute(String pattern, Artifact artifact,
098: String conf) {
099: return substitute(pattern, artifact.getModuleRevisionId(),
100: artifact, conf);
101: }
102:
103: public static String substitute(String pattern,
104: ModuleRevisionId mrid, Artifact artifact) {
105: return substitute(pattern, mrid, artifact, null);
106: }
107:
108: public static String substitute(String pattern,
109: ModuleRevisionId mrid, Artifact artifact, String conf) {
110: return substitute(pattern, mrid, artifact, conf, null);
111: }
112:
113: public static String substitute(String pattern,
114: ModuleRevisionId mrid, Artifact artifact, String conf,
115: ArtifactOrigin origin) {
116: Map attributes = new HashMap();
117: attributes.putAll(mrid.getAttributes());
118: attributes.putAll(artifact.getAttributes());
119: return substitute(pattern, mrid.getOrganisation(), mrid
120: .getName(), mrid.getBranch(), mrid.getRevision(),
121: artifact.getName(), artifact.getType(), artifact
122: .getExt(), conf, origin, attributes);
123: }
124:
125: public static String substitute(String pattern, String org,
126: String module, String revision, String artifact,
127: String type, String ext) {
128: return substitute(pattern, org, module, revision, artifact,
129: type, ext, null);
130: }
131:
132: public static String substitute(String pattern, String org,
133: String module, String revision, String artifact,
134: String type, String ext, String conf) {
135: return substitute(pattern, org, module, revision, artifact,
136: type, ext, conf, null);
137: }
138:
139: public static String substitute(String pattern, String org,
140: String module, String revision, String artifact,
141: String type, String ext, String conf, Map extraAttributes) {
142: return substitute(pattern, org, module, revision, artifact,
143: type, ext, conf, null, extraAttributes);
144: }
145:
146: public static String substitute(String pattern, String org,
147: String module, String revision, String artifact,
148: String type, String ext, String conf,
149: ArtifactOrigin origin, Map extraAttributes) {
150: return substitute(pattern, org, module, null, revision,
151: artifact, type, ext, conf, origin, extraAttributes);
152: }
153:
154: public static String substitute(String pattern, String org,
155: String module, String branch, String revision,
156: String artifact, String type, String ext, String conf,
157: ArtifactOrigin origin, Map extraAttributes) {
158: Map tokens = new HashMap(
159: extraAttributes == null ? Collections.EMPTY_MAP
160: : extraAttributes);
161: tokens.put(ORGANISATION_KEY, org == null ? "" : org);
162: tokens.put(ORGANISATION_KEY2, org == null ? "" : org);
163: tokens.put(MODULE_KEY, module == null ? "" : module);
164: tokens.put(BRANCH_KEY, branch == null ? "" : branch);
165: tokens.put(REVISION_KEY, revision == null ? "" : revision);
166: tokens.put(ARTIFACT_KEY, artifact == null ? module : artifact);
167: tokens.put(TYPE_KEY, type == null ? "jar" : type);
168: tokens.put(EXT_KEY, ext == null ? "jar" : ext);
169: tokens.put(CONF_KEY, conf == null ? "default" : conf);
170: tokens.put(ORIGINAL_ARTIFACTNAME_KEY,
171: origin == null ? new OriginalArtifactNameValue(org,
172: module, branch, revision, artifact, type, ext)
173: : new OriginalArtifactNameValue(origin));
174: return substituteTokens(pattern, tokens);
175: }
176:
177: public static String substituteVariables(String pattern,
178: Map variables) {
179: return substituteVariables(pattern,
180: new IvyVariableContainerImpl(variables), new Stack());
181: }
182:
183: public static String substituteVariables(String pattern,
184: IvyVariableContainer variables) {
185: return substituteVariables(pattern, variables, new Stack());
186: }
187:
188: private static String substituteVariables(String pattern,
189: IvyVariableContainer variables, Stack substituting) {
190: // if you supply null, null is what you get
191: if (pattern == null) {
192: return null;
193: }
194:
195: Matcher m = VAR_PATTERN.matcher(pattern);
196:
197: StringBuffer sb = new StringBuffer();
198: while (m.find()) {
199: String var = m.group(1);
200: String val = (String) variables.getVariable(var);
201: if (val != null) {
202: int index = substituting.indexOf(var);
203: if (index != -1) {
204: List cycle = new ArrayList(substituting.subList(
205: index, substituting.size()));
206: cycle.add(var);
207: throw new IllegalArgumentException(
208: "cyclic variable definition: cycle = "
209: + cycle);
210: }
211: substituting.push(var);
212: val = substituteVariables(val, variables, substituting);
213: substituting.pop();
214: } else {
215: val = m.group();
216: }
217: m.appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\")
218: .replaceAll("\\$", "\\\\\\$"));
219: }
220: m.appendTail(sb);
221:
222: return sb.toString();
223: }
224:
225: public static String substituteTokens(String pattern, Map tokens) {
226: StringBuffer buffer = new StringBuffer();
227:
228: char[] chars = pattern.toCharArray();
229:
230: StringBuffer optionalPart = null;
231: StringBuffer tokenBuffer = null;
232: boolean insideOptionalPart = false;
233: boolean insideToken = false;
234: boolean tokenHadValue = false;
235:
236: for (int i = 0; i < chars.length; i++) {
237: switch (chars[i]) {
238: case '(':
239: if (insideOptionalPart) {
240: throw new IllegalArgumentException(
241: "invalid start of optional part at position "
242: + i + " in pattern " + pattern);
243: }
244:
245: optionalPart = new StringBuffer();
246: insideOptionalPart = true;
247: tokenHadValue = false;
248: break;
249:
250: case ')':
251: if (!insideOptionalPart || insideToken) {
252: throw new IllegalArgumentException(
253: "invalid end of optional part at position "
254: + i + " in pattern " + pattern);
255: }
256:
257: if (tokenHadValue) {
258: buffer.append(optionalPart.toString());
259: }
260:
261: insideOptionalPart = false;
262: break;
263:
264: case '[':
265: if (insideToken) {
266: throw new IllegalArgumentException(
267: "invalid start of token at position " + i
268: + " in pattern " + pattern);
269: }
270:
271: tokenBuffer = new StringBuffer();
272: insideToken = true;
273: break;
274:
275: case ']':
276: if (!insideToken) {
277: throw new IllegalArgumentException(
278: "invalid end of token at position " + i
279: + " in pattern " + pattern);
280: }
281:
282: String token = tokenBuffer.toString();
283: Object tokenValue = tokens.get(token);
284: String value = (tokenValue == null) ? null : tokenValue
285: .toString();
286:
287: if (insideOptionalPart) {
288: tokenHadValue = (value != null)
289: && (value.length() > 0);
290: optionalPart.append(value);
291: } else {
292: if (value == null) { // the token wasn't set, it's kept as is
293: value = "[" + token + "]";
294: }
295: buffer.append(value);
296: }
297:
298: insideToken = false;
299: break;
300:
301: default:
302: if (insideToken) {
303: tokenBuffer.append(chars[i]);
304: } else if (insideOptionalPart) {
305: optionalPart.append(chars[i]);
306: } else {
307: buffer.append(chars[i]);
308: }
309:
310: break;
311: }
312: }
313:
314: if (insideToken) {
315: throw new IllegalArgumentException(
316: "last token hasn't been closed in pattern "
317: + pattern);
318: }
319:
320: if (insideOptionalPart) {
321: throw new IllegalArgumentException(
322: "optional part hasn't been closed in pattern "
323: + pattern);
324: }
325:
326: return buffer.toString();
327: }
328:
329: public static String substituteVariable(String pattern,
330: String variable, String value) {
331: StringBuffer buf = new StringBuffer(pattern);
332: substituteVariable(buf, variable, value);
333: return buf.toString();
334: }
335:
336: public static void substituteVariable(StringBuffer buf,
337: String variable, String value) {
338: String from = "${" + variable + "}";
339: int fromLength = from.length();
340: for (int index = buf.indexOf(from); index != -1; index = buf
341: .indexOf(from, index)) {
342: buf.replace(index, index + fromLength, value);
343: }
344: }
345:
346: public static String substituteToken(String pattern, String token,
347: String value) {
348: StringBuffer buf = new StringBuffer(pattern);
349: substituteToken(buf, token, value);
350: return buf.toString();
351: }
352:
353: public static void substituteToken(StringBuffer buf, String token,
354: String value) {
355: String from = getTokenString(token);
356: int fromLength = from.length();
357: for (int index = buf.indexOf(from); index != -1; index = buf
358: .indexOf(from, index)) {
359: buf.replace(index, index + fromLength, value);
360: }
361: }
362:
363: public static String getTokenString(String token) {
364: return "[" + token + "]";
365: }
366:
367: public static String substituteParams(String pattern, Map params) {
368: return substituteParams(pattern, new IvyVariableContainerImpl(
369: params), new Stack());
370: }
371:
372: private static String substituteParams(String pattern,
373: IvyVariableContainer params, Stack substituting) {
374: // TODO : refactor this with substituteVariables
375: // if you supply null, null is what you get
376: if (pattern == null) {
377: return null;
378: }
379:
380: Matcher m = PARAM_PATTERN.matcher(pattern);
381:
382: StringBuffer sb = new StringBuffer();
383: while (m.find()) {
384: String var = m.group(1);
385: String val = (String) params.getVariable(var);
386: if (val != null) {
387: int index = substituting.indexOf(var);
388: if (index != -1) {
389: List cycle = new ArrayList(substituting.subList(
390: index, substituting.size()));
391: cycle.add(var);
392: throw new IllegalArgumentException(
393: "cyclic param definition: cycle = " + cycle);
394: }
395: substituting.push(var);
396: val = substituteVariables(val, params, substituting);
397: substituting.pop();
398: } else {
399: val = m.group();
400: }
401: m.appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\")
402: .replaceAll("\\@", "\\\\\\@"));
403: }
404: m.appendTail(sb);
405:
406: return sb.toString();
407: }
408:
409: /**
410: * This class returns the original name of the artifact 'on demand'. This is done to avoid
411: * having to read the cached datafile containing the original location of the artifact if we
412: * don't need it.
413: */
414: private static class OriginalArtifactNameValue {
415: // module properties
416: private String org;
417:
418: private String moduleName;
419:
420: private String branch;
421:
422: private String revision;
423:
424: // artifact properties
425: private String artifactName;
426:
427: private String artifactType;
428:
429: private String artifactExt;
430:
431: // cached origin;
432: private ArtifactOrigin origin;
433:
434: public OriginalArtifactNameValue(String org, String moduleName,
435: String branch, String revision, String artifactName,
436: String artifactType, String artifactExt) {
437: this .org = org;
438: this .moduleName = moduleName;
439: this .branch = branch;
440: this .revision = revision;
441: this .artifactName = artifactName;
442: this .artifactType = artifactType;
443: this .artifactExt = artifactExt;
444: }
445:
446: /**
447: * @param origin
448: */
449: public OriginalArtifactNameValue(ArtifactOrigin origin) {
450: this .origin = origin;
451: }
452:
453: // Called by substituteTokens only if the original artifact name is needed
454: public String toString() {
455: if (origin == null) {
456: ModuleRevisionId revId = ModuleRevisionId.newInstance(
457: org, moduleName, branch, revision);
458: Artifact artifact = new DefaultArtifact(revId, null,
459: artifactName, artifactType, artifactExt);
460:
461: // TODO cache: see how we could know which actual cache manager to use, since this
462: // will fail when using a resolver in a chain with a specific cache manager
463: RepositoryCacheManager cacheManager = IvyContext
464: .getContext().getSettings().getResolver(revId)
465: .getRepositoryCacheManager();
466:
467: origin = cacheManager.getSavedArtifactOrigin(artifact);
468:
469: if (origin == ArtifactOrigin.UNKNOWN) {
470: Message.debug("no artifact origin found for "
471: + artifact + " in " + cacheManager);
472: return null;
473: }
474: }
475:
476: if (origin == ArtifactOrigin.UNKNOWN) {
477: return null;
478: }
479:
480: // we assume that the original filename is the last part of the original file location
481: String location = origin.getLocation();
482: int lastPathIndex = location.lastIndexOf('/');
483: if (lastPathIndex == -1) {
484: lastPathIndex = location.lastIndexOf('\\');
485: }
486: int lastColonIndex = location.lastIndexOf('.');
487:
488: return location
489: .substring(lastPathIndex + 1, lastColonIndex);
490: }
491: }
492:
493: public static String getTokenRoot(String pattern) {
494: int index = pattern.indexOf('[');
495: if (index == -1) {
496: return pattern;
497: } else {
498: return pattern.substring(0, index);
499: }
500: }
501: }
|