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: package org.apache.pluto.util.assemble;
018:
019: import java.io.File;
020: import java.io.IOException;
021:
022: import org.apache.commons.io.FileUtils;
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.apache.pluto.util.UtilityException;
026:
027: /**
028: * A base class that assembler implementations should extend.
029: *
030: * The purpose of this class is to ensure consistent behavior
031: * when performing assembly.
032: */
033: public abstract class AbstractArchiveAssembler extends
034: WebXmlRewritingAssembler {
035:
036: private static final Log LOG = LogFactory
037: .getLog(AbstractArchiveAssembler.class);
038:
039: /**
040: * This implementation throws <code>UtilityException</code> if the source
041: * archive doesn't exist or is a directory. If the destination archive is
042: * null, it assumes that in-place assembly is dessired. It determines
043: * if the source archive should be replaced with the destination archive
044: * and provisions temporary files as needed.
045: */
046: public void assemble(AssemblerConfig config)
047: throws UtilityException {
048: File source = config.getSource();
049: File dest = config.getDestination();
050:
051: try {
052:
053: if (source == null || !source.exists()) {
054: throw new UtilityException(
055: "Source archive doesn't exist.");
056: }
057:
058: if (source.isDirectory()) {
059: throw new UtilityException(
060: "Source archive is a directory.");
061: }
062:
063: if (performInPlaceAssembly(config)) {
064: if (LOG.isDebugEnabled()) {
065: LOG.debug("Performing in-place assembly of "
066: + config.getSource().getAbsolutePath());
067: }
068: dest = File.createTempFile(source.getName(), ".tmp");
069: config.setDestination(dest);
070: assembleInternal(config);
071: // renameTo() is impl-specific
072: boolean success = dest.renameTo(source);
073: if (!success) {
074: // do it the old-fashioned way
075: FileUtils.copyFile(dest, source);
076: }
077: } else {
078: if (LOG.isDebugEnabled()) {
079: LOG
080: .debug("Performing assembly of "
081: + config.getSource()
082: .getAbsolutePath()
083: + " to "
084: + config.getDestination()
085: .getAbsolutePath());
086: }
087: File destFile = dest;
088:
089: // if the destination is a directory, ensure that parent
090: // directories have been created and set the destination
091: // file to the file in the direcotory.
092: if (dest.isDirectory()) {
093: dest.mkdirs();
094: destFile = new File(dest, source.getName());
095: }
096:
097: config.setDestination(destFile);
098: assembleInternal(config);
099: }
100:
101: } catch (IOException e) {
102: LOG.error("Assembly failed: " + e.getMessage());
103: throw new UtilityException(e.getMessage(), e);
104: }
105: }
106:
107: /**
108: * Performs a series of checks to determine whether or not the assembly should
109: * occur "in-place" - that is, if the source archive will be assembled and then
110: * replaced by the destination archive.
111: * <p/>
112: * <ul>
113: * <li>If the destination is null, then perform in place assembly.</li>
114: * <li>If the destination is equal to the source, then perform in place assembly.</li>
115: * </ul>
116: * @param config the AssemblerConfig
117: * @return true if in-place configuration should occur
118: */
119: protected boolean performInPlaceAssembly(
120: final AssemblerConfig config) {
121: // If the destination wasn't provided, in-place assembly is inferred
122: if (config.getDestination() == null) {
123: return true;
124: }
125:
126: // If the source and the destination are the same, in-place
127: // assembly has been explicitly requested by the caller
128: if (config.getDestination().equals(config.getSource())) {
129: return true;
130: }
131:
132: // If the destination is the parent directory of the source, then
133: // in-place assembly is inferred.
134: if (config.getDestination().equals(
135: config.getSource().getParentFile())) {
136: return true;
137: }
138:
139: return false;
140: }
141:
142: /**
143: * Assemble the source file to the destination file. The superclass is responsible for ensuring
144: * correct and not-null values for the source and destination, and for temporary file handling
145: * used during in-place assembly.
146: *
147: * @param config the assembler configuration object
148: * @throws UtilityException
149: * @throws IOException
150: */
151: protected abstract void assembleInternal(AssemblerConfig config)
152: throws UtilityException, IOException;
153:
154: }
|