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.plugins.resolver;
019:
020: import java.io.File;
021: import java.io.IOException;
022: import java.util.Collection;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.regex.Matcher;
028: import java.util.regex.Pattern;
029:
030: import org.apache.ivy.core.IvyPatternHelper;
031: import org.apache.ivy.core.module.descriptor.Artifact;
032: import org.apache.ivy.core.module.id.ModuleRevisionId;
033: import org.apache.ivy.plugins.repository.file.FileRepository;
034: import org.apache.ivy.util.Message;
035:
036: /**
037: */
038: public class FileSystemResolver extends RepositoryResolver {
039:
040: private static final String TRANSACTION_DESTINATION_SUFFIX = ".part";
041: private static final Pattern TRANSACTION_PATTERN = Pattern
042: .compile("(.*\\[revision\\])([/\\\\][^/\\\\]+)");
043:
044: /**
045: * Transactional mode.
046: *
047: * auto: use transaction if possible, only log verbose message if not
048: * true: always use transaction, fail if not supported
049: * false: never use transactions
050: */
051: private String transactional = "auto"; // one of 'auto', 'true' or 'false'
052:
053: /**
054: * When set indicates if this resolver supports transaction
055: */
056: private Boolean supportTransaction;
057: /**
058: * The pattern leading to the directory where files are published before being moved at the end
059: * of a transaction
060: */
061: private String baseTransactionPattern;
062: /**
063: * Map between actual patterns and patterns used during the transaction to put files in a
064: * temporary directory
065: */
066: private Map/*<String,String>*/fullTransactionPatterns = new HashMap();
067:
068: /**
069: * Is the current transaction open in overwrite mode?
070: */
071: private boolean overwriteTransaction = false;
072: /**
073: * Location where files are published during the transaction
074: */
075: private File transactionTempDir;
076: /**
077: * Location where files should end up at the end of the transaction
078: */
079: private File transactionDestDir;
080:
081: public FileSystemResolver() {
082: setRepository(new FileRepository());
083: }
084:
085: public String getTypeName() {
086: return "file";
087: }
088:
089: public boolean isLocal() {
090: return getFileRepository().isLocal();
091: }
092:
093: public void setLocal(boolean local) {
094: getFileRepository().setLocal(local);
095: }
096:
097: private FileRepository getFileRepository() {
098: return (FileRepository) getRepository();
099: }
100:
101: protected String getDestination(String pattern, Artifact artifact,
102: ModuleRevisionId mrid) {
103: if (supportTransaction() && !overwriteTransaction) {
104:
105: String destPattern = (String) fullTransactionPatterns
106: .get(pattern);
107: if (destPattern == null) {
108: throw new IllegalArgumentException(
109: "unsupported pattern for publish destination pattern: "
110: + pattern + ". supported patterns: "
111: + fullTransactionPatterns.keySet());
112: }
113: return IvyPatternHelper.substitute(destPattern, mrid,
114: artifact);
115: } else {
116: return super .getDestination(pattern, artifact, mrid);
117: }
118: }
119:
120: public void abortPublishTransaction() throws IOException {
121: if (supportTransaction() && !overwriteTransaction) {
122: if (transactionTempDir == null) {
123: throw new IllegalStateException(
124: "no current transaction!");
125: }
126: getFileRepository().delete(transactionTempDir);
127: Message.info("\tpublish aborted: deleted "
128: + transactionTempDir);
129: closeTransaction();
130: }
131: }
132:
133: public void commitPublishTransaction() throws IOException {
134: if (supportTransaction() && !overwriteTransaction) {
135: if (transactionTempDir == null) {
136: throw new IllegalStateException(
137: "no current transaction!");
138: }
139: getFileRepository().move(transactionTempDir,
140: transactionDestDir);
141: Message.info("\tpublish commited: moved "
142: + transactionTempDir + " \n\t\tto "
143: + transactionDestDir);
144: closeTransaction();
145: }
146: }
147:
148: public void beginPublishTransaction(ModuleRevisionId module,
149: boolean overwrite) throws IOException {
150: if (supportTransaction()) {
151: if (transactionTempDir != null) {
152: throw new IllegalStateException(
153: "a transaction is already started and not closed!");
154: }
155: overwriteTransaction = overwrite;
156: if (overwriteTransaction) {
157: unsupportedTransaction("overwrite transaction not supported yet");
158: } else {
159: initTransaction(module);
160: }
161: }
162: }
163:
164: protected Collection filterNames(Collection values) {
165: if (supportTransaction()) {
166: values = super .filterNames(values);
167: for (Iterator iterator = values.iterator(); iterator
168: .hasNext();) {
169: String v = (String) iterator.next();
170: if (v.endsWith(TRANSACTION_DESTINATION_SUFFIX)) {
171: iterator.remove();
172: }
173: }
174: return values;
175: } else {
176: return super .filterNames(values);
177: }
178: }
179:
180: public boolean supportTransaction() {
181: if ("false".equals(transactional)) {
182: return false;
183: }
184: checkSupportTransaction();
185: return supportTransaction.booleanValue();
186: }
187:
188: private void closeTransaction() {
189: transactionTempDir = null;
190: transactionDestDir = null;
191: }
192:
193: private void checkSupportTransaction() {
194: if (supportTransaction == null) {
195: List ivyPatterns = getIvyPatterns();
196: List artifactPatterns = getArtifactPatterns();
197:
198: if (ivyPatterns.size() > 0) {
199: String pattern = (String) ivyPatterns.get(0);
200: Matcher m = TRANSACTION_PATTERN.matcher(pattern);
201: if (!m.matches()) {
202: unsupportedTransaction("ivy pattern does not use revision as last directory");
203: return;
204: } else {
205: baseTransactionPattern = m.group(1);
206: fullTransactionPatterns.put(pattern, m.group(1)
207: + TRANSACTION_DESTINATION_SUFFIX
208: + m.group(2));
209: }
210: }
211: if (artifactPatterns.size() > 0) {
212: String pattern = (String) artifactPatterns.get(0);
213: Matcher m = TRANSACTION_PATTERN.matcher(pattern);
214: if (!m.matches()) {
215: unsupportedTransaction("ivy pattern does not use revision as last directory");
216: return;
217: } else if (baseTransactionPattern != null) {
218: if (!baseTransactionPattern.equals(m.group(1))) {
219: unsupportedTransaction("ivy pattern and artifact pattern "
220: + "do not use the same directory for revision");
221: return;
222: } else {
223: fullTransactionPatterns.put(pattern, m.group(1)
224: + TRANSACTION_DESTINATION_SUFFIX
225: + m.group(2));
226: }
227: } else {
228: baseTransactionPattern = m.group(1);
229: fullTransactionPatterns.put(pattern, m.group(1)
230: + TRANSACTION_DESTINATION_SUFFIX
231: + m.group(2));
232: }
233: }
234: supportTransaction = Boolean.TRUE;
235: }
236: }
237:
238: private void unsupportedTransaction(String msg) {
239: String fullMsg = getName() + " do not support transaction. "
240: + msg;
241: if ("true".equals(transactional)) {
242: throw new IllegalStateException(
243: fullMsg
244: + ". Set transactional attribute to 'auto' or 'false' or fix the problem.");
245: } else {
246: Message.verbose(fullMsg);
247: supportTransaction = Boolean.FALSE;
248: }
249: }
250:
251: private void initTransaction(ModuleRevisionId module) {
252: transactionTempDir = new File(IvyPatternHelper.substitute(
253: baseTransactionPattern, ModuleRevisionId.newInstance(
254: module, module.getRevision()
255: + TRANSACTION_DESTINATION_SUFFIX)));
256: transactionDestDir = new File(IvyPatternHelper.substitute(
257: baseTransactionPattern, module));
258: }
259:
260: public String getTransactional() {
261: return transactional;
262: }
263:
264: public void setTransactional(String transactional) {
265: this.transactional = transactional;
266: }
267:
268: }
|