/* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://www.sun.com/cddl/cddl.html or
* install_dir/legal/LICENSE
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at install_dir/legal/LICENSE.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id$
*
* Copyright 2005-2009 Sun Microsystems Inc. All Rights Reserved
*/
package com.sun.faban.harness.webclient;
import com.sun.faban.harness.common.Config;
import com.sun.faban.harness.common.RunId;
import com.sun.faban.harness.util.FileHelper;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.io.File;
import java.util.ArrayList;
import java.util.logging.Logger;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import static com.sun.faban.harness.util.FileHelper.*;
/**
* This is a controller class.
*
* @author Sheetal Patil
*/
public class Uploader {
private static Logger logger = Logger.getLogger(ResultAction.class.getName());
/**
* Checks the existence of the runs on the repository.
* @param request
* @param response
* @return String
* @throws java.io.IOException
* @throws javax.servlet.ServletException
*/
public String checkRuns(HttpServletRequest request, HttpServletResponse
response) throws IOException, ServletException {
HashSet<String> duplicateSet = new HashSet<String>();
String host = request.getParameter("host");
String[] runIds = request.getParameterValues("runId");
String[] ts = request.getParameterValues("ts");
for (int r=0; r< runIds.length ; r++){
String runId = runIds[r];
if (checkIfArchived(host+"."+runId)){
//check for runId timestamp
String reposTs =
getRunIdTimestamp(host + "." + runId, Config.OUT_DIR);
if (ts[r].equals(reposTs)) {
duplicateSet.add(runId);
}
}
response.setStatus(HttpServletResponse.SC_OK);
}
request.setAttribute("duplicates", duplicateSet);
return "/duplicates.jsp";
}
private String getRunIdTimestamp(String runId, String dir) {
char[] cBuf = null;
String[] status = new String[2];
int length = -1;
try {
FileReader reader = new FileReader(dir + runId + '/'
+ Config.RESULT_INFO);
cBuf = new char[128];
length = reader.read(cBuf);
reader.close();
} catch (IOException e) {
// Do nothing, length = -1.
}
String content = new String(cBuf, 0, length);
int idx = content.indexOf('\t');
if (idx != -1) {
status[0] = content.substring(0, idx).trim();
status[1] = content.substring(++idx).trim();
} else {
status[0] = content.trim();
}
return status[1];
}
private String getNextRunId(String runId) {
RunId current = new RunId(runId);
String seq = current.getRunSeq(); // Say "1A1"
int i = 0;
for (; i < seq.length(); i++) {
if (Character.isLetter(seq.charAt(i)))
break;
} // i now points to 'A'
String origSeq = seq.substring(0, i + 1); // origSeq = "1A"
String cDup = seq.substring(i + 1); // cDup = "1"
String nDup = null;
if (cDup.length() == 0) {
nDup = "0";
} else {
int x = Integer.parseInt(cDup, 16); // x = (int) 1
nDup = Integer.toHexString(++x).toUpperCase(); // nDup - "2"
}
RunId next = new RunId(current.getHostName(),
current.getBenchName(), origSeq + nDup);
return next.toString();
}
private boolean checkIfArchived(String runId) {
boolean found = false;
File file = new File(Config.OUT_DIR + runId + '/' +
Config.RESULT_INFO);
found = file.exists();
return found;
}
/**
* Updates the tags file.
* @param req
* @param resp
* @throws java.io.IOException
*/
public void updateTagsFile(HttpServletRequest req,
HttpServletResponse resp) throws IOException{
String tags = req.getParameter("tags");
String runId = req.getParameter("runId");
RunResult result = RunResult.getInstance(new RunId(runId));
StringBuilder formattedTags = new StringBuilder();
File runTagFile = new File(Config.OUT_DIR + runId + "/META-INF/tags");
if (tags != null && !"".equals(tags)) {
StringTokenizer t = new StringTokenizer(tags," \n,");
ArrayList<String> tagList = new ArrayList<String>(t.countTokens());
while (t.hasMoreTokens()) {
String nextT = t.nextToken().trim();
if( nextT != null && !"".equals(nextT) ){
formattedTags.append(nextT + "\n");
tagList.add(nextT);
}
}
FileHelper.writeContentToFile(formattedTags.toString(), runTagFile);
result.tags = tagList.toArray(new String[tagList.size()]);
}
try {
uploadTags(runId);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Uploader.class.getName()).log(Level.SEVERE, null, ex);
}
Writer w = resp.getWriter();
w.write("Tags updating completed");
w.flush();
w.close();
}
/**
* Updates the run description.
* @param req
* @param resp
* @throws java.io.IOException
*/
public void updateRunDesc(HttpServletRequest req,
HttpServletResponse resp) throws IOException{
String runId = req.getParameter("runId");
RunResult result = RunResult.getInstance(new RunId(runId));
result.description = req.getParameter("desc");
ResultAction.editXML(result);
Writer w = resp.getWriter();
w.write("Tags updating completed");
w.flush();
w.close();
}
private void uploadTags(String runId) throws IOException, ClassNotFoundException {
File file = new File(Config.OUT_DIR + runId + "/META-INF/tags");
String tags = FileHelper.readContentFromFile(file);
TagEngine te = TagEngine.getInstance();
String[] tagsArray;
if (tags != null && !"".equals(tags)) {
StringTokenizer tok = new StringTokenizer(tags," ");
tagsArray = new String[tok.countTokens()];
int count = tok.countTokens();
int i=0;
while(i < count){
String nextT = tok.nextToken().trim();
tagsArray[i] = nextT;
i++;
}
te.add(runId, tagsArray);
}else{
te.add(runId, new String[0]);
}
te.save();
}
/**
* Responsible for uploading the runs.
* @param request
* @param response
* @return String
* @throws java.io.IOException
* @throws javax.servlet.ServletException
* @throws java.lang.ClassNotFoundException
*/
public String uploadRuns(HttpServletRequest request, HttpServletResponse
response) throws IOException, ServletException, ClassNotFoundException {
// 3. Upload the run
HashSet<String> duplicateSet = new HashSet<String>();
HashSet<String> replaceSet = new HashSet<String>();
String host = null;
String key = null;
boolean origin = false; // Whether the upload is to the original
// run requestor. If so, key is needed.
DiskFileUpload fu = new DiskFileUpload();
// No maximum size
fu.setSizeMax(-1);
// maximum size that will be stored in memory
fu.setSizeThreshold(4096);
// the location for saving data that is larger than
// getSizeThreshold()
fu.setRepositoryPath(Config.TMP_DIR);
List fileItems = null;
try {
fileItems = fu.parseRequest(request);
} catch (FileUploadException e) {
throw new ServletException(e);
}
// assume we know there are two files. The first file is a small
// text file, the second is unknown and is written to a file on
// the server
for (Iterator i = fileItems.iterator(); i.hasNext();) {
FileItem item = (FileItem) i.next();
String fieldName = item.getFieldName();
if (item.isFormField()) {
if ("host".equals(fieldName)) {
host = item.getString();
} else if ("replace".equals(fieldName)) {
replaceSet.add(item.getString());
} else if ("key".equals(fieldName)) {
key = item.getString();
} else if ("origin".equals(fieldName)) {
String value = item.getString();
origin = Boolean.parseBoolean(value);
}
continue;
}
if (host == null) {
logger.warning("Host not received on upload request!");
response.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
}
// The host, origin, key info must be here before we receive
// any file.
if (origin) {
if (Config.daemonMode != Config.DaemonModes.POLLEE) {
logger.warning("Origin upload requested. Not pollee!");
response.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
}
if (key == null) {
logger.warning("Origin upload requested. No key!");
response.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
}
if (!RunRetriever.authenticate(host, key)) {
logger.warning("Origin upload requested. " +
"Host/key mismatch: " +host + '/' + key + "!");
response.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
}
}
if (!"jarfile".equals(fieldName)) // ignore
continue;
String fileName = item.getName();
if (fileName == null) // We don't process files without names
continue;
// Now, this name may have a path attached, dependent on the
// source browser. We need to cover all possible clients...
char[] pathSeparators = {'/', '\\'};
// Well, if there is another separator we did not account for,
// just add it above.
for (int j = 0; j < pathSeparators.length; j++) {
int idx = fileName.lastIndexOf(pathSeparators[j]);
if (idx != -1) {
fileName = fileName.substring(idx + 1);
break;
}
}
// Ignore all non-jarfiles.
if (!fileName.toLowerCase().endsWith(".jar"))
continue;
File uploadFile = new File(Config.TMP_DIR, host + '.' +
fileName);
try {
item.write(uploadFile);
} catch (Exception e) {
throw new ServletException(e);
}
int runIdx = fileName.lastIndexOf(".");
String runName = host + '.' + fileName.substring(0, runIdx);
File runTmp = unjarTmp(uploadFile);
//Check if archived recently
if (checkIfArchived(runName) &&
!(replaceSet.contains(fileName.substring(0, runIdx)))) {
//Now check if timestamps are same
//Get the timestamp of run being uploaded at this point
//ts is timestamp of run being uploaded
String ts = getRunIdTimestamp(runName,Config.TMP_DIR);
l1: while (true) {
//reposTs is timestamp of run being compared in the
//repository
String reposTs =
getRunIdTimestamp(runName,Config.OUT_DIR);
if (reposTs.equals(ts)){
duplicateSet.add(fileName.substring(0, runIdx));
}else{
runName = getNextRunId(runName);
if (checkIfArchived(runName))
continue l1;
File newRunNameFile = new File(Config.OUT_DIR,
runName);
if (newRunNameFile.exists()) {
recursiveDelete(newRunNameFile);
}
if (recursiveCopy(runTmp, newRunNameFile)) {
newRunNameFile.setLastModified(runTmp.lastModified());
uploadTags(runName);
uploadFile.delete();
recursiveDelete(runTmp);
} else {
logger.warning("Origin upload requested. " +
"Copy error!");
response.sendError(
HttpServletResponse.SC_NOT_ACCEPTABLE);
break;
}
response.setStatus(HttpServletResponse.SC_CREATED);
}
break;
}
}else{
//File runTmp = unjarTmp(uploadFile);
String runId = null;
if (origin) {
// Change origin file to know where this run came from.
File metaInf = new File(runTmp, "META-INF");
File originFile = new File(metaInf, "origin");
if (!originFile.exists()) {
logger.warning("Origin upload requested. " +
"Origin file does not exist!");
response.sendError(
HttpServletResponse.SC_NOT_ACCEPTABLE,
"Origin file does not exist!");
break;
}
RunId origRun;
try {
origRun = new RunId(
readStringFromFile(originFile).trim());
} catch (IndexOutOfBoundsException e) {
response.sendError(
HttpServletResponse.SC_NOT_ACCEPTABLE,
"Origin file error. " + e.getMessage());
break;
}
runId = origRun.getBenchName() + '.' +
origRun.getRunSeq();
String localHost = origRun.getHostName();
if (!localHost.equals(Config.FABAN_HOST)) {
logger.warning("Origin upload requested. Origin " +
"host" + localHost + " does not match this host " +
Config.FABAN_HOST + '!');
response.sendError(
HttpServletResponse.SC_FORBIDDEN);
break;
}
writeStringToFile(runTmp.getName(), originFile);
} else {
runId = runTmp.getName();
}
File newRunFile = new File(Config.OUT_DIR, runId);
if(newRunFile.exists()){
recursiveDelete(newRunFile);
}
if (recursiveCopy(runTmp, newRunFile)){
newRunFile.setLastModified(runTmp.lastModified());
uploadFile.delete();
uploadTags(runId);
recursiveDelete(runTmp);
} else {
logger.warning("Origin upload requested. Copy error!");
response.sendError(
HttpServletResponse.SC_NOT_ACCEPTABLE);
break;
}
}
response.setStatus(HttpServletResponse.SC_CREATED);
//break;
}
request.setAttribute("duplicates", duplicateSet);
return "/duplicates.jsp";
}
}