private CIJobStatus deleteCI(CIJob job, List<String> builds) throws PhrescoException { S_LOGGER.debug("Entering Method CIManagerImpl.deleteCI(CIJob job)"); S_LOGGER.debug("Job name " + job.getName()); cli = getCLI(job); String deleteType = null; List<String> argList = new ArrayList<String>(); S_LOGGER.debug("job name " + job.getName()); S_LOGGER.debug("Builds " + builds); if (CollectionUtils.isEmpty(builds)) { // delete job S_LOGGER.debug("Job deletion started"); S_LOGGER.debug("Command " + FrameworkConstants.CI_JOB_DELETE_COMMAND); deleteType = DELETE_TYPE_JOB; argList.add(FrameworkConstants.CI_JOB_DELETE_COMMAND); argList.add(job.getName()); } else { // delete Build S_LOGGER.debug("Build deletion started"); deleteType = DELETE_TYPE_BUILD; argList.add(FrameworkConstants.CI_BUILD_DELETE_COMMAND); argList.add(job.getName()); StringBuilder result = new StringBuilder(); for (String string : builds) { result.append(string); result.append(","); } String buildNos = result.substring(0, result.length() - 1); argList.add(buildNos); S_LOGGER.debug("Command " + FrameworkConstants.CI_BUILD_DELETE_COMMAND); S_LOGGER.debug("Build numbers " + buildNos); } try { int status = cli.execute(argList); String message = deleteType + " deletion started in jenkins"; if (status == FrameworkConstants.JOB_STATUS_NOTOK) { deleteType = deleteType.substring(0, 1).toLowerCase() + deleteType.substring(1); message = "Error while deleting " + deleteType + " in jenkins"; } S_LOGGER.debug("Delete CI Status " + status); S_LOGGER.debug("Delete CI Message " + message); return new CIJobStatus(status, message); } finally { if (cli != null) { try { cli.close(); } catch (IOException e) { if (debugEnabled) { S_LOGGER.error( "Entered into catch block of CIManagerImpl.deleteCI(CIJob job) " + e.getLocalizedMessage()); } } catch (InterruptedException e) { if (debugEnabled) { S_LOGGER.error( "Entered into catch block of CIManagerImpl.deleteCI(CIJob job) " + e.getLocalizedMessage()); } } } } }
private CLI getCLI(CIJob job) throws PhrescoException { if (debugEnabled) { S_LOGGER.debug("Entering Method CIManagerImpl.getCLI()"); } String jenkinsUrl = HTTP_PROTOCOL + PROTOCOL_POSTFIX + job.getJenkinsUrl() + COLON + job.getJenkinsPort() + FORWARD_SLASH + CI + FORWARD_SLASH; if (debugEnabled) { S_LOGGER.debug("jenkinsUrl to get cli object " + jenkinsUrl); } try { return new CLI(new URL(jenkinsUrl)); } catch (MalformedURLException e) { throw new PhrescoException(e); } catch (IOException e) { throw new PhrescoException(e); } catch (InterruptedException e) { throw new PhrescoException(e); } }
public List<CIBuild> getBuilds(CIJob job) throws PhrescoException { if (debugEnabled) { S_LOGGER.debug("Entering Method CIManagerImpl.getCIBuilds(CIJob job)"); } List<CIBuild> ciBuilds = null; try { if (debugEnabled) { S_LOGGER.debug("getCIBuilds() JobName = " + job.getName()); } JsonArray jsonArray = getBuildsArray(job); ciBuilds = new ArrayList<CIBuild>(jsonArray.size()); Gson gson = new Gson(); CIBuild ciBuild = null; for (int i = 0; i < jsonArray.size(); i++) { ciBuild = gson.fromJson(jsonArray.get(i), CIBuild.class); setBuildStatus(ciBuild, job); String buildUrl = ciBuild.getUrl(); String jenkinUrl = job.getJenkinsUrl() + ":" + job.getJenkinsPort(); buildUrl = buildUrl.replaceAll( "localhost:" + job.getJenkinsPort(), jenkinUrl); // when displaying url it should display setup machine ip ciBuild.setUrl(buildUrl); ciBuilds.add(ciBuild); } } catch (Exception e) { if (debugEnabled) { S_LOGGER.debug( "Entering Method CIManagerImpl.getCIBuilds(CIJob job) " + e.getLocalizedMessage()); } } return ciBuilds; }
private CIJobStatus buildJob(CIJob job) throws PhrescoException { if (debugEnabled) { S_LOGGER.debug("Entering Method CIManagerImpl.buildJob(CIJob job)"); } cli = getCLI(job); List<String> argList = new ArrayList<String>(); argList.add(FrameworkConstants.CI_BUILD_JOB_COMMAND); argList.add(job.getName()); try { int status = cli.execute(argList); String message = FrameworkConstants.CI_BUILD_STARTED; if (status == FrameworkConstants.JOB_STATUS_NOTOK) { message = FrameworkConstants.CI_BUILD_STARTING_ERROR; } return new CIJobStatus(status, message); } finally { if (cli != null) { try { cli.close(); } catch (IOException e) { if (debugEnabled) { S_LOGGER.error(e.getLocalizedMessage()); } } catch (InterruptedException e) { if (debugEnabled) { S_LOGGER.error(e.getLocalizedMessage()); } } } } }
private void setSvnCredential(CIJob job) throws JDOMException, IOException { S_LOGGER.debug("Entering Method CIManagerImpl.setSvnCredential"); try { String jenkinsTemplateDir = Utility.getJenkinsTemplateDir(); String credentialFilePath = jenkinsTemplateDir + job.getRepoType() + HYPHEN + CREDENTIAL_XML; if (debugEnabled) { S_LOGGER.debug("credentialFilePath ... " + credentialFilePath); } File credentialFile = new File(credentialFilePath); SvnProcessor processor = new SvnProcessor(credentialFile); // DataInputStream in = new DataInputStream(new FileInputStream(credentialFile)); // while (in.available() != 0) { // System.out.println(in.readLine()); // } // in.close(); processor.changeNodeValue("credentials/entry//userName", job.getUserName()); processor.changeNodeValue("credentials/entry//password", job.getPassword()); processor.writeStream(new File(Utility.getJenkinsHome() + File.separator + job.getName())); // jenkins home location String jenkinsJobHome = System.getenv(JENKINS_HOME); StringBuilder builder = new StringBuilder(jenkinsJobHome); builder.append(File.separator); processor.writeStream(new File(builder.toString() + CI_CREDENTIAL_XML)); } catch (Exception e) { S_LOGGER.error( "Entered into the catch block of CIManagerImpl.setSvnCredential " + e.getLocalizedMessage()); } }
public void updateJob(ApplicationInfo appInfo, CIJob job) throws PhrescoException { if (debugEnabled) { S_LOGGER.debug( "Entering Method ProjectAdministratorImpl.updateJob(Project project, CIJob job)"); } FileWriter writer = null; try { CIJobStatus jobStatus = configureJob(job, FrameworkConstants.CI_UPDATE_JOB_COMMAND); if (jobStatus.getCode() == -1) { throw new PhrescoException(jobStatus.getMessage()); } if (debugEnabled) { S_LOGGER.debug("getCustomModules() ProjectInfo = " + appInfo); } updateJsonJob(appInfo, job); } catch (ClientHandlerException ex) { if (debugEnabled) { S_LOGGER.error(ex.getLocalizedMessage()); } throw new PhrescoException(ex); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { if (debugEnabled) { S_LOGGER.error(e.getLocalizedMessage()); } } } } }
// When already existing adapted project is created , need to move to new adapted project private boolean deleteCIJobFile(ApplicationInfo appInfo) throws PhrescoException { S_LOGGER.debug("Entering Method ProjectAdministratorImpl.deleteCI()"); try { File ciJobInfo = new File(getCIJobPath(appInfo)); return ciJobInfo.delete(); } catch (ClientHandlerException ex) { S_LOGGER.error( "Entered into catch block of ProjectAdministratorImpl.deleteCI()" + ex.getLocalizedMessage()); throw new PhrescoException(ex); } }
private String getJsonResponse(String jsonUrl) throws PhrescoException { if (debugEnabled) { S_LOGGER.debug("Entering Method CIManagerImpl.getJsonResponse(String jsonUrl)"); S_LOGGER.debug("getJsonResponse() JSonUrl = " + jsonUrl); } try { HttpClient httpClient = new DefaultHttpClient(); HttpGet httpget = new HttpGet(jsonUrl); ResponseHandler<String> responseHandler = new BasicResponseHandler(); return httpClient.execute(httpget, responseHandler); } catch (IOException e) { throw new PhrescoException(e); } }
private void setBuildStatus(CIBuild ciBuild, CIJob job) throws PhrescoException { S_LOGGER.debug("Entering Method CIManagerImpl.setBuildStatus(CIBuild ciBuild)"); S_LOGGER.debug("setBuildStatus() url = " + ciBuild.getUrl()); String buildUrl = ciBuild.getUrl(); String jenkinsUrl = job.getJenkinsUrl() + ":" + job.getJenkinsPort(); buildUrl = buildUrl.replaceAll( "localhost:" + job.getJenkinsPort(), jenkinsUrl); // display the jenkins running url in ci list String response = getJsonResponse(buildUrl + API_JSON); JsonParser parser = new JsonParser(); JsonElement jsonElement = parser.parse(response); JsonObject jsonObject = jsonElement.getAsJsonObject(); JsonElement resultJson = jsonObject.get(FrameworkConstants.CI_JOB_BUILD_RESULT); JsonElement idJson = jsonObject.get(FrameworkConstants.CI_JOB_BUILD_ID); JsonElement timeJson = jsonObject.get(FrameworkConstants.CI_JOB_BUILD_TIME_STAMP); JsonArray asJsonArray = jsonObject.getAsJsonArray(FrameworkConstants.CI_JOB_BUILD_ARTIFACTS); if (jsonObject .get(FrameworkConstants.CI_JOB_BUILD_RESULT) .toString() .equals(STRING_NULL)) { // when build is result is not known ciBuild.setStatus(INPROGRESS); } else if (resultJson.getAsString().equals(CI_SUCCESS_FLAG) && asJsonArray.size() < 1) { // when build is success and zip relative path is not added in json ciBuild.setStatus(INPROGRESS); } else { ciBuild.setStatus(resultJson.getAsString()); // download path for (JsonElement jsonArtElement : asJsonArray) { String buildDownloadZip = jsonArtElement .getAsJsonObject() .get(FrameworkConstants.CI_JOB_BUILD_DOWNLOAD_PATH) .toString(); if (buildDownloadZip.endsWith(CI_ZIP)) { if (debugEnabled) { S_LOGGER.debug("download artifact " + buildDownloadZip); } ciBuild.setDownload(buildDownloadZip); } } } ciBuild.setId(idJson.getAsString()); String dispFormat = DD_MM_YYYY_HH_MM_SS; ciBuild.setTimeStamp(getDate(timeJson.getAsString(), dispFormat)); }
private void setMailCredential(CIJob job) { if (debugEnabled) { S_LOGGER.debug("Entering Method CIManagerImpl.setMailCredential"); } try { String jenkinsTemplateDir = Utility.getJenkinsTemplateDir(); String mailFilePath = jenkinsTemplateDir + MAIL + HYPHEN + CREDENTIAL_XML; if (debugEnabled) { S_LOGGER.debug("configFilePath ... " + mailFilePath); } File mailFile = new File(mailFilePath); SvnProcessor processor = new SvnProcessor(mailFile); // DataInputStream in = new DataInputStream(new FileInputStream(mailFile)); // while (in.available() != 0) { // System.out.println(in.readLine()); // } // in.close(); // Mail have to go with jenkins running email address InetAddress ownIP = InetAddress.getLocalHost(); processor.changeNodeValue( CI_HUDSONURL, HTTP_PROTOCOL + PROTOCOL_POSTFIX + ownIP.getHostAddress() + COLON + job.getJenkinsPort() + FORWARD_SLASH + CI + FORWARD_SLASH); processor.changeNodeValue("smtpAuthUsername", job.getSenderEmailId()); processor.changeNodeValue("smtpAuthPassword", job.getSenderEmailPassword()); processor.changeNodeValue("adminAddress", job.getSenderEmailId()); // jenkins home location String jenkinsJobHome = System.getenv(JENKINS_HOME); StringBuilder builder = new StringBuilder(jenkinsJobHome); builder.append(File.separator); processor.writeStream(new File(builder.toString() + CI_MAILER_XML)); } catch (Exception e) { S_LOGGER.error( "Entered into the catch block of CIManagerImpl.setMailCredential " + e.getLocalizedMessage()); } }
protected void logParams() { Enumeration en = req.getParameterNames(); while (en.hasMoreElements()) { String name = (String) en.nextElement(); String vals[]; String dispval; if (StringUtil.indexOfIgnoreCase(name, "passw") >= 0) { dispval = req.getParameter(name).length() == 0 ? "" : "********"; } else if (log.isDebug2() && (vals = req.getParameterValues(name)).length > 1) { dispval = StringUtil.separatedString(vals, ", "); } else { dispval = req.getParameter(name); } log.debug(name + " = " + dispval); } }
private int getProgressInBuild(CIJob job) throws PhrescoException { S_LOGGER.debug("Entering Method CIManagerImpl.isBuilding(CIJob job)"); String jenkinsUrl = HTTP_PROTOCOL + PROTOCOL_POSTFIX + job.getJenkinsUrl() + COLON + job.getJenkinsPort() + FORWARD_SLASH + CI + FORWARD_SLASH; String isBuildingUrlUrl = BUSY_EXECUTORS; String jsonResponse = getJsonResponse(jenkinsUrl + isBuildingUrlUrl); int buidInProgress = Integer.parseInt(jsonResponse); S_LOGGER.debug("buidInProgress " + buidInProgress); return buidInProgress; }
public int getTotalBuilds(ApplicationInfo appInfo) throws PhrescoException { try { CIJob ciJob = getJob(appInfo); return getTotalBuilds(ciJob); } catch (ClientHandlerException ex) { S_LOGGER.error(ex.getLocalizedMessage()); throw new PhrescoException(ex); } }
private CIJob getJob(ApplicationInfo appInfo) throws PhrescoException { Gson gson = new Gson(); try { BufferedReader br = new BufferedReader(new FileReader(getCIJobPath(appInfo))); CIJob job = gson.fromJson(br, CIJob.class); br.close(); return job; } catch (FileNotFoundException e) { S_LOGGER.debug(e.getLocalizedMessage()); return null; } catch (com.google.gson.JsonParseException e) { S_LOGGER.debug("it is already adpted project !!!!! " + e.getLocalizedMessage()); return null; } catch (IOException e) { S_LOGGER.debug(e.getLocalizedMessage()); return null; } }
public List<CIJob> getJobs(ApplicationInfo appInfo) throws PhrescoException { S_LOGGER.debug("GetJobs Called!"); try { boolean adaptedProject = adaptExistingJobs(appInfo); S_LOGGER.debug("Project adapted for new feature => " + adaptedProject); Gson gson = new Gson(); BufferedReader br = new BufferedReader(new FileReader(getCIJobPath(appInfo))); Type type = new TypeToken<List<CIJob>>() {}.getType(); List<CIJob> jobs = gson.fromJson(br, type); br.close(); return jobs; } catch (FileNotFoundException e) { S_LOGGER.debug("FileNotFoundException"); return null; } catch (IOException e) { S_LOGGER.debug("IOException"); throw new PhrescoException(e); } }
public CIJobStatus deleteJobs(ApplicationInfo appInfo, List<String> jobNames) throws PhrescoException { S_LOGGER.debug("Entering Method ProjectAdministratorImpl.deleteCI()"); try { CIJobStatus deleteCI = null; for (String jobName : jobNames) { S_LOGGER.debug(" Deleteable job name " + jobName); CIJob ciJob = getJob(appInfo, jobName); // job and build numbers deleteCI = deleteCI(ciJob, null); S_LOGGER.debug("write back json data after job deletion successfull"); deleteJsonJobs(appInfo, Arrays.asList(ciJob)); } return deleteCI; } catch (ClientHandlerException ex) { S_LOGGER.error( "Entered into catch block of ProjectAdministratorImpl.deleteCI()" + ex.getLocalizedMessage()); throw new PhrescoException(ex); } }
private int getTotalBuilds(CIJob job) throws PhrescoException { try { S_LOGGER.debug("Entering Method CIManagerImpl.getTotalBuilds(CIJob job)"); S_LOGGER.debug("getCIBuilds() JobName = " + job.getName()); JsonArray jsonArray = getBuildsArray(job); Gson gson = new Gson(); CIBuild ciBuild = null; if (jsonArray.size() > 0) { ciBuild = gson.fromJson(jsonArray.get(0), CIBuild.class); String buildUrl = ciBuild.getUrl(); String jenkinsUrl = job.getJenkinsUrl() + ":" + job.getJenkinsPort(); // display the jenkins running url in ci buildUrl = buildUrl.replaceAll("localhost:" + job.getJenkinsPort(), jenkinsUrl); // list String response = getJsonResponse(buildUrl + API_JSON); JsonParser parser = new JsonParser(); JsonElement jsonElement = parser.parse(response); JsonObject jsonObject = jsonElement.getAsJsonObject(); JsonElement resultJson = jsonObject.get(FrameworkConstants.CI_JOB_BUILD_RESULT); JsonArray asJsonArray = jsonObject.getAsJsonArray(FrameworkConstants.CI_JOB_BUILD_ARTIFACTS); // when build result is not known if (jsonObject.get(FrameworkConstants.CI_JOB_BUILD_RESULT).toString().equals(STRING_NULL)) { // it indicates the job is in progress and not yet completed return -1; // when build is success and build zip relative path is unknown } else if (resultJson.getAsString().equals(CI_SUCCESS_FLAG) && asJsonArray.size() < 1) { return -1; } else { return jsonArray.size(); } } else { return -1; // When the project is build first time, } } catch (ClientHandlerException ex) { S_LOGGER.error(ex.getLocalizedMessage()); throw new PhrescoException(ex); } }
String getLocalIPAddr() { if (localAddr == null) { try { IPAddr localHost = IPAddr.getLocalHost(); localAddr = localHost.getHostAddress(); } catch (UnknownHostException e) { // shouldn't happen log.error("LockssServlet: getLocalHost: " + e.toString()); return "???"; } } return localAddr; }
public boolean isJobCreatingBuild(CIJob ciJob) throws PhrescoException { S_LOGGER.debug("Entering Method ProjectAdministratorImpl.isBuilding()"); try { int isBuilding = getProgressInBuild(ciJob); if (isBuilding > 0) { return true; } else { return false; } } catch (Exception ex) { return false; } }
public CIJobStatus deleteBuilds(ApplicationInfo appInfo, Map<String, List<String>> builds) throws PhrescoException { S_LOGGER.debug("Entering Method ProjectAdministratorImpl.deleteCI()"); try { CIJobStatus deleteCI = null; Iterator iterator = builds.keySet().iterator(); while (iterator.hasNext()) { String jobName = iterator.next().toString(); List<String> deleteBuilds = builds.get(jobName); S_LOGGER.debug("jobName " + jobName + " builds " + deleteBuilds); CIJob ciJob = getJob(appInfo, jobName); // job and build numbers deleteCI = deleteCI(ciJob, deleteBuilds); } return deleteCI; } catch (ClientHandlerException ex) { S_LOGGER.error( "Entered into catch block of ProjectAdministratorImpl.deleteCI()" + ex.getLocalizedMessage()); throw new PhrescoException(ex); } }
public MultiPartRequest getMultiPartRequest(int maxLen) throws FormDataTooLongException, IOException { if (req.getContentType() == null || !req.getContentType().startsWith("multipart/form-data")) { return null; } if (req.getContentLength() > maxLen) { throw new FormDataTooLongException(req.getContentLength() + " bytes, " + maxLen + " allowed"); } MultiPartRequest multi = new MultiPartRequest(req); if (log.isDebug2()) { String[] parts = multi.getPartNames(); log.debug3("Multipart request, " + parts.length + " parts"); if (log.isDebug3()) { for (int p = 0; p < parts.length; p++) { String name = parts[p]; String cont = multi.getString(parts[p]); log.debug3(name + ": " + cont); } } } multiReq = multi; return multi; }
public CIJob getJob(ApplicationInfo appInfo, String jobName) throws PhrescoException { try { S_LOGGER.debug("Search for jobName => " + jobName); if (StringUtils.isEmpty(jobName)) { return null; } List<CIJob> jobs = getJobs(appInfo); if (CollectionUtils.isEmpty(jobs)) { S_LOGGER.debug("job list is empty!!!!!!!!"); return null; } S_LOGGER.debug("Job list found!!!!!"); for (CIJob job : jobs) { S_LOGGER.debug("job list job Names => " + job.getName()); if (job.getName().equals(jobName)) { return job; } } } catch (Exception e) { throw new PhrescoException(e); } return null; }
public CIJobStatus buildJobs(ApplicationInfo appInfo, List<String> jobsName) throws PhrescoException { try { CIJobStatus jobStatus = null; for (String jobName : jobsName) { CIJob ciJob = getJob(appInfo, jobName); jobStatus = buildJob(ciJob); } return jobStatus; } catch (ClientHandlerException ex) { S_LOGGER.error(ex.getLocalizedMessage()); throw new PhrescoException(ex); } }
private boolean adaptExistingJobs(ApplicationInfo appInfo) { try { CIJob existJob = getJob(appInfo); S_LOGGER.debug("Going to get existing jobs to relocate!!!!!"); if (existJob != null) { S_LOGGER.debug("Existing job found " + existJob.getName()); boolean deleteExistJob = deleteCIJobFile(appInfo); Gson gson = new Gson(); List<CIJob> existingJobs = new ArrayList<CIJob>(); existingJobs.addAll(Arrays.asList(existJob)); FileWriter writer = null; File ciJobFile = new File(getCIJobPath(appInfo)); String jobJson = gson.toJson(existingJobs); writer = new FileWriter(ciJobFile); writer.write(jobJson); writer.flush(); S_LOGGER.debug("Existing job moved to new type of project!!"); } return true; } catch (Exception e) { S_LOGGER.debug("It is already adapted !!!!! "); } return false; }
private static synchronized String getJavascript() { if (jstext == null) { InputStream istr = null; try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); istr = loader.getResourceAsStream(JAVASCRIPT_RESOURCE); jstext = StringUtil.fromInputStream(istr); istr.close(); } catch (Exception e) { log.error("Can't load javascript", e); } finally { IOUtil.safeClose(istr); } } return jstext; }
public void addRioxxVersionSection(List upload, Item item) throws WingException { String version = item.getMetadata("rioxxterms.version"); if (StringUtils.isNotBlank(version) && !"NA".equals(version)) { try { DCInputsReader a = new DCInputsReader(); java.util.List<String> pairs = a.getPairs("rioxxterms_version"); int humanReadable = pairs.indexOf(version) - 1; version = pairs.get(humanReadable); } catch (DCInputsReaderException e) { log.error(e.getMessage(), e); } upload .addItem("upload-rioxx-version-warning", "upload-rioxx-version-warning") .addContent(T_rioxx_version.parameterize(version)); } }
// SingleThreadModel causes servlet instances to be assigned to only a // single thread (request) at a time. public abstract class LockssServlet extends HttpServlet implements SingleThreadModel { protected static Logger log = Logger.getLogger("LockssServlet"); // Constants static final String PARAM_LOCAL_IP = Configuration.PREFIX + "localIPAddress"; static final String PARAM_PLATFORM_VERSION = Configuration.PREFIX + "platform.version"; /** Inactive HTTP session (cookie) timeout */ static final String PARAM_UI_SESSION_TIMEOUT = Configuration.PREFIX + "ui.sessionTimeout"; static final long DEFAULT_UI_SESSION_TIMEOUT = 2 * Constants.DAY; /** Maximum size of uploaded file accepted */ static final String PARAM_MAX_UPLOAD_FILE_SIZE = Configuration.PREFIX + "ui.maxUploadFileSize"; static final int DEFAULT_MAX_UPLOAD_FILE_SIZE = 500000; /** The warning string to display when the UI is disabled. */ static final String PARAM_UI_WARNING = Configuration.PREFIX + "ui.warning"; // session keys static final String SESSION_KEY_OBJECT_ID = "obj_id"; static final String SESSION_KEY_OBJ_MAP = "obj_map"; public static final String SESSION_KEY_RUNNING_SERVLET = "running_servlet"; public static final String SESSION_KEY_REQUEST_HOST = "request_host"; // Name given to form element whose value is the action that should be // performed when the form is submitted. (Not always the submit button.) public static final String ACTION_TAG = "lockssAction"; public static final String JAVASCRIPT_RESOURCE = "org/lockss/htdocs/admin.js"; public static final String ATTR_INCLUDE_SCRIPT = "IncludeScript"; public static final String ATTR_ALLOW_ROLES = "AllowRoles"; /** User may configure admin access (add/delete/modify users, set admin access list) */ public static final String ROLE_USER_ADMIN = "userAdminRole"; /** User may configure content access (set content access list) */ public static final String ROLE_CONTENT_ADMIN = "contentAdminRole"; /** User may change AU configuration (add/delete content) */ public static final String ROLE_AU_ADMIN = "auAdminRole"; public static final String ROLE_DEBUG = "debugRole"; protected ServletContext context; private LockssApp theApp = null; private ServletManager servletMgr; private AccountManager acctMgr; // Request-local storage. Convenient, but requires servlet instances // to be single threaded, and must ensure reset them to avoid carrying // over state between requests. protected HttpServletRequest req; protected HttpServletResponse resp; protected URL reqURL; protected HttpSession session; private String adminDir = null; protected String clientAddr; // client addr, even if no param protected String localAddr; protected MultiPartRequest multiReq; private Vector footnotes; private int footNumber; private int tabindex; ServletDescr _myServletDescr = null; private String myName = null; // number submit buttons sequentially so unit tests can find them protected int submitButtonNumber = 0; /** Run once when servlet loaded. */ public void init(ServletConfig config) throws ServletException { super.init(config); context = config.getServletContext(); theApp = (LockssApp) context.getAttribute(ServletManager.CONTEXT_ATTR_LOCKSS_APP); servletMgr = (ServletManager) context.getAttribute(ServletManager.CONTEXT_ATTR_SERVLET_MGR); if (theApp instanceof LockssDaemon) { acctMgr = getLockssDaemon().getAccountManager(); } } public ServletManager getServletManager() { return servletMgr; } protected ServletDescr[] getServletDescrs() { return servletMgr.getServletDescrs(); } /** Servlets must implement this method. */ protected abstract void lockssHandleRequest() throws ServletException, IOException; /** Common request handling. */ public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resetState(); boolean success = false; HttpSession session = req.getSession(false); try { this.req = req; this.resp = resp; if (log.isDebug()) { logParams(); } resp.setContentType("text/html"); if (!mayPageBeCached()) { resp.setHeader("pragma", "no-cache"); resp.setHeader("Cache-control", "no-cache"); } reqURL = new URL(UrlUtil.getRequestURL(req)); clientAddr = getLocalIPAddr(); // check that current user has permission to run this servlet if (!isServletAllowed(myServletDescr())) { displayWarningInLieuOfPage("You are not authorized to use " + myServletDescr().heading); return; } // check whether servlet is disabled String reason = ServletUtil.servletDisabledReason(myServletDescr().getServletName()); if (reason != null) { displayWarningInLieuOfPage("This function is disabled. " + reason); return; } if (session != null) { session.setAttribute(SESSION_KEY_RUNNING_SERVLET, getHeading()); String reqHost = req.getRemoteHost(); String forw = req.getHeader(HttpFields.__XForwardedFor); if (!StringUtil.isNullString(forw)) { reqHost += " (proxies for " + forw + ")"; } session.setAttribute(SESSION_KEY_REQUEST_HOST, reqHost); } lockssHandleRequest(); success = (errMsg == null); } catch (ServletException e) { log.error("Servlet threw", e); throw e; } catch (IOException e) { log.error("Servlet threw", e); throw e; } catch (RuntimeException e) { log.error("Servlet threw", e); throw e; } finally { if (session != null) { session.setAttribute(SESSION_KEY_RUNNING_SERVLET, null); session.setAttribute(LockssFormAuthenticator.__J_AUTH_ACTIVITY, TimeBase.nowMs()); } if ("please".equalsIgnoreCase(req.getHeader("X-Lockss-Result"))) { log.debug3("X-Lockss-Result: " + (success ? "Ok" : "Fail")); resp.setHeader("X-Lockss-Result", success ? "Ok" : "Fail"); } resetMyLocals(); resetLocals(); } } protected void resetState() { multiReq = null; footNumber = 0; submitButtonNumber = 0; tabindex = 1; statusMsg = null; errMsg = null; isFramed = false; } protected void resetLocals() {} protected void resetMyLocals() { // Don't hold on to stuff forever req = null; resp = null; session = null; reqURL = null; adminDir = null; localAddr = null; footnotes = null; _myServletDescr = null; myName = null; multiReq = null; } /** * Return true if generated page may be cached (e.g., by browser). Default is false as most * servlets generate dynamic results */ protected boolean mayPageBeCached() { return false; } /** Set the session timeout to the configured value */ protected void setSessionTimeout(HttpSession session) { Configuration config = CurrentConfig.getCurrentConfig(); setSessionTimeout( session, config.getTimeInterval(PARAM_UI_SESSION_TIMEOUT, DEFAULT_UI_SESSION_TIMEOUT)); } /** Set the session timeout */ protected void setSessionTimeout(HttpSession session, long time) { session.setMaxInactiveInterval((int) (time / Constants.SECOND)); } /** Get the current session, creating it if necessary (and set the timeout if so) */ protected HttpSession getSession() { if (session == null) { session = req.getSession(true); if (session.isNew()) { setSessionTimeout(session); } } return session; } /** Return true iff a session has already been established */ protected boolean hasSession() { return req.getSession(false) != null; } /** Get an unused ID string for storing an object in the session */ protected String getNewSessionObjectId() { HttpSession session = getSession(); synchronized (session) { Integer id = (Integer) getSession().getAttribute(SESSION_KEY_OBJECT_ID); if (id == null) { id = new Integer(1); } session.setAttribute(SESSION_KEY_OBJECT_ID, new Integer(id.intValue() + 1)); return id.toString(); } } /** Get the object associated with the ID in the session */ protected Object getSessionIdObject(String id) { HttpSession session = getSession(); synchronized (session) { BidiMap map = (BidiMap) session.getAttribute(SESSION_KEY_OBJ_MAP); if (map == null) { return null; } return map.getKey(id); } } /** Get the String associated with the ID in the session */ protected String getSessionIdString(String id) { return (String) getSessionIdObject(id); } /** Get the ID with which the object is associated with the session, if any */ protected String getSessionObjectId(Object obj) { HttpSession session = getSession(); BidiMap map; synchronized (session) { map = (BidiMap) session.getAttribute(SESSION_KEY_OBJ_MAP); if (map == null) { map = new DualHashBidiMap(); session.setAttribute(SESSION_KEY_OBJ_MAP, map); } } synchronized (map) { String id = (String) map.get(obj); if (id == null) { id = getNewSessionObjectId(); map.put(obj, id); } return id; } } // Return descriptor of running servlet protected ServletDescr myServletDescr() { if (_myServletDescr == null) { _myServletDescr = servletMgr.findServletDescr(this); } return _myServletDescr; } // By default, servlet heading is in descr. Override method to // compute other heading protected String getHeading(ServletDescr d) { if (d == null) return "Unknown Servlet"; return d.heading; } protected String getHeading() { return getHeading(myServletDescr()); } String getLocalIPAddr() { if (localAddr == null) { try { IPAddr localHost = IPAddr.getLocalHost(); localAddr = localHost.getHostAddress(); } catch (UnknownHostException e) { // shouldn't happen log.error("LockssServlet: getLocalHost: " + e.toString()); return "???"; } } return localAddr; } // Return IP addr used by LCAP. If specified by (misleadingly named) // localIPAddress prop, might not really be our address (if we are // behind NAT). String getLcapIPAddr() { String ip = CurrentConfig.getParam(PARAM_LOCAL_IP); if (ip == null || ip.length() <= 0) { return getLocalIPAddr(); } return ip; } String getRequestHost() { return reqURL.getHost(); } String getMachineName() { return PlatformUtil.getLocalHostname(); } // String getMachineName0() { // if (myName == null) { // // Return the canonical name of the interface the request was aimed // // at. (localIPAddress prop isn't necessarily right here, as it // // might be the address of a NAT that we're behind.) // String host = reqURL.getHost(); // try { // IPAddr localHost = IPAddr.getByName(host); // String ip = localHost.getHostAddress(); // myName = getMachineName(ip); // } catch (UnknownHostException e) { // // shouldn't happen // log.error("getMachineName", e); // return host; // } // } // return myName; // } // String getMachineName(String ip) { // try { // IPAddr inet = IPAddr.getByName(ip); // return inet.getHostName(); // } catch (UnknownHostException e) { // log.warning("getMachineName", e); // } // return ip; // } // return IP given name or IP String getMachineIP(String name) { try { IPAddr inet = IPAddr.getByName(name); return inet.getHostAddress(); } catch (UnknownHostException e) { return null; } } boolean isServletLinkInNav(ServletDescr d) { return !isThisServlet(d) || linkMeInNav(); } boolean isThisServlet(ServletDescr d) { return d == myServletDescr(); } /** servlets may override this to determine whether they should be a link in nav table */ protected boolean linkMeInNav() { return false; } boolean isLargeLogo() { return myServletDescr().isLargeLogo(); } // user predicates String getUsername() { Principal user = req.getUserPrincipal(); return user != null ? user.toString() : null; } protected UserAccount getUserAccount() { if (acctMgr != null) { return acctMgr.getUser(getUsername()); } return AccountManager.NOBODY_ACCOUNT; } protected boolean isDebugUser() { return doesUserHaveRole(ROLE_DEBUG); } protected boolean doesUserHaveRole(String role) { if ((req.isUserInRole(role) || req.isUserInRole(ROLE_USER_ADMIN)) && !hasNoRoleParsm(role)) { return true; } return hasTestRole(role); } static Map<String, String> noRoleParams = new HashMap<String, String>(); static { noRoleParams.put(ROLE_USER_ADMIN, "noadmin"); noRoleParams.put(ROLE_CONTENT_ADMIN, "nocontent"); noRoleParams.put(ROLE_AU_ADMIN, "noau"); noRoleParams.put(ROLE_DEBUG, "nodebug"); } protected boolean hasNoRoleParsm(String roleName) { String noRoleParam = noRoleParams.get(roleName); return (noRoleParam != null && !StringUtil.isNullString(req.getParameter(noRoleParam))); } protected boolean hasTestRole(String role) { // Servlet test harness puts roles in context List roles = (List) context.getAttribute(ATTR_ALLOW_ROLES); return roles != null && (roles.contains(role) || roles.contains(ROLE_USER_ADMIN)); } protected boolean isServletAllowed(ServletDescr d) { if (d.needsUserAdminRole() && !doesUserHaveRole(ROLE_USER_ADMIN)) return false; if (d.needsContentAdminRole() && !doesUserHaveRole(ROLE_CONTENT_ADMIN)) return false; if (d.needsAuAdminRole() && !doesUserHaveRole(ROLE_AU_ADMIN)) return false; return d.isEnabled(getLockssDaemon()); } protected boolean isServletDisplayed(ServletDescr d) { if (!isServletAllowed(d)) return false; if (d.needsDebugRole() && !doesUserHaveRole(ROLE_DEBUG)) return false; return true; } protected boolean isServletInNav(ServletDescr d) { if (d.cls == ServletDescr.UNAVAILABLE_SERVLET_MARKER) return false; return d.isInNav(this) && isServletDisplayed(d); } // Called when a servlet doesn't get the parameters it expects/needs protected void paramError() throws IOException { // FIXME: As of 2006-03-15 this method and its only caller checkParam() are not called from // anywhere PrintWriter wrtr = resp.getWriter(); Page page = new Page(); // add referer, params, msg to contact lockss unless from old bookmark // or manually entered url page.add("Parameter error"); page.write(wrtr); } // return true iff error protected boolean checkParam(boolean ok, String msg) throws IOException { if (ok) return false; log.error(myServletDescr().getPath() + ": " + msg); paramError(); return true; } /** Construct servlet URL */ String srvURL(ServletDescr d) { return srvURL((String) null, d, null); } /** Construct servlet URL with params */ String srvURL(ServletDescr d, String params) { return srvURL((String) null, d, params); } /** Construct servlet URL with params */ String srvURL(ServletDescr d, Properties params) { return srvURL(d, concatParams(params)); } /** Construct servlet absolute URL, with params as necessary. */ String srvAbsURL(ServletDescr d, String params) { return srvURL(getRequestHost(), d, params); } /** * Construct servlet URL, with params as necessary. Avoid generating a hostname different from * that used in the original request, or browsers will prompt again for login */ String srvURL(String host, ServletDescr d, String params) { return srvURLFromStem(srvUrlStem(host), d, params); } String srvURL(PeerIdentity peer, ServletDescr d, String params) { return srvURLFromStem(peer.getUiUrlStem(reqURL.getPort()), d, params); } /** * Construct servlet URL, with params as necessary. Avoid generating a hostname different from * that used in the original request, or browsers will prompt again for login */ String srvURLFromStem(String stem, ServletDescr d, String params) { if (d.isPathIsUrl()) { return d.getPath(); } StringBuilder sb = new StringBuilder(80); if (stem != null) { sb.append(stem); if (stem.charAt(stem.length() - 1) != '/') { sb.append('/'); } } else { // ensure absolute path even if no scheme/host/port sb.append('/'); } sb.append(d.getPath()); if (params != null) { sb.append('?'); sb.append(params); } return sb.toString(); } String srvUrlStem(String host) { if (host == null) { return null; } StringBuilder sb = new StringBuilder(); sb.append(reqURL.getProtocol()); sb.append("://"); sb.append(host); sb.append(':'); sb.append(reqURL.getPort()); return sb.toString(); } /** Return a link to a servlet */ String srvLink(ServletDescr d, String text) { return srvLink(d, text, (String) null); } /** Return a link to a servlet with params */ String srvLink(ServletDescr d, String text, String params) { return new Link(srvURL(d, params), (text != null ? text : d.heading)).toString(); } /** Return a link to a servlet with params */ String srvLink(ServletDescr d, String text, Properties params) { return new Link(srvURL(d, params), text).toString(); } /** Return an absolute link to a servlet with params */ String srvAbsLink(ServletDescr d, String text, Properties params) { return srvAbsLink(d, text, concatParams(params)); } /** Return an absolute link to a servlet with params */ String srvAbsLink(ServletDescr d, String text, String params) { return new Link(srvAbsURL(d, params), (text != null ? text : d.heading)).toString(); } /** Return an absolute link to a servlet with params */ String srvAbsLink(String host, ServletDescr d, String text, String params) { return new Link(srvURL(host, d, params), (text != null ? text : d.heading)).toString(); } /** Return an absolute link to a servlet with params */ String srvAbsLink(PeerIdentity peer, ServletDescr d, String text, String params) { return new Link(srvURL(peer, d, params), (text != null ? text : d.heading)).toString(); } /** Return text as a link iff isLink */ String conditionalSrvLink(ServletDescr d, String text, String params, boolean isLink) { if (isLink) { return srvLink(d, text, params); } else { return text; } } /** Return text as a link iff isLink */ String conditionalSrvLink(ServletDescr d, String text, boolean isLink) { return conditionalSrvLink(d, text, null, isLink); } /** Concatenate params for URL string */ static String concatParams(String p1, String p2) { if (StringUtil.isNullString(p1)) { return p2; } if (StringUtil.isNullString(p2)) { return p1; } return p1 + "&" + p2; } /** Concatenate params for URL string */ String concatParams(Properties props) { if (props == null) { return null; } java.util.List list = new ArrayList(); for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) { String key = (String) iter.next(); String val = props.getProperty(key); if (!StringUtil.isNullString(val)) { list.add(key + "=" + urlEncode(val)); } } return StringUtil.separatedString(list, "&"); } String modifyParams(String key, String val) { Properties props = getParamsAsProps(); props.setProperty(key, val); return concatParams(props); } /** * Return the request parameters as a Properties. Only the first value of multivalued parameters * is included. */ Properties getParamsAsProps() { Properties props = new Properties(); for (Enumeration en = req.getParameterNames(); en.hasMoreElements(); ) { String name = (String) en.nextElement(); props.setProperty(name, req.getParameter(name)); } return props; } /** * Return the request parameters as a Map<String,String>. Only the first value of multivalued * parameters is included. */ Map<String, String> getParamsAsMap() { Map<String, String> map = new HashMap<String, String>(); for (Enumeration en = req.getParameterNames(); en.hasMoreElements(); ) { String name = (String) en.nextElement(); map.put(name, req.getParameter(name)); } return map; } protected String urlEncode(String param) { return UrlUtil.encodeUrl(param); } protected String getRequestKey() { String key = req.getPathInfo(); if (key != null && key.startsWith("/")) { return key.substring(1); } return key; } /** Common page setup. */ protected Page newPage() { // Compute heading String heading = getHeading(); if (heading == null) { heading = "Box Administration"; } // Create page and layout header Page page = ServletUtil.doNewPage(getPageTitle(), isFramed()); Iterator inNavIterator; if (myServletDescr().hasNoNavTable()) { inNavIterator = CollectionUtil.EMPTY_ITERATOR; } else { inNavIterator = new FilterIterator( new ObjectArrayIterator(getServletDescrs()), new Predicate() { public boolean evaluate(Object obj) { return isServletInNav((ServletDescr) obj); } }); } ServletUtil.layoutHeader( this, page, heading, isLargeLogo(), getMachineName(), getLockssApp().getStartDate(), inNavIterator); String warnMsg = CurrentConfig.getParam(PARAM_UI_WARNING); if (warnMsg != null) { Composite warning = new Composite(); warning.add("<center><font color=red size=+1>"); warning.add(warnMsg); warning.add("</font></center><br>"); page.add(warning); } return page; } protected Page addBarePageHeading(Page page) { // FIXME: Move the following fragment elsewhere // It causes the doctype statement to appear in the middle, // after the <body> tag. page.add("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"); page.addHeader("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">"); page.addHeader("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); page.addHeader("<link rel=\"shortcut icon\" href=\"/favicon.ico\" type=\"image/x-icon\" />"); return page; } private boolean isFramed = false; protected String errMsg; protected String statusMsg; protected boolean isFramed() { return isFramed; } protected void setFramed(boolean v) { isFramed = v; } protected String getPageTitle() { String heading = getHeading(); if (heading != null) { return "LOCKSS: " + heading; } else { return "LOCKSS"; } } /** Return a button that invokes the javascript submit routine with the specified action */ protected Element submitButton(String label, String action) { return submitButton(label, action, null, null); } /** Return a button that invokes javascript when clicked. */ Input jsButton(String label, String js) { Input btn = new Input("button", null); btn.attribute("value", label); setTabOrder(btn); btn.attribute("onClick", js); return btn; } /** * Return a button that invokes the javascript submit routine with the specified action, first * storing the value in the specified form prop. */ protected Element submitButton(String label, String action, String prop, String value) { StringBuilder sb = new StringBuilder(40); sb.append("lockssButton(this, '"); sb.append(action); sb.append("'"); if (prop != null && value != null) { sb.append(", '"); sb.append(prop); sb.append("', '"); sb.append(value); sb.append("'"); } sb.append(")"); Input btn = jsButton(label, sb.toString()); btn.attribute("id", "lsb." + (++submitButtonNumber)); return btn; } /** * Return a (possibly labelled) checkbox. * * @param label appears to right of checkbox if non null * @param value value included in result set if box checked * @param key form key to which result set is assigned * @param checked if true, box is initially checked * @return a checkbox Element */ Element checkBox(String label, String value, String key, boolean checked) { Input in = new Input(Input.Checkbox, key, value); if (checked) { in.check(); } setTabOrder(in); if (StringUtil.isNullString(label)) { return in; } else { Composite c = new Composite(); c.add(in); c.add(" "); c.add(label); return c; } } /** * Return a labelled rasio button * * @param label label to right of circle, and form value if checked * @param key form key to which value is assigned * @param checked if true, is initially checked * @return a readio button Element */ protected Element radioButton(String label, String key, boolean checked) { return radioButton(label, label, key, checked); } /** * Return a labelled rasio button * * @param label appears to right of circle if non null * @param value value assigned to key if box checked * @param key form key to which value is assigned * @param checked if true, is initially checked * @return a readio button Element */ protected Element radioButton(String label, String value, String key, boolean checked) { Composite c = new Composite(); Input in = new Input(Input.Radio, key, value); if (checked) { in.check(); } setTabOrder(in); c.add(in); c.add(label); return c; } /** Add html tags to grey the text if isGrey is true */ protected String greyText(String txt, boolean isGrey) { if (!isGrey) { return txt; } return "<font color=gray>" + txt + "</font>"; } /** * Set this element next in the tab order. Returns the element for easier nesting in expressions. */ protected Element setTabOrder(Element ele) { ele.attribute("tabindex", tabindex++); return ele; } /** * Store a footnote, assign it a number, return html for footnote reference. If footnote in null * or empty, no footnote is added and an empty string is returned. Footnote numbers get turned * into links; <b>Do not put the result of addFootnote inside a link!</b>. */ protected String addFootnote(String s) { if (s == null || s.length() == 0) { return ""; } if (footNumber == 0) { if (footnotes == null) { footnotes = new Vector(10, 10); } else { footnotes.removeAllElements(); } } int n = footnotes.indexOf(s); if (n < 0) { n = footNumber++; footnotes.addElement(s); } return "<sup><font size=-1><a href=#foottag" + (n + 1) + ">" + (n + 1) + "</a></font></sup>"; } /** * Add javascript to page. Normally adds a link to the script file, but can be told to include the * script directly in the page, to accomodate unit testing of individual servlets, when other * fetches won't work. */ protected void addJavaScript(Composite comp) { String include = (String) context.getAttribute(ATTR_INCLUDE_SCRIPT); if (StringUtil.isNullString(include)) { linkToJavaScript(comp); } else { includeJavaScript0(comp); } } private void includeJavaScript0(Composite comp) { Script script = new Script(getJavascript()); comp.add(script); } private void linkToJavaScript(Composite comp) { Script script = new Script(""); script.attribute("src", "admin.js"); comp.add(script); } private static String jstext = null; private static synchronized String getJavascript() { if (jstext == null) { InputStream istr = null; try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); istr = loader.getResourceAsStream(JAVASCRIPT_RESOURCE); jstext = StringUtil.fromInputStream(istr); istr.close(); } catch (Exception e) { log.error("Can't load javascript", e); } finally { IOUtil.safeClose(istr); } } return jstext; } /** Display a message in lieu of the normal page */ protected void displayMsgInLieuOfPage(String msg) throws IOException { // TODO: Look at HTML Page page = newPage(); Composite warning = new Composite(); warning.add(msg); warning.add("<br>"); page.add(warning); layoutFooter(page); page.write(resp.getWriter()); } /** Display a warning in red, in lieu of the normal page */ protected void displayWarningInLieuOfPage(String msg) throws IOException { displayMsgInLieuOfPage("<center><font color=red size=+1>" + msg + "</font></center>"); } /** Display "The cache isn't ready yet, come back later" */ protected void displayNotStarted() throws IOException { displayWarningInLieuOfPage( "This LOCKSS box is still starting. Please " + srvLink(myServletDescr(), "try again", getParamsAsProps()) + " in a moment."); } public MultiPartRequest getMultiPartRequest() throws FormDataTooLongException, IOException { int maxUpload = CurrentConfig.getIntParam(PARAM_MAX_UPLOAD_FILE_SIZE, DEFAULT_MAX_UPLOAD_FILE_SIZE); return getMultiPartRequest(maxUpload); } public MultiPartRequest getMultiPartRequest(int maxLen) throws FormDataTooLongException, IOException { if (req.getContentType() == null || !req.getContentType().startsWith("multipart/form-data")) { return null; } if (req.getContentLength() > maxLen) { throw new FormDataTooLongException(req.getContentLength() + " bytes, " + maxLen + " allowed"); } MultiPartRequest multi = new MultiPartRequest(req); if (log.isDebug2()) { String[] parts = multi.getPartNames(); log.debug3("Multipart request, " + parts.length + " parts"); if (log.isDebug3()) { for (int p = 0; p < parts.length; p++) { String name = parts[p]; String cont = multi.getString(parts[p]); log.debug3(name + ": " + cont); } } } multiReq = multi; return multi; } public String getParameter(String name) { String val = req.getParameter(name); if (val == null && multiReq != null) { val = multiReq.getString(name); } if (val == null) { return null; } val = StringUtils.strip(val, " \t"); // if (StringUtil.isNullString(val)) { if ("".equals(val)) { return null; } return val; } protected void layoutFooter(Page page) { ServletUtil.doLayoutFooter( page, (footnotes == null ? null : footnotes.iterator()), getLockssApp().getVersionInfo()); if (footnotes != null) { footnotes.removeAllElements(); } } /** Return the app instance. */ protected LockssApp getLockssApp() { return theApp; } /** * Return the daemon instance, assumes that the servlet is running in the daemon. * * @throws ClassCastException if the servlet is running in an app other than the daemon */ protected LockssDaemon getLockssDaemon() { return (LockssDaemon) theApp; } protected void logParams() { Enumeration en = req.getParameterNames(); while (en.hasMoreElements()) { String name = (String) en.nextElement(); String vals[]; String dispval; if (StringUtil.indexOfIgnoreCase(name, "passw") >= 0) { dispval = req.getParameter(name).length() == 0 ? "" : "********"; } else if (log.isDebug2() && (vals = req.getParameterValues(name)).length > 1) { dispval = StringUtil.separatedString(vals, ", "); } else { dispval = req.getParameter(name); } log.debug(name + " = " + dispval); } } /** Convenience method */ protected String encodeText(String s) { return HtmlUtil.encode(s, HtmlUtil.ENCODE_TEXT); } /** Convenience method */ protected String encodeTextArea(String s) { return HtmlUtil.encode(s, HtmlUtil.ENCODE_TEXTAREA); } /** Convenience method */ protected String encodeAttr(String s) { return HtmlUtil.encode(s, HtmlUtil.ENCODE_ATTR); } /** * Create message and error message block * * @param composite TODO */ protected void layoutErrorBlock(Composite composite) { if (errMsg != null || statusMsg != null) { ServletUtil.layoutErrorBlock(composite, errMsg, statusMsg); } } /** Exception thrown if multipart form data is longer than the caller-supplied max */ public static class FormDataTooLongException extends Exception { public FormDataTooLongException(String message) { super(message); } } }
// return true iff error protected boolean checkParam(boolean ok, String msg) throws IOException { if (ok) return false; log.error(myServletDescr().getPath() + ": " + msg); paramError(); return true; }
/** Common request handling. */ public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resetState(); boolean success = false; HttpSession session = req.getSession(false); try { this.req = req; this.resp = resp; if (log.isDebug()) { logParams(); } resp.setContentType("text/html"); if (!mayPageBeCached()) { resp.setHeader("pragma", "no-cache"); resp.setHeader("Cache-control", "no-cache"); } reqURL = new URL(UrlUtil.getRequestURL(req)); clientAddr = getLocalIPAddr(); // check that current user has permission to run this servlet if (!isServletAllowed(myServletDescr())) { displayWarningInLieuOfPage("You are not authorized to use " + myServletDescr().heading); return; } // check whether servlet is disabled String reason = ServletUtil.servletDisabledReason(myServletDescr().getServletName()); if (reason != null) { displayWarningInLieuOfPage("This function is disabled. " + reason); return; } if (session != null) { session.setAttribute(SESSION_KEY_RUNNING_SERVLET, getHeading()); String reqHost = req.getRemoteHost(); String forw = req.getHeader(HttpFields.__XForwardedFor); if (!StringUtil.isNullString(forw)) { reqHost += " (proxies for " + forw + ")"; } session.setAttribute(SESSION_KEY_REQUEST_HOST, reqHost); } lockssHandleRequest(); success = (errMsg == null); } catch (ServletException e) { log.error("Servlet threw", e); throw e; } catch (IOException e) { log.error("Servlet threw", e); throw e; } catch (RuntimeException e) { log.error("Servlet threw", e); throw e; } finally { if (session != null) { session.setAttribute(SESSION_KEY_RUNNING_SERVLET, null); session.setAttribute(LockssFormAuthenticator.__J_AUTH_ACTIVITY, TimeBase.nowMs()); } if ("please".equalsIgnoreCase(req.getHeader("X-Lockss-Result"))) { log.debug3("X-Lockss-Result: " + (success ? "Ok" : "Fail")); resp.setHeader("X-Lockss-Result", success ? "Ok" : "Fail"); } resetMyLocals(); resetLocals(); } }
/** * This is a step of the item submission processes. The upload stages allow the user to upload files * into the submission. The form is optimized for one file, but allows the user to upload more if * needed. * * <p>The form is broken up into three sections: * * <p>Part A: Ask the user to upload a file Part B: List previously uploaded files Part C: The * standard action bar * * @author Scott Phillips * @author Tim Donohue (updated for Configurable Submission) */ public class UploadStep extends AbstractSubmissionStep { private static Logger log = Logger.getLogger(UploadStep.class); /** Language Strings for Uploading * */ protected static final Message T_head = message("xmlui.Submission.submit.UploadStep.head"); protected static final Message T_file = message("xmlui.Submission.submit.UploadStep.file"); protected static final Message T_file_help = message("xmlui.Submission.submit.UploadStep.file_help"); protected static final Message T_file_error = message("xmlui.Submission.submit.UploadStep.file_error"); protected static final Message T_upload_error = message("xmlui.Submission.submit.UploadStep.upload_error"); protected static final Message T_virus_checker_error = message("xmlui.Submission.submit.UploadStep.virus_checker_error"); protected static final Message T_virus_error = message("xmlui.Submission.submit.UploadStep.virus_error"); protected static final Message T_description = message("xmlui.Submission.submit.UploadStep.description"); protected static final Message T_description_help = message("xmlui.Submission.submit.UploadStep.description_help"); protected static final Message T_submit_upload = message("xmlui.Submission.submit.UploadStep.submit_upload"); protected static final Message T_head2 = message("xmlui.Submission.submit.UploadStep.head2"); protected static final Message T_column0 = message("xmlui.Submission.submit.UploadStep.column0"); protected static final Message T_column1 = message("xmlui.Submission.submit.UploadStep.column1"); protected static final Message T_column2 = message("xmlui.Submission.submit.UploadStep.column2"); protected static final Message T_column3 = message("xmlui.Submission.submit.UploadStep.column3"); protected static final Message T_column4 = message("xmlui.Submission.submit.UploadStep.column4"); protected static final Message T_column5 = message("xmlui.Submission.submit.UploadStep.column5"); protected static final Message T_column6 = message("xmlui.Submission.submit.UploadStep.column6"); protected static final Message T_unknown_name = message("xmlui.Submission.submit.UploadStep.unknown_name"); protected static final Message T_unknown_format = message("xmlui.Submission.submit.UploadStep.unknown_format"); protected static final Message T_supported = message("xmlui.Submission.submit.UploadStep.supported"); protected static final Message T_known = message("xmlui.Submission.submit.UploadStep.known"); protected static final Message T_unsupported = message("xmlui.Submission.submit.UploadStep.unsupported"); protected static final Message T_submit_edit = message("xmlui.Submission.submit.UploadStep.submit_edit"); protected static final Message T_checksum = message("xmlui.Submission.submit.UploadStep.checksum"); protected static final Message T_submit_remove = message("xmlui.Submission.submit.UploadStep.submit_remove"); protected static final Message T_rioxx_version = message("xmlui.Submission.submit.UploadStep.rioxx_version"); protected static final Message T_sherpa_consult = message("xmlui.aspect.sherpa.submission.consult"); protected static final Message T_sherpa_title = message("xmlui.aspect.sherpa.submission.title"); protected static final Message T_sherpa_journal = message("xmlui.aspect.sherpa.submission.journal"); protected static final Message T_sherpa_publisher = message("xmlui.aspect.sherpa.submission.publisher"); protected static final Message T_sherpa_colour = message("xmlui.aspect.sherpa.submission.colour"); protected static final Message T_sherpa_more = message("xmlui.aspect.sherpa.submission.more"); /** Global reference to edit file page (this is used when a user requests to edit a bitstream) */ private EditFileStep editFile = null; /** Establish our required parameters, abstractStep will enforce these. */ public UploadStep() { this.requireSubmission = true; this.requireStep = true; } /** Check if user has requested to edit information about an uploaded file */ public void setup(SourceResolver resolver, Map objectModel, String src, Parameters parameters) throws ProcessingException, SAXException, IOException { super.setup(resolver, objectModel, src, parameters); // If this page for editing an uploaded file's information // was requested, then we need to load EditFileStep instead! if (this.errorFlag == org.dspace.submit.step.UploadStep.STATUS_EDIT_BITSTREAM) { this.editFile = new EditFileStep(); this.editFile.setup(resolver, objectModel, src, parameters); } else { this.editFile = null; } } public void addBody(Body body) throws SAXException, WingException, UIException, SQLException, IOException, AuthorizeException { // If we are actually editing information of an uploaded file, // then display that body instead! if (this.editFile != null) { editFile.addBody(body); return; } // Get a list of all files in the original bundle Item item = submission.getItem(); Collection collection = submission.getCollection(); String actionURL = contextPath + "/handle/" + collection.getHandle() + "/submit/" + knot.getId() + ".continue"; boolean disableFileEditing = (submissionInfo.isInWorkflow()) && !ConfigurationManager.getBooleanProperty("workflow", "reviewer.file-edit"); Bundle[] bundles = item.getBundles("ORIGINAL"); Bitstream[] bitstreams = new Bitstream[0]; if (bundles.length > 0) { bitstreams = bundles[0].getBitstreams(); } // Part A: // First ask the user if they would like to upload a new file (may be the first one) Division div = body.addInteractiveDivision( "submit-upload", actionURL, Division.METHOD_MULTIPART, "primary submission"); div.setHead(T_submission_head); addSubmissionProgressList(div); List upload = null; if (!disableFileEditing) { // Only add the upload capabilities for new item submissions upload = div.addList("submit-upload-new", List.TYPE_FORM); upload.setHead(T_head); addRioxxVersionSection(upload, item); File file = upload.addItem().addFile("file"); file.setLabel(T_file); file.setHelp(T_file_help); file.setRequired(); // if no files found error was thrown by processing class, display it! if (this.errorFlag == org.dspace.submit.step.UploadStep.STATUS_NO_FILES_ERROR) { file.addError(T_file_error); } // if an upload error was thrown by processing class, display it! if (this.errorFlag == org.dspace.submit.step.UploadStep.STATUS_UPLOAD_ERROR) { file.addError(T_upload_error); } // if virus checking was attempted and failed in error then let the user know if (this.errorFlag == org.dspace.submit.step.UploadStep.STATUS_VIRUS_CHECKER_UNAVAILABLE) { file.addError(T_virus_checker_error); } // if virus checking was attempted and a virus found then let the user know if (this.errorFlag == org.dspace.submit.step.UploadStep.STATUS_CONTAINS_VIRUS) { file.addError(T_virus_error); } Text description = upload.addItem().addText("description"); description.setLabel(T_description); description.setHelp(T_description_help); Button uploadSubmit = upload.addItem().addButton("submit_upload"); uploadSubmit.setValue(T_submit_upload); } make_sherpaRomeo_submission(item, div); // Part B: // If the user has already uploaded files provide a list for the user. if (bitstreams.length > 0 || disableFileEditing) { Table summary = div.addTable("submit-upload-summary", (bitstreams.length * 2) + 2, 7); summary.setHead(T_head2); Row header = summary.addRow(Row.ROLE_HEADER); header.addCellContent(T_column0); // primary bitstream header.addCellContent(T_column1); // select checkbox header.addCellContent(T_column2); // file name header.addCellContent(T_column3); // size header.addCellContent(T_column4); // description header.addCellContent(T_column5); // format header.addCellContent(T_column6); // edit button for (Bitstream bitstream : bitstreams) { int id = bitstream.getID(); String name = bitstream.getName(); String url = makeBitstreamLink(item, bitstream); long bytes = bitstream.getSize(); String desc = bitstream.getDescription(); String algorithm = bitstream.getChecksumAlgorithm(); String checksum = bitstream.getChecksum(); Row row = summary.addRow(); // Add radio-button to select this as the primary bitstream Radio primary = row.addCell().addRadio("primary_bitstream_id"); primary.addOption(String.valueOf(id)); // If this bitstream is already marked as the primary bitstream // mark it as such. if (bundles[0].getPrimaryBitstreamID() == id) { primary.setOptionSelected(String.valueOf(id)); } if (!disableFileEditing) { // Workflow users can not remove files. CheckBox remove = row.addCell().addCheckBox("remove"); remove.setLabel("remove"); remove.addOption(id); } else { row.addCell(); } row.addCell().addXref(url, name); row.addCellContent(bytes + " bytes"); if (desc == null || desc.length() == 0) { row.addCellContent(T_unknown_name); } else { row.addCellContent(desc); } BitstreamFormat format = bitstream.getFormat(); if (format == null) { row.addCellContent(T_unknown_format); } else { int support = format.getSupportLevel(); Cell cell = row.addCell(); cell.addContent(format.getMIMEType()); cell.addContent(" "); switch (support) { case 1: cell.addContent(T_supported); break; case 2: cell.addContent(T_known); break; case 3: cell.addContent(T_unsupported); break; } } Button edit = row.addCell().addButton("submit_edit_" + id); edit.setValue(T_submit_edit); Row checksumRow = summary.addRow(); checksumRow.addCell(); Cell checksumCell = checksumRow.addCell(null, null, 0, 6, null); checksumCell.addHighlight("bold").addContent(T_checksum); checksumCell.addContent(" "); checksumCell.addContent(algorithm + ":" + checksum); } if (!disableFileEditing) { // Workflow users can not remove files. Row actionRow = summary.addRow(); actionRow.addCell(); Button removeSeleceted = actionRow.addCell(null, null, 0, 6, null).addButton("submit_remove_selected"); removeSeleceted.setValue(T_submit_remove); } upload = div.addList("submit-upload-new-part2", List.TYPE_FORM); } // Part C: // add standard control/paging buttons addControlButtons(upload); } /** Sherpa romeo submission support */ public void make_sherpaRomeo_submission(Item item, Division divIn) throws WingException { if (ConfigurationManager.getBooleanProperty( "webui.submission.sherparomeo-policy-enabled", true)) { SHERPASubmitService sherpaSubmitService = new DSpace().getSingletonService(SHERPASubmitService.class); if (sherpaSubmitService.hasISSNs(context, item)) { List div = divIn.addList("submit-upload-new", List.TYPE_FORM); div.setHead(T_sherpa_title); // Since sherpa web service doesn't work reliable with more than 1 issn, perform the service // for each issn Set<String> issns = sherpaSubmitService.getISSNs(context, item); Iterator<String> issnsIterator = issns.iterator(); int i = 0; while (issnsIterator.hasNext()) { SHERPAResponse shresp = sherpaSubmitService.searchRelatedJournalsByISSN(issnsIterator.next()); java.util.List<SHERPAJournal> journals = shresp.getJournals(); java.util.List<SHERPAPublisher> publishers = shresp.getPublishers(); if (CollectionUtils.isNotEmpty(journals)) { for (SHERPAJournal journ : journals) { SHERPAPublisher pub = publishers.get(0); List sherpaList = div.addList("sherpaList" + (i + 1), "simple", "sherpaList"); sherpaList .addItem() .addFigure( contextPath + "/static/images/" + (i == 0 ? "romeosmall" : "clear") + ".gif", "http://www.sherpa.ac.uk/romeo/", "sherpaLogo"); sherpaList.addItem().addHighlight("sherpaBold").addContent(T_sherpa_journal); sherpaList.addItem(journ.getTitle() + " (" + journ.getIssn() + ")"); sherpaList.addItem().addHighlight("sherpaBold").addContent(T_sherpa_publisher); sherpaList.addItemXref(pub.getHomeurl(), pub.getName()); sherpaList.addItem().addHighlight("sherpaBold").addContent(T_sherpa_colour); sherpaList .addItem() .addHighlight("sherpaStyle " + pub.getRomeocolour()) .addContent(message("xmlui.aspect.sherpa.submission." + pub.getRomeocolour())); sherpaList .addItem() .addXref( "http://www.sherpa.ac.uk/romeo/search.php?issn=" + journ.getIssn(), T_sherpa_more, "sherpaMoreInfo"); i = i + 1; } } } List sherpaList = div.addList("sherpaListEnd", "simple", "sherpaList"); sherpaList.addItem(T_sherpa_consult); } } } /** * Each submission step must define its own information to be reviewed during the final * Review/Verify Step in the submission process. * * <p>The information to review should be tacked onto the passed in List object. * * <p>NOTE: To remain consistent across all Steps, you should first add a sub-List object (with * this step's name as the heading), by using a call to reviewList.addList(). This sublist is the * list you return from this method! * * @param reviewList The List to which all reviewable information should be added * @return The new sub-List object created by this step, which contains all the reviewable * information. If this step has nothing to review, then return null! */ public List addReviewSection(List reviewList) throws SAXException, WingException, UIException, SQLException, IOException, AuthorizeException { // Create a new list section for this step (and set its heading) List uploadSection = reviewList.addList("submit-review-" + this.stepAndPage, List.TYPE_FORM); uploadSection.setHead(T_head); // Review all uploaded files Item item = submission.getItem(); Bundle[] bundles = item.getBundles("ORIGINAL"); Bitstream[] bitstreams = new Bitstream[0]; if (bundles.length > 0) { bitstreams = bundles[0].getBitstreams(); } for (Bitstream bitstream : bitstreams) { BitstreamFormat bitstreamFormat = bitstream.getFormat(); String name = bitstream.getName(); String url = makeBitstreamLink(item, bitstream); String format = bitstreamFormat.getShortDescription(); Message support = ReviewStep.T_unknown; if (bitstreamFormat.getSupportLevel() == BitstreamFormat.KNOWN) { support = T_known; } else if (bitstreamFormat.getSupportLevel() == BitstreamFormat.SUPPORTED) { support = T_supported; } org.dspace.app.xmlui.wing.element.Item file = uploadSection.addItem(); file.addXref(url, name); file.addContent(" - " + format + " "); file.addContent(support); } // return this new "upload" section return uploadSection; } /** * Returns canonical link to a bitstream in the item. * * @param item The DSpace Item that the bitstream is part of * @param bitstream The bitstream to link to * @returns a String link to the bitstream */ private String makeBitstreamLink(Item item, Bitstream bitstream) { String name = bitstream.getName(); StringBuilder result = new StringBuilder(contextPath); result.append("/bitstream/item/").append(String.valueOf(item.getID())); // append name although it isn't strictly necessary try { if (name != null) { result.append("/").append(Util.encodeBitstreamName(name, "UTF-8")); } } catch (UnsupportedEncodingException uee) { // just ignore it, we don't have to have a pretty // name on the end of the url because the sequence id will // locate it. However it means that links in this file might // not work.... } result.append("?sequence=").append(String.valueOf(bitstream.getSequenceID())); return result.toString(); } public void addRioxxVersionSection(List upload, Item item) throws WingException { String version = item.getMetadata("rioxxterms.version"); if (StringUtils.isNotBlank(version) && !"NA".equals(version)) { try { DCInputsReader a = new DCInputsReader(); java.util.List<String> pairs = a.getPairs("rioxxterms_version"); int humanReadable = pairs.indexOf(version) - 1; version = pairs.get(humanReadable); } catch (DCInputsReaderException e) { log.error(e.getMessage(), e); } upload .addItem("upload-rioxx-version-warning", "upload-rioxx-version-warning") .addContent(T_rioxx_version.parameterize(version)); } } }