| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.tools.ant.taskdefs.optional.vss; |
| |
| import org.apache.tools.ant.types.EnumeratedAttribute; |
| import java.io.File; |
| import java.io.IOException; |
| import java.text.DateFormat; |
| import java.text.ParseException; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.GregorianCalendar; |
| |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.taskdefs.Execute; |
| import org.apache.tools.ant.taskdefs.LogStreamHandler; |
| import org.apache.tools.ant.types.Commandline; |
| import org.apache.tools.ant.util.FileUtils; |
| |
| /** |
| * A base class for creating tasks for executing commands on Visual SourceSafe. |
| * <p> |
| * The class extends the 'exec' task as it operates by executing the ss.exe program |
| * supplied with SourceSafe. By default the task expects ss.exe to be in the path, |
| * you can override this be specifying the ssdir attribute. |
| * </p> |
| * <p> |
| * This class provides set and get methods for 'login' and 'vsspath' attributes. It |
| * also contains constants for the flags that can be passed to SS. |
| * </p> |
| * |
| */ |
| public abstract class MSVSS extends Task implements MSVSSConstants { |
| |
| private String ssDir = null; |
| private String vssLogin = null; |
| private String vssPath = null; |
| private String serverPath = null; |
| |
| /** Version */ |
| private String version = null; |
| /** Date */ |
| private String date = null; |
| /** Label */ |
| private String label = null; |
| /** Auto response */ |
| private String autoResponse = null; |
| /** Local path */ |
| private String localPath = null; |
| /** Comment */ |
| private String comment = null; |
| /** From label */ |
| private String fromLabel = null; |
| /** To label */ |
| private String toLabel = null; |
| /** Output file name */ |
| private String outputFileName = null; |
| /** User */ |
| private String user = null; |
| /** From date */ |
| private String fromDate = null; |
| /** To date */ |
| private String toDate = null; |
| /** History style */ |
| private String style = null; |
| /** Quiet defaults to false */ |
| private boolean quiet = false; |
| /** Recursive defaults to false */ |
| private boolean recursive = false; |
| /** Writable defaults to false */ |
| private boolean writable = false; |
| /** Fail on error defaults to true */ |
| private boolean failOnError = true; |
| /** Get local copy for checkout defaults to true */ |
| private boolean getLocalCopy = true; |
| /** Number of days offset for History */ |
| private int numDays = Integer.MIN_VALUE; |
| /** Date format for History */ |
| private DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT); |
| /** Timestamp for retreived files */ |
| private CurrentModUpdated timestamp = null; |
| /** Behaviour for writable files */ |
| private WritableFiles writableFiles = null; |
| |
| /** |
| * Each sub-class must implemnt this method and return the constructed |
| * command line to be executed. It is up to the sub-task to determine the |
| * required attrubutes and their order. |
| * @return The Constructed command line. |
| */ |
| abstract Commandline buildCmdLine(); |
| |
| /** |
| * Directory where <code>ss.exe</code> resides. |
| * By default the task expects it to be in the PATH. |
| * @param dir The directory containing ss.exe. |
| */ |
| public final void setSsdir(String dir) { |
| this.ssDir = FileUtils.translatePath(dir); |
| } |
| |
| /** |
| * Login to use when accessing VSS, formatted as "username,password". |
| * <p> |
| * You can omit the password if your database is not password protected. |
| * If you have a password and omit it, Ant will hang. |
| * @param vssLogin The login string to use. |
| */ |
| public final void setLogin(final String vssLogin) { |
| this.vssLogin = vssLogin; |
| } |
| |
| /** |
| * SourceSafe path which specifies the project/file(s) you wish to perform |
| * the action on. |
| * <p> |
| * A prefix of 'vss://' will be removed if specified. |
| * @param vssPath The VSS project path. |
| * @ant.attribute group="required" |
| */ |
| public final void setVsspath(final String vssPath) { |
| String projectPath; |
| // CheckStyle:MagicNumber OFF |
| if (vssPath.startsWith("vss://")) { //$NON-NLS-1$ |
| projectPath = vssPath.substring(5); |
| } else { |
| projectPath = vssPath; |
| } |
| // CheckStyle:MagicNumber ON |
| |
| if (projectPath.startsWith(PROJECT_PREFIX)) { |
| this.vssPath = projectPath; |
| } else { |
| this.vssPath = PROJECT_PREFIX + projectPath; |
| } |
| } |
| |
| /** |
| * Directory where <code>srssafe.ini</code> resides. |
| * @param serverPath The path to the VSS server. |
| */ |
| public final void setServerpath(final String serverPath) { |
| this.serverPath = serverPath; |
| } |
| |
| /** |
| * Indicates if the build should fail if the Sourcesafe command does. Defaults to true. |
| * @param failOnError True if task should fail on any error. |
| */ |
| public final void setFailOnError(final boolean failOnError) { |
| this.failOnError = failOnError; |
| } |
| |
| /** |
| * Executes the task. <br> |
| * Builds a command line to execute ss.exe and then calls Exec's run method |
| * to execute the command line. |
| * @throws BuildException if the command cannot execute. |
| */ |
| public void execute() throws BuildException { |
| int result = 0; |
| Commandline commandLine = buildCmdLine(); |
| result = run(commandLine); |
| if (Execute.isFailure(result) && getFailOnError()) { |
| String msg = "Failed executing: " + formatCommandLine(commandLine) |
| + " With a return code of " + result; |
| throw new BuildException(msg, getLocation()); |
| } |
| } |
| |
| // Special setters for the sub-classes |
| |
| /** |
| * Set the internal comment attribute. |
| * @param comment the value to use. |
| */ |
| protected void setInternalComment(final String comment) { |
| this.comment = comment; |
| } |
| |
| /** |
| * Set the auto response attribute. |
| * @param autoResponse the value to use. |
| */ |
| protected void setInternalAutoResponse(final String autoResponse) { |
| this.autoResponse = autoResponse; |
| } |
| |
| /** |
| * Set the date attribute. |
| * @param date the value to use. |
| */ |
| protected void setInternalDate(final String date) { |
| this.date = date; |
| } |
| |
| /** |
| * Set the date format attribute. |
| * @param dateFormat the value to use. |
| */ |
| protected void setInternalDateFormat(final DateFormat dateFormat) { |
| this.dateFormat = dateFormat; |
| } |
| |
| /** |
| * Set the failOnError attribute. |
| * @param failOnError the value to use. |
| */ |
| protected void setInternalFailOnError(final boolean failOnError) { |
| this.failOnError = failOnError; |
| } |
| |
| /** |
| * Set the from date attribute. |
| * @param fromDate the value to use. |
| */ |
| protected void setInternalFromDate(final String fromDate) { |
| this.fromDate = fromDate; |
| } |
| |
| /** |
| * Set the from label attribute. |
| * @param fromLabel the value to use. |
| */ |
| protected void setInternalFromLabel(final String fromLabel) { |
| this.fromLabel = fromLabel; |
| } |
| |
| /** |
| * Set the label attribute. |
| * @param label the value to use. |
| */ |
| protected void setInternalLabel(final String label) { |
| this.label = label; |
| } |
| |
| /** |
| * Set the local path comment attribute. |
| * @param localPath the value to use. |
| */ |
| protected void setInternalLocalPath(final String localPath) { |
| this.localPath = localPath; |
| } |
| |
| /** |
| * Set the num days attribute. |
| * @param numDays the value to use. |
| */ |
| protected void setInternalNumDays(final int numDays) { |
| this.numDays = numDays; |
| } |
| |
| /** |
| * Set the outputFileName comment attribute. |
| * @param outputFileName the value to use. |
| */ |
| protected void setInternalOutputFilename(final String outputFileName) { |
| this.outputFileName = outputFileName; |
| } |
| |
| /** |
| * Set the quiet attribute. |
| * @param quiet the value to use. |
| */ |
| protected void setInternalQuiet(final boolean quiet) { |
| this.quiet = quiet; |
| } |
| |
| /** |
| * Set the recursive attribute. |
| * @param recursive the value to use. |
| */ |
| protected void setInternalRecursive(final boolean recursive) { |
| this.recursive = recursive; |
| } |
| |
| /** |
| * Set the style attribute. |
| * @param style the value to use. |
| */ |
| protected void setInternalStyle(final String style) { |
| this.style = style; |
| } |
| |
| /** |
| * Set the to date attribute. |
| * @param toDate the value to use. |
| */ |
| protected void setInternalToDate(final String toDate) { |
| this.toDate = toDate; |
| } |
| |
| /** |
| * Set the to label attribute. |
| * @param toLabel the value to use. |
| */ |
| protected void setInternalToLabel(final String toLabel) { |
| this.toLabel = toLabel; |
| } |
| |
| /** |
| * Set the user attribute. |
| * @param user the value to use. |
| */ |
| protected void setInternalUser(final String user) { |
| this.user = user; |
| } |
| |
| /** |
| * Set the version attribute. |
| * @param version the value to use. |
| */ |
| protected void setInternalVersion(final String version) { |
| this.version = version; |
| } |
| |
| /** |
| * Set the writable attribute. |
| * @param writable the value to use. |
| */ |
| protected void setInternalWritable(final boolean writable) { |
| this.writable = writable; |
| } |
| |
| /** |
| * Set the timestamp attribute. |
| * @param timestamp the value to use. |
| */ |
| protected void setInternalFileTimeStamp(final CurrentModUpdated timestamp) { |
| this.timestamp = timestamp; |
| } |
| |
| /** |
| * Set the writableFiles attribute. |
| * @param writableFiles the value to use. |
| */ |
| protected void setInternalWritableFiles(final WritableFiles writableFiles) { |
| this.writableFiles = writableFiles; |
| } |
| |
| /** |
| * Set the getLocalCopy attribute. |
| * @param getLocalCopy the value to use. |
| */ |
| protected void setInternalGetLocalCopy(final boolean getLocalCopy) { |
| this.getLocalCopy = getLocalCopy; |
| } |
| |
| /** |
| * Gets the sscommand string. "ss" or "c:\path\to\ss" |
| * @return The path to ss.exe or just ss if sscommand is not set. |
| */ |
| protected String getSSCommand() { |
| if (ssDir == null) { |
| return SS_EXE; |
| } |
| return ssDir.endsWith(File.separator) ? ssDir + SS_EXE : ssDir |
| + File.separator + SS_EXE; |
| } |
| |
| /** |
| * Gets the vssserverpath string. |
| * @return null if vssserverpath is not set. |
| */ |
| protected String getVsspath() { |
| return vssPath; |
| } |
| |
| /** |
| * Gets the quiet string. -O- |
| * @return An empty string if quiet is not set or is false. |
| */ |
| protected String getQuiet() { |
| return quiet ? FLAG_QUIET : ""; |
| } |
| |
| /** |
| * Gets the recursive string. "-R" |
| * @return An empty string if recursive is not set or is false. |
| */ |
| protected String getRecursive() { |
| return recursive ? FLAG_RECURSION : ""; |
| } |
| |
| /** |
| * Gets the writable string. "-W" |
| * @return An empty string if writable is not set or is false. |
| */ |
| protected String getWritable() { |
| return writable ? FLAG_WRITABLE : ""; |
| } |
| |
| /** |
| * Gets the label string. "-Lbuild1" |
| * Max label length is 32 chars |
| * @return An empty string if label is not set. |
| */ |
| protected String getLabel() { |
| String shortLabel = ""; |
| if (label != null && label.length() > 0) { |
| shortLabel = FLAG_LABEL + getShortLabel(); |
| } |
| return shortLabel; |
| } |
| /** |
| * Return at most the 30 first chars of the label, |
| * logging a warning message about the truncation |
| * @return at most the 30 first chars of the label |
| */ |
| private String getShortLabel() { |
| String shortLabel; |
| // CheckStyle:MagicNumber OFF |
| if (label != null && label.length() > 31) { |
| shortLabel = this.label.substring(0, 30); |
| log("Label is longer than 31 characters, truncated to: " + shortLabel, |
| Project.MSG_WARN); |
| } else { |
| shortLabel = label; |
| } |
| // CheckStyle:MagicNumber ON |
| return shortLabel; |
| } |
| /** |
| * Gets the style string. "-Lbuild1" |
| * @return An empty string if label is not set. |
| */ |
| protected String getStyle() { |
| return style != null ? style : ""; |
| } |
| |
| /** |
| * Gets the version string. Returns the first specified of version "-V1.0", |
| * date "-Vd01.01.01", label "-Vlbuild1". |
| * @return An empty string if a version, date and label are not set. |
| */ |
| protected String getVersionDateLabel() { |
| String versionDateLabel = ""; |
| if (version != null) { |
| versionDateLabel = FLAG_VERSION + version; |
| } else if (date != null) { |
| versionDateLabel = FLAG_VERSION_DATE + date; |
| } else { |
| // Use getShortLabel() so labels longer then 30 char are truncated |
| // and the user is warned |
| String shortLabel = getShortLabel(); |
| if (shortLabel != null && !shortLabel.equals("")) { |
| versionDateLabel = FLAG_VERSION_LABEL + shortLabel; |
| } |
| } |
| return versionDateLabel; |
| } |
| |
| /** |
| * Gets the version string. |
| * @return An empty string if a version is not set. |
| */ |
| protected String getVersion() { |
| return version != null ? FLAG_VERSION + version : ""; |
| } |
| |
| /** |
| * Gets the localpath string. "-GLc:\source" <p> |
| * The localpath is created if it didn't exist. |
| * @return An empty string if localpath is not set. |
| */ |
| protected String getLocalpath() { |
| String lclPath = ""; //set to empty str if no local path return |
| if (localPath != null) { |
| //make sure m_LocalDir exists, create it if it doesn't |
| File dir = getProject().resolveFile(localPath); |
| if (!dir.exists()) { |
| boolean done = dir.mkdirs(); |
| if (!done) { |
| String msg = "Directory " + localPath + " creation was not " |
| + "successful for an unknown reason"; |
| throw new BuildException(msg, getLocation()); |
| } |
| getProject().log("Created dir: " + dir.getAbsolutePath()); |
| } |
| lclPath = FLAG_OVERRIDE_WORKING_DIR + localPath; |
| } |
| return lclPath; |
| } |
| |
| /** |
| * Gets the comment string. "-Ccomment text" |
| * @return A comment of "-" if comment is not set. |
| */ |
| protected String getComment() { |
| return comment != null ? FLAG_COMMENT + comment : FLAG_COMMENT + "-"; |
| } |
| |
| /** |
| * Gets the auto response string. This can be Y "-I-Y" or N "-I-N". |
| * @return The default value "-I-" if autoresponse is not set. |
| */ |
| protected String getAutoresponse() { |
| if (autoResponse == null) { |
| return FLAG_AUTORESPONSE_DEF; |
| } else if (autoResponse.equalsIgnoreCase("Y")) { |
| return FLAG_AUTORESPONSE_YES; |
| } else if (autoResponse.equalsIgnoreCase("N")) { |
| return FLAG_AUTORESPONSE_NO; |
| } else { |
| return FLAG_AUTORESPONSE_DEF; |
| } |
| } |
| |
| /** |
| * Gets the login string. This can be user and password, "-Yuser,password" |
| * or just user "-Yuser". |
| * @return An empty string if login is not set. |
| */ |
| protected String getLogin() { |
| return vssLogin != null ? FLAG_LOGIN + vssLogin : ""; |
| } |
| |
| /** |
| * Gets the output file string. "-Ooutput.file" |
| * @return An empty string if user is not set. |
| */ |
| protected String getOutput() { |
| return outputFileName != null ? FLAG_OUTPUT + outputFileName : ""; |
| } |
| |
| /** |
| * Gets the user string. "-Uusername" |
| * @return An empty string if user is not set. |
| */ |
| protected String getUser() { |
| return user != null ? FLAG_USER + user : ""; |
| } |
| |
| /** |
| * Gets the version string. This can be to-from "-VLbuild2~Lbuild1", from |
| * "~Lbuild1" or to "-VLbuild2". |
| * @return An empty string if neither tolabel or fromlabel are set. |
| */ |
| protected String getVersionLabel() { |
| if (fromLabel == null && toLabel == null) { |
| return ""; |
| } |
| // CheckStyle:MagicNumber OFF |
| if (fromLabel != null && toLabel != null) { |
| if (fromLabel.length() > 31) { |
| fromLabel = fromLabel.substring(0, 30); |
| log("FromLabel is longer than 31 characters, truncated to: " |
| + fromLabel, Project.MSG_WARN); |
| } |
| if (toLabel.length() > 31) { |
| toLabel = toLabel.substring(0, 30); |
| log("ToLabel is longer than 31 characters, truncated to: " |
| + toLabel, Project.MSG_WARN); |
| } |
| return FLAG_VERSION_LABEL + toLabel + VALUE_FROMLABEL + fromLabel; |
| } else if (fromLabel != null) { |
| if (fromLabel.length() > 31) { |
| fromLabel = fromLabel.substring(0, 30); |
| log("FromLabel is longer than 31 characters, truncated to: " |
| + fromLabel, Project.MSG_WARN); |
| } |
| return FLAG_VERSION + VALUE_FROMLABEL + fromLabel; |
| } else { |
| if (toLabel.length() > 31) { |
| toLabel = toLabel.substring(0, 30); |
| log("ToLabel is longer than 31 characters, truncated to: " |
| + toLabel, Project.MSG_WARN); |
| } |
| return FLAG_VERSION_LABEL + toLabel; |
| } |
| // CheckStyle:MagicNumber ON |
| } |
| |
| /** |
| * Gets the Version date string. |
| * @return An empty string if neither Todate or from date are set. |
| * @throws BuildException if there is an error. |
| */ |
| protected String getVersionDate() throws BuildException { |
| if (fromDate == null && toDate == null |
| && numDays == Integer.MIN_VALUE) { |
| return ""; |
| } |
| if (fromDate != null && toDate != null) { |
| return FLAG_VERSION_DATE + toDate + VALUE_FROMDATE + fromDate; |
| } else if (toDate != null && numDays != Integer.MIN_VALUE) { |
| try { |
| return FLAG_VERSION_DATE + toDate + VALUE_FROMDATE |
| + calcDate(toDate, numDays); |
| } catch (ParseException ex) { |
| String msg = "Error parsing date: " + toDate; |
| throw new BuildException(msg, getLocation()); |
| } |
| } else if (fromDate != null && numDays != Integer.MIN_VALUE) { |
| try { |
| return FLAG_VERSION_DATE + calcDate(fromDate, numDays) |
| + VALUE_FROMDATE + fromDate; |
| } catch (ParseException ex) { |
| String msg = "Error parsing date: " + fromDate; |
| throw new BuildException(msg, getLocation()); |
| } |
| } else { |
| return fromDate != null ? FLAG_VERSION + VALUE_FROMDATE |
| + fromDate : FLAG_VERSION_DATE + toDate; |
| } |
| } |
| |
| /** |
| * Builds and returns the -G- flag if required. |
| * @return An empty string if get local copy is true. |
| */ |
| protected String getGetLocalCopy() { |
| return (!getLocalCopy) ? FLAG_NO_GET : ""; |
| } |
| |
| /** |
| * Gets the value of the fail on error flag. |
| * @return True if the FailOnError flag has been set or if 'writablefiles=skip'. |
| */ |
| private boolean getFailOnError() { |
| return getWritableFiles().equals(WRITABLE_SKIP) ? false : failOnError; |
| } |
| |
| |
| /** |
| * Gets the value set for the FileTimeStamp. |
| * if it equals "current" then we return -GTC |
| * if it equals "modified" then we return -GTM |
| * if it equals "updated" then we return -GTU |
| * otherwise we return -GTC |
| * |
| * @return The default file time flag, if not set. |
| */ |
| public String getFileTimeStamp() { |
| if (timestamp == null) { |
| return ""; |
| } else if (timestamp.getValue().equals(TIME_MODIFIED)) { |
| return FLAG_FILETIME_MODIFIED; |
| } else if (timestamp.getValue().equals(TIME_UPDATED)) { |
| return FLAG_FILETIME_UPDATED; |
| } else { |
| return FLAG_FILETIME_DEF; |
| } |
| } |
| |
| |
| /** |
| * Gets the value to determine the behaviour when encountering writable files. |
| * @return An empty String, if not set. |
| */ |
| public String getWritableFiles() { |
| if (writableFiles == null) { |
| return ""; |
| } else if (writableFiles.getValue().equals(WRITABLE_REPLACE)) { |
| return FLAG_REPLACE_WRITABLE; |
| } else if (writableFiles.getValue().equals(WRITABLE_SKIP)) { |
| // ss.exe exits with '100', when files have been skipped |
| // so we have to ignore the failure |
| failOnError = false; |
| return FLAG_SKIP_WRITABLE; |
| } else { |
| return ""; |
| } |
| } |
| |
| /** |
| * Sets up the required environment and executes the command line. |
| * |
| * @param cmd The command line to execute. |
| * @return The return code from the exec'd process. |
| */ |
| private int run(Commandline cmd) { |
| try { |
| Execute exe = new Execute(new LogStreamHandler(this, |
| Project.MSG_INFO, |
| Project.MSG_WARN)); |
| |
| // If location of ss.ini is specified we need to set the |
| // environment-variable SSDIR to this value |
| if (serverPath != null) { |
| String[] env = exe.getEnvironment(); |
| if (env == null) { |
| env = new String[0]; |
| } |
| String[] newEnv = new String[env.length + 1]; |
| System.arraycopy(env, 0, newEnv, 0, env.length); |
| newEnv[env.length] = "SSDIR=" + serverPath; |
| |
| exe.setEnvironment(newEnv); |
| } |
| |
| exe.setAntRun(getProject()); |
| exe.setWorkingDirectory(getProject().getBaseDir()); |
| exe.setCommandline(cmd.getCommandline()); |
| // Use the OS launcher so we get environment variables |
| exe.setVMLauncher(false); |
| return exe.execute(); |
| } catch (IOException e) { |
| throw new BuildException(e, getLocation()); |
| } |
| } |
| |
| /** |
| * Calculates the start date for version comparison. |
| * <p> |
| * Calculates the date numDay days earlier than startdate. |
| * @param startDate The start date. |
| * @param daysToAdd The number of days to add. |
| * @return The calculated date. |
| * @throws ParseException |
| */ |
| private String calcDate(String startDate, int daysToAdd) throws ParseException { |
| Calendar calendar = new GregorianCalendar(); |
| Date currentDate = dateFormat.parse(startDate); |
| calendar.setTime(currentDate); |
| calendar.add(Calendar.DATE, daysToAdd); |
| return dateFormat.format(calendar.getTime()); |
| } |
| |
| /** |
| * Changes the password to '***' so it isn't displayed on screen if the build fails |
| * |
| * @param cmd The command line to clean |
| * @return The command line as a string with out the password |
| */ |
| private String formatCommandLine(Commandline cmd) { |
| StringBuffer sBuff = new StringBuffer(cmd.toString()); |
| int indexUser = sBuff.substring(0).indexOf(FLAG_LOGIN); |
| if (indexUser > 0) { |
| int indexPass = sBuff.substring(0).indexOf(",", indexUser); |
| int indexAfterPass = sBuff.substring(0).indexOf(" ", indexPass); |
| |
| for (int i = indexPass + 1; i < indexAfterPass; i++) { |
| sBuff.setCharAt(i, '*'); |
| } |
| } |
| return sBuff.toString(); |
| } |
| |
| /** |
| * Extention of EnumeratedAttribute to hold the values for file time stamp. |
| */ |
| public static class CurrentModUpdated extends EnumeratedAttribute { |
| /** |
| * Gets the list of allowable values. |
| * @return The values. |
| */ |
| public String[] getValues() { |
| return new String[] {TIME_CURRENT, TIME_MODIFIED, TIME_UPDATED}; |
| } |
| } |
| |
| /** |
| * Extention of EnumeratedAttribute to hold the values for writable filess. |
| */ |
| public static class WritableFiles extends EnumeratedAttribute { |
| /** |
| * Gets the list of allowable values. |
| * @return The values. |
| */ |
| public String[] getValues() { |
| return new String[] {WRITABLE_REPLACE, WRITABLE_SKIP, WRITABLE_FAIL}; |
| } |
| } |
| } |