/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/**
* Manages transferred files delivered via the request or response {@link Payload}.
* <p>
* Callers can process the entire payload
* at once, treating each Part as a file, using the {@link #processParts}
* method. Or, the caller can invoke the {@link #processPart}
* method to work with a single Part as a file.
* <p>
* If the caller wants to extract the payload's content as temporary files it should
* instantiate {@link Temp} which exposes a {@link PayLoadFilesManager.Temp#cleanup}
* method. The caller should invoke this method once it has finished with
* the transferred files, although the finalizer will invoke cleanup just in case.
* <p>
* On the other hand, if the caller wants to keep the transferred files it
* should instantiate {@link Perm}.
* <p>
* <code>Temp</code> uses a unique temporary directory, then creates one
* temp file for each part it is asked to deal with, either from an entire payload
* ({@link #processParts(org.glassfish.api.admin.Payload.Inbound)}) or a
* single part ({@link #processPart(org.glassfish.api.admin.Payload.Part)}). Recall that each part in the
* payload has a name which is a relative or absolute URI.
*
* @author tjquinn
*/
public abstract class PayloadFilesManager {
public final static LocalStringManagerImpl strings = new LocalStringManagerImpl(PayloadFilesManager.class);
private PayloadFilesManager(
final ActionReport report,
final ActionReportHandler reportHandler) {
this.reportHandler = reportHandler;
}
private PayloadFilesManager(
final ActionReport report,
}
return targetDir;
}
/*
* parentURI and parentFile start as the target extraction directory for this
* manager, but will change iff the part specifies a file
* transfer root.
*/
if (parentPathFromPart != null) {
}
if (xferRootFile.isAbsolute()) {
} else {
}
/*
* If this parent directory does not exist, then the URI from
* the File object will lack the trailing slash. So create
* the URI a little oddly to account for that case.
*/
}
return parentFileURI;
}
/**
* Extracts files from a Payload and leaves them on disk.
* <p>
* The Perm manager constructs output file paths this way. The URI from the
* manager's targetDir (which the caller passes to the constructor) is the default
* parent URI for the output file.
* <p>
* Next, the Part's properties are checked for a file-xfer-root property.
* If found, it is used as a URI (either absolute or, if relative, resolved
* against the targetDir).
* <p>
* Finally, the "output name" is either the
* name from the Payload.Part for the {@link #extractFile(org.glassfish.api.admin.Payload.Part) }
* method or the caller-provided argument in the {@link #extractFile(org.glassfish.api.admin.Payload.Part, java.lang.String) }
* method.
* <p>
* In either case, the output name is used as a URI
* string and is resolved against the targetDir combined with (if present) the
* file-xfer-root property.
* <p>
* The net effect of this
* is that if the output name is an absolute URI then it will override the
* targetDir and the file-xfer-root setting. If the output name is
* relative then it will be resolved
* against the targetDir plus file-xfer-root URI to derive the URI for the output file.
*/
/**
* Creates a new PayloadFilesManager for dealing with permanent files that
* will be anchored at the specified target directory.
* @param targetDir directory under which the payload's files should be stored
* @param report result report to which extraction results will be appened
* @param logger logger to receive messages
*/
}
/**
* Creates a new PayloadFilesManager for permanent files anchored at
* the specified target directory.
* @param targetDir directory under which the payload's files should be stored
* @param report result report to which extraction results will be appened
* @param logger logger to receive messages
* @param reportHandler handler to invoke for each ActionReport in the payload
*/
}
/**
* Creates a new PayloadFilesManager for permanent files anchored at
* the caller's current directory.
* @param report result report to which extraction results will be appended
* @param logger logger to receive messages
*/
}
/**
* Creates a new PayloadFilesManager for permanent files anchored at
* the caller's current directory.
* @param report result report to which extraction results will be appened
* @param logger logger to receive messages
* @param reportHandler handler to invoke for each ActionReport in the payload
*/
final ActionReportHandler reportHandler) {
}
/**
* Creates a new PayloadFilesManager for permanent files anchored at
* the caller's current directory.
* @param logger logger to receive messages
*/
}
/**
* Creates a new PayloadFilesManager for permanent files anchored at
* the caller's current directory.
*/
public Perm() {
this((ActionReportHandler) null);
}
}
// no-op for permanent files
}
protected void postProcessParts() {
if (isFine) {
logger.log(Level.FINER, "Setting lastModified for {0} explicitly to {1}", new Object[]{entry.getKey().getAbsolutePath(), when});
}
"payload.setLatModifiedFailed",
"Attempt to set lastModified for {0} failed; no further information is available. Continuing.",
}
}
}
}
/**
* Extracts files from a payload, treating them as temporary files.
* The caller should invoke {@link #cleanup} once it is finished with the
* extracted files, although the finalizer will invoke cleanup if the
* caller has not.
*/
// /*
// * regex to match colons and backslashes on Windows and slashes on non-Windows
// */
// private static final String DIR_PATH_TO_FLAT_NAME_PATTERN = (File.separatorChar == '\\') ?
// "[:\\\\]" : "/";
private boolean isCleanedUp = false;
// /** maps payload part name paths (excluding name and type) to temp file subdirs */
// private Map<String,File> pathToTempSubdir = new HashMap<String,File>();
super(createTempFolder(
logger),
logger);
}
/**
* Creates a new PayloadFilesManager for temporary files.
* @param report results report to which extraction results will be appended
* @param logger logger to receive messages
* @throws java.io.IOException
*/
}
/**
* Creates a new PayloadFilesManager for temporary files.
* @param logger logger to receive messages
* @throws java.io.IOException
*/
}
/**
* Deletes the temporary files created by this temp PayloadFilesManager.
*/
public void cleanup() {
if ( ! isCleanedUp) {
isCleanedUp = true;
}
}
super.finalize();
cleanup();
}
}
protected void postProcessParts() {
// no-op
}
// private String getParentPath(String partName) {
// if (partName.endsWith("/")) {
// partName = partName.substring(0, partName.length() - 1);
// }
// int lastSlash = partName.lastIndexOf('/');
// if (lastSlash != -1) {
// return partName.substring(0, lastSlash);
// }
// return null;
// }
// URI getTempSubDirForPath(String path) throws IOException {
// /*
// * Convert the path (which is currently in URI form) to
// * the local file system form.
// */
// path = path.replace('/', File.separatorChar);
// File tempSubDir = pathToTempSubdir.get(path);
// if (tempSubDir == null) {
// /*
// * Replace slashes (forward or backward) that are directory
// * separators and replace colons (from Windows devices) with single
// * dashes. This technique generates unique but flat directory
// * names so same-named files in different directories will
// * go to different directories.
// *
// * The extra dashes make sure the prefix meets createTempFile's reqts.
// *
// */
// String tempDirPrefix = path.replaceAll(DIR_PATH_TO_FLAT_NAME_PATTERN, "-") + "---";
// tempSubDir = createTempFolder(getTargetDir(), tempDirPrefix, super.logger);
// pathToTempSubdir.put(path, tempSubDir);
// }
// return tempSubDir.toURI();
// }
// private String getNameAndType(String path) {
// if (path.endsWith("/")) {
// path = path.substring(0, path.length() - 1);
// }
// final int lastSlash = path.lastIndexOf('/');
// return path.substring(lastSlash + 1);
// }
}
/*
* The part name might have path elements using / as the
* separator, so figure out the full path for the resulting
* file.
*/
}
return targetURI;
}
return result;
}
if (targetFile.exists()) {
if (isRemovalRecursive ?
if (isFine) {
logger.log(Level.FINER, "Deleted {0}{1} as requested", new Object[]{targetFile.getAbsolutePath(), isRemovalRecursive ? " recursively" : ""});
}
} else {
if (isFine) {
logger.log(Level.FINER, "File {0} ({1}) requested for deletion exists but was not able to be deleted", new Object[]{part.getName(), targetFile.getAbsolutePath()});
}
"Requested deletion of {0} failed; the file was found but the deletion attempt failed - no reason is available"));
}
} else {
if (isFine) {
logger.log(Level.FINER, "File {0} ({1}) requested for deletion does not exist.", new Object[]{part.getName(), targetFile.getAbsolutePath()});
}
}
return targetFile;
}
}
try {
}
} finally {
}
}
}
if (reportHandler != null) {
} else {
}
}
/**
* Extracts the contents of the specified Part as a file, specifying
* the relative or absolute URI to use for creating the extracted file.
* If outputName is relative it is resolved against the manager's target
* directory (which the caller passed to the constructor) and the
* file-xfer-root Part property, if present.
* @param part the Part containing the file's contents
* @param outputName absolute or relative URI string to use for the extracted file
* @return File for the extracted file
* @throws java.io.IOException
*/
/*
* Look in the Part's properties first for the URI of the target
* directory for the file. If there is none there then use the
* target directory for this manager.
*/
try {
/*
* Create the required directory tree under the target directory.
*/
"payload.mkdirsFailed",
"Attempt to create directories for {0} failed; no further information is available. Continuing.",
}
if (extractedFile.exists()) {
/*
* Don't warn if we cannot delete the directory - there
* are likely to be files in it preventing its removal.
*/
"payload.overwrite",
"Overwriting previously-uploaded file because the attempt to delete it failed: {0}",
} else if (isFine) {
logger.log(Level.FINER, "Deleted pre-existing file {0} before extracting transferred file", extractedFile.getAbsolutePath());
}
}
/*
* If we are extracting a directory, then we need to consume the
* Part's body but we won't write anything into the directory
* file.
*/
"Attempt to create directories for {0} failed; no further information is available. Continuing.",
}
}
int bytesRead;
}
}
}
"payload.setLatModifiedFailed",
"Attempt to set lastModified for {0} failed; no further information is available. Continuing.",
}
if (extractedFile.isDirectory()) {
}
logger.log(Level.FINER, "Extracted transferred entry {0} to {1}", new Object[]{part.getName(), extractedFile.getAbsolutePath()});
return extractedFile;
}
catch (IOException e) {
throw new IOException(e.getMessage(), e);
} finally {
}
}
}
/**
* Returns all Files extracted from the Payload, treating each Part as a
* separate file, via a Map from each File to its associated Properties.
*
* @param inboundPayload Payload containing file data to be extracted
* @return map from each extracted File to its corresponding Properties
* @throws java.io.IOException
*/
if (inboundPayload == null) {
return Collections.EMPTY_MAP;
}
boolean isReportProcessed = false;
} else {
}
}
}
isReportProcessed = true;
}
return result;
}
/**
* Returns all Files extracted from the Payload, treating each Part as a
* separate file.
* @param inboundPayload Payload containing file data to be extracted
* @parma reportHandler invoked for each ActionReport Part in the payload
* @return the Files corresponding to the content of each extracted file
* @throws java.io.IOException
*/
}
public static interface ActionReportHandler {
}
protected abstract void postProcessParts();
private void reportExtractionSuccess() {
}
private void reportSuccess() {
}
}
private void reportDeletionSuccess() {
}
}
"payload.errDeleting",
"Error deleting file {0}",
partName), e);
}
private void reportFailure(final String partName, final String formattedMessage, final Exception e) {
}
}
"payload.errExtracting",
"Error extracting transferred file {0}",
partName),
e);
}
/**
* Creates a unique temporary directory within the specified parent.
* @param parent directory within which to create the temp dir; will be created if absent
* @return the temporary folder
* @throws java.io.IOException
*/
private static File createTempFolder(final File parent, final String prefix, final Logger logger) throws IOException {
try {
throw new IOException(
"payload.command.errorDeletingTempFile",
"Unknown error deleting temporary file {0}",
result.getAbsolutePath()));
}
throw new IOException(
"payload.command.errorCreatingDir",
"Unknown error creating directory {0}",
result.getAbsolutePath()));
}
return result;
} catch (Exception e) {
"payload.command.errorCreatingXferFolder",
"Error creating temporary file transfer folder"), e);
}
}
}
/**
* Types of data requests the PayloadFilesManager understands.
* <p>
* To add a new type, add a new enum value with the value of the data
* request type as the constructor argument and implement the processPart
* method.
*/
private enum DataRequestType {
protected File processPart(
final PayloadFilesManager pfm,
}
},
protected File processPart(
final PayloadFilesManager pfm,
}
},
protected File processPart(
final PayloadFilesManager pfm,
}
},
protected File processPart(
final PayloadFilesManager pfm, final
return null;
}
};
/** data-request-type value for this enum */
/**
* Creates a new instance of the enum
* @param type
*/
}
/**
* Processes the specified part by delegating to the right method on
* the PayloadFilesManager.
* @param pfm
* @param part
* @param partName
* @return
* @throws IOException
*/
throws Exception;
/**
* Finds the DataRequestType enum which matches the data-request-type
* in the Part's properties.
* @param part
* @return DataRequestType matching the Part's data-request-type; null if no match exists
*/
return candidateType;
}
}
return null;
}
}
}