Example #1
0
  public void releaseObject(DragDropEvent ddEvent) {
    Map<String, String> params =
        FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
    String left = params.get("class");
    String[] sClass = left.split(" ");
    int col = 0;
    int ligne = 0;
    int item = 0;
    for (String s : sClass) {
      if (StringUtils.startsWith(s, "colonne_")) {
        String c = s.replace("colonne_", "");
        col = Integer.valueOf(c);
      }
      if (StringUtils.startsWith(s, "ligne_")) {
        String c = s.replace("ligne_", "");
        ligne = Integer.valueOf(c);
      }
      if (StringUtils.startsWith(s, "position_")) {
        String c = s.replace("position_", "");
        item = Integer.valueOf(c);
      }
    }
    if (col == 0 && ligne == 0) {
      pioche.remove(item);
    } else {
      Cell c = list.get(ligne).get(col);
      c.setType(Cell.CELL_EMPTY);
      c.setAngle(-1);
    }

    System.out.println("drop");
  }
Example #2
0
 public void putInPioche(DragDropEvent ddEvent) {
   Map<String, String> params =
       FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
   String left = params.get("class");
   String[] sClass = left.split(" ");
   String idTmp = "";
   int colTmp = -1;
   int ligneTmp = 0;
   for (String s : sClass) {
     if (StringUtils.startsWith(s, "colonne_")) {
       String c = s.replace("colonne_", "");
       colTmp = Integer.valueOf(c);
     }
     if (StringUtils.startsWith(s, "ligne_")) {
       String c = s.replace("ligne_", "");
       ligneTmp = Integer.valueOf(c);
     }
     if (StringUtils.startsWith(s, "id_")) {
       idTmp = s.replace("id_", "");
     }
   }
   if (colTmp != -1) {
     Cell c = list.get(ligneTmp).get(colTmp);
     c.setType(Cell.CELL_EMPTY);
     c.setAngle(-1);
   }
   if (idTmp.equals(Cell.CELL_MIRROR) || idTmp.equals(Cell.CELL_SPLIT)) {
     Cell c = new Cell(idTmp);
     c.setAngle(0);
     pioche.add(c);
   }
 }
  /**
   * Every overload of {@link Reader#read()} method delegates to this one so it is enough to
   * override only this one. <br>
   * To skip invalid characters this method shifts only valid chars to left and returns decreased
   * value of the original read method. So after last valid character there will be some unused
   * chars in the buffer.
   *
   * @return Number of read valid characters or <code>-1</code> if end of the underling reader was
   *     reached.
   */
  @Override
  public int read(char[] cbuf, int off, int len) throws IOException {
    int read = super.read(cbuf, off, len);
    // check for end
    if (read == -1) {
      return -1;
    }
    // target position
    int pos = off - 1;

    int entityStart = -1;
    for (int readPos = off; readPos < off + read; readPos++) {
      boolean useChar = true;
      switch (cbuf[readPos]) {
        case '&':
          pos++;
          entityStart = readPos;
          break;
        case ';':
          pos++;
          if (entityStart >= 0) {
            int entityLength = readPos - entityStart + 1;
            if (entityLength <= 5) {
              String entity = new String(cbuf, entityStart, entityLength);
              if (StringUtils.startsWith(entity, "&#")) {
                String numberString = StringUtils.substringBetween(entity, "&#", ";");
                final int value;
                if (StringUtils.startsWith(numberString, "x")) {
                  value = Integer.parseInt(numberString.substring(1), 16);
                } else {
                  value = Integer.parseInt(numberString);
                }
                if (!isValidXMLChar((char) value)) {
                  pos -= entityLength;
                  useChar = false;
                }
              }
            }
          }
          break;
        default:
          if (isValidXMLChar(cbuf[readPos])) {
            pos++;
          } else {
            continue;
          }
      }
      // copy, and skip unwanted characters
      if (pos < readPos && useChar) {
        cbuf[pos] = cbuf[readPos];
      }
    }
    return pos - off + 1;
  }
Example #4
0
  public void dropObject(DragDropEvent ddEvent) {
    Map<String, String> params =
        FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
    String ligne = getParam("ligne");
    String colonne = getParam("colonne");
    String left = params.get("class");
    String[] sClass = left.split(" ");
    int colTmp = -1;
    int ligneTmp = 0;
    int item = -1;
    String idTmp = "";
    for (String s : sClass) {
      if (StringUtils.startsWith(s, "colonne_")) {
        String c = s.replace("colonne_", "");
        colTmp = Integer.valueOf(c);
      }
      if (StringUtils.startsWith(s, "ligne_")) {
        String c = s.replace("ligne_", "");
        ligneTmp = Integer.valueOf(c);
      }
      if (StringUtils.startsWith(s, "id_")) {
        idTmp = s.replace("id_", "");
      }

      if (StringUtils.startsWith(s, "position_")) {
        String c = s.replace("position_", "");
        item = Integer.valueOf(c);
      }
    }
    int x = Integer.valueOf(ligne);
    int y = Integer.valueOf(colonne);
    String id;
    if (StringUtils.isEmpty(idTmp)) {
      id = params.get("dragId");
      id = id.replaceAll("FormContent:", "");
    } else {
      id = idTmp;
      if (item != -1) pioche.remove(item);
    }
    if (colTmp == -1) {
      Cell newCell = list.get(x).get(y);
      newCell.setType(id);
      newCell.setAngle(0);
    } else {
      Cell c = list.get(ligneTmp).get(colTmp);
      Cell newCell = list.get(x).get(y);
      newCell.setType(c.getType());
      newCell.setAngle(c.getAngle());
      c.setType(Cell.CELL_EMPTY);
      c.setAngle(-1);
    }
  }
Example #5
0
 /**
  * @param color
  * @return whether the color is testable, i.e defined as a rgb color
  */
 public static boolean isColorTestable(final String color) {
   return !StringUtils.contains(color, BACKGROUND_IMAGE_KEY)
       && !StringUtils.contains(color, GRADIENT_KEY)
       && !StringUtils.contains(color, ALPHA_COLOR_KEY)
       && !StringUtils.equalsIgnoreCase(color, TRANSPARENT_KEY)
       && StringUtils.startsWith(color, RGB_COLOR_KEY);
 }
Example #6
0
  /**
   * Converts the resource type to an absolute path. If it does not start with "/" the resource is
   * resolved via search paths using resource resolver. If not matching resource is found it is
   * returned unchanged.
   *
   * @param resourceType Resource type
   * @return Absolute resource type
   */
  public static String makeAbsolute(String resourceType, ResourceResolver resourceResolver) {
    if (StringUtils.isEmpty(resourceType) || StringUtils.startsWith(resourceType, "/")) {
      return resourceType;
    }

    // first try to resolve path via component manager - because on publish instance the original
    // resource may not accessible
    ComponentManager componentManager = resourceResolver.adaptTo(ComponentManager.class);
    if (componentManager != null) {
      Component component = componentManager.getComponent(resourceType);
      if (component != null) {
        return component.getPath();
      } else {
        return resourceType;
      }
    }

    // otherwise use resource resolver directly
    Resource resource = resourceResolver.getResource(resourceType);
    if (resource != null) {
      return resource.getPath();
    } else {
      return resourceType;
    }
  }
  @Override
  @SuppressWarnings("unchecked")
  public ActionForward refresh(
      ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception {

    ActionForward forward = super.refresh(mapping, form, request, response);

    String prefix =
        getSpecialReviewService().getProtocolSaveLocationPrefix(request.getParameterMap());
    InstitutionalProposalForm proposalForm = (InstitutionalProposalForm) form;

    InstitutionalProposalSpecialReview proposalSpecialReview = null;
    if (StringUtils.startsWith(prefix, "specialReviewHelper.newSpecialReview")) {
      proposalSpecialReview = proposalForm.getSpecialReviewHelper().getNewSpecialReview();
    } else {
      int index = getSpecialReviewService().getProtocolIndex(prefix);
      if (index != -1) {
        proposalSpecialReview =
            proposalForm
                .getInstitutionalProposalDocument()
                .getInstitutionalProposal()
                .getSpecialReviews()
                .get(index);
      }
    }

    proposalForm.getSpecialReviewHelper().prepareProtocolLinkViewFields(proposalSpecialReview);

    return forward;
  }
Example #8
0
 public static final String id(String id) {
   if (StringUtils.startsWith(id, prefix)) {
     return prefix.concat(Utils.noSpaces(Utils.stripAndTrim(id.replaceAll(prefix, ""), " "), "-"));
   } else if (id != null) {
     return prefix.concat(Utils.noSpaces(Utils.stripAndTrim(id, " "), "-"));
   } else {
     return null;
   }
 }
Example #9
0
 /**
  * Checks whether the given String is a parsable number.
  *
  * <p>Parsable numbers include those Strings understood by {@link Integer#parseInt(String)},
  * {@link Long#parseLong(String)}, {@link Float#parseFloat(String)} or {@link
  * Double#parseDouble(String)}. This method can be used instead of catching {@link
  * java.text.ParseException} when calling one of those methods.
  *
  * <p>Hexadecimal and scientific notations are <strong>not</strong> considered parsable. See
  * {@link #isNumber(String)} on those cases.
  *
  * <p>{@code Null} and empty String will return <code>false</code>.
  *
  * @param str the String to check.
  * @return {@code true} if the string is a parsable number.
  * @since 3.4
  */
 public static boolean isParsable(final String str) {
   if (StringUtils.endsWith(str, ".")) {
     return false;
   }
   if (StringUtils.startsWith(str, "-")) {
     return isDigits(StringUtils.replaceOnce(str.substring(1), ".", StringUtils.EMPTY));
   } else {
     return isDigits(StringUtils.replaceOnce(str, ".", StringUtils.EMPTY));
   }
 }
Example #10
0
 private StepCandidate findComposedCandidate(
     String composedStep, List<StepCandidate> allCandidates) {
   for (StepCandidate candidate : allCandidates) {
     if (StringUtils.startsWith(composedStep, candidate.getStartingWord())
         && (StringUtils.endsWith(composedStep, candidate.getPatternAsString())
             || candidate.matches(composedStep))) {
       return candidate;
     }
   }
   return null;
 }
  private void hashPassword(org.molgenis.omx.auth.MolgenisUser user) {
    // if password already encrypted, nothing changed -> return
    if (StringUtils.startsWith(user.getPassword(), "md5_")) return;

    try {
      PasswordHasher md5 = new PasswordHasher();
      String newPassword = md5.toMD5(user.getPassword());
      user.setPassword(newPassword);
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException(e);
    }
  }
Example #12
0
 @Override
 public void execute() throws Exception {
   Path destinationFile = task.getDestinationFile().toAbsolutePath();
   if (!Files.isReadable(destinationFile) || Files.size(destinationFile) == 0) {
     String contentType =
         HTTPClient.getInstance()
             .downloadToFile(
                 new WebResource(task.getUrl(), task.getReferer()), destinationFile, 0);
     if (task.isImage() && !StringUtils.startsWith(contentType, "image/")) {
       ErrorManager.getInstance().reportError(String.format("%s is not an image", task.getUrl()));
       Files.delete(destinationFile);
     }
   }
 }
  @Test
  public void testCampusCodeSearchResults() {
    service.setBusinessObjectClass(Unit.class);

    Map<String, String> fieldValues = new HashMap<String, String>();
    fieldValues.put(CAMPUS_CODE_FIELD, CAMPUS_CODE);
    List<? extends BusinessObject> searchResults = service.getSearchResults(fieldValues);
    assertEquals(SEARCH_RESULTS_CAMPUS_CODE_COUNT, searchResults.size());

    for (BusinessObject searchResult : searchResults) {
      Unit unit = (Unit) searchResult;
      assertTrue(StringUtils.startsWith(unit.getUnitNumber(), CAMPUS_CODE));
    }
  }
  public List<FormattedText> get(String source) {
    List<String> splitedStringList = split(source);
    if (splitedStringList == null) {
      return null;
    }

    List<FormattedText> formattedTextList = new ArrayList<FormattedText>();
    for (String splitedString : splitedStringList) {
      if (StringUtils.startsWithAny(splitedString, OUT_LINK_START_WITHS)) {
        formattedTextList.add(getFormattedText(splitedString, ' ', FormattedText.Type.OUT_LINK));
      } else if (StringUtils.startsWith(splitedString, INNER_LINK_ARTICLE_START_WITH)) {
        formattedTextList.add(
            getFormattedText(splitedString, '|', FormattedText.Type.IN_LINK_ARTICLE));
      } else if (StringUtils.startsWith(splitedString, INNER_LINK_PERSON_START_WITH)) {
        formattedTextList.add(
            getFormattedText(splitedString, '|', FormattedText.Type.IN_LINK_PERSON));
      } else {
        formattedTextList.add(getPlainText(splitedString));
      }
    }

    return formattedTextList;
  }
  @Override
  /**
   * copied from org.supercsv.io.AbstractCsvWriter
   *
   * @see org.supercsv.io.AbstractCsvWriter
   */
  protected String escapeString(String csvElement) {
    String escaped = super.escapeString(csvElement);

    if (!StringUtils.startsWith(escaped, String.valueOf((char) preference.getQuoteChar()))) {
      return (char) preference.getQuoteChar() + escaped + (char) preference.getQuoteChar();
    }

    return escaped;
  }
  private List<TaobaoCommentBean> parseTaobaoComment(String result, Task task) {
    JSONObject rateDetail = JSON.parseObject(result).getJSONObject("rateDetail");
    JSONArray rateList = rateDetail.getJSONArray("rateList");
    List<TaobaoCommentBean> beans = new ArrayList<TaobaoCommentBean>(rateList.size());
    String itemId = HttpURLUtils.getUrlParams(task.getUrl(), "GBK").get("itemId");
    TaobaoCommentBean bean = null;
    for (int i = 0; i < rateList.size(); i++) {
      bean = new TaobaoCommentBean();
      bean.setType(task.getExtra());
      bean.setItemId(itemId);
      try {
        JSONObject rate = rateList.getJSONObject(i);
        bean.setId(rate.getString("id"));
        bean.setConmment(rate.getString("rateContent"));
        bean.setCommentTime(rate.getString("rateDate"));
        bean.setReply(rate.getString("reply"));

        String appendCommentJson = rate.getString("appendComment");
        if (!StringUtils.isBlank(appendCommentJson)
            && StringUtils.startsWith(appendCommentJson, "{")) {
          JSONObject appendComment = JSON.parseObject(appendCommentJson);
          bean.setAppandConmment(appendComment.getString("content"));

        } else {
          bean.setAppandConmment(appendCommentJson);
        }

        bean.setServiceComment(rate.getString("serviceRateContent"));

        // user
        bean.setNick(rate.getString("displayUserNick"));
        bean.setVip(rate.getString("tamllSweetLevel"));

        beans.add(bean);
      } catch (Exception e) {

      }
    }
    return beans;
  }
Example #17
0
  protected static MailAddress parsePath(int maxNumParams, String prefix, String str)
      throws SmtpCommandException {
    String[] params = parseParameters(1, maxNumParams, str);

    if (!StringUtils.startsWith(params[0], prefix)
        || !StringUtils.endsWith(
            params[0], ToolMailAddressUtils.MAIL_ADDR_PART_PERSONAL_ADDR_SUFFIX)) {
      throw new SmtpCommandException(
          new SmtpReplyImpl(
              SmtpReplyCode.SYNTAX_ERROR_ARGUMENTS,
              String.format(
                  "Required syntax: '%slocal@domain%s'",
                  prefix, ToolMailAddressUtils.MAIL_ADDR_PART_PERSONAL_ADDR_SUFFIX)));
    }

    int pathLen =
        (params[0] =
                StringUtils.removeEnd(
                    StringUtils.removeStart(params[0], prefix),
                    ToolMailAddressUtils.MAIL_ADDR_PART_PERSONAL_ADDR_SUFFIX))
            .length();

    if (pathLen > MAX_PATH_LEN) {
      throw new SmtpCommandException(
          new SmtpReplyImpl(
              SmtpReplyCode.SYNTAX_ERROR_ARGUMENTS,
              String.format("Path too long: %d > %d", pathLen, MAX_PATH_LEN)));
    }

    Matcher pathMatcher = PATTERN_PATH.matcher(params[0]);

    if (!pathMatcher.matches()) {
      throw new SmtpCommandException(
          new SmtpReplyImpl(
              SmtpReplyCode.SYNTAX_ERROR_ARGUMENTS,
              String.format("Malformed email address: %s", params[0])));
    }

    return new MailAddressImpl(pathMatcher.group(1));
  }
 /**
  * 注解到对象复制,只复制能匹配上的方法。
  *
  * @param annotation
  * @param object
  */
 public static void annotationToObject(Object annotation, Object object) {
   if (annotation != null) {
     Class<?> annotationClass = annotation.getClass();
     Class<?> objectClass = object.getClass();
     for (Method m : objectClass.getMethods()) {
       if (StringUtils.startsWith(m.getName(), "set")) {
         try {
           String s = StringUtils.uncapitalize(StringUtils.substring(m.getName(), 3));
           Object obj = annotationClass.getMethod(s).invoke(annotation);
           if (obj != null && !"".equals(obj.toString())) {
             if (object == null) {
               object = objectClass.newInstance();
             }
             m.invoke(object, obj);
           }
         } catch (Exception e) {
           // 忽略所有设置失败方法
         }
       }
     }
   }
 }
Example #19
0
  @Nullable
  private String makeAbsoluteURL(final String url) {
    // Check if uri is absolute or not, if not attach the connector hostname
    // FIXME: that should also include the scheme
    if (Uri.parse(url).isAbsolute()) {
      return url;
    }

    final String host = ConnectorFactory.getConnector(geocode).getHost();
    if (StringUtils.isNotEmpty(host)) {
      final StringBuilder builder = new StringBuilder("http://");
      builder.append(host);
      if (!StringUtils.startsWith(url, "/")) {
        // FIXME: explain why the result URL would be valid if the path does not start with
        // a '/', or signal an error.
        builder.append('/');
      }
      builder.append(url);
      return builder.toString();
    }

    return null;
  }
Example #20
0
 public boolean isPrefixOf(TaskCharSet other) {
   return StringUtils.startsWith(
       other.getJoinedStringOfIdentifiers(), this.getJoinedStringOfIdentifiers());
 }
  /**
   * Creates any result types from the resources available in the web application. This scans the
   * web application resources using the servlet context.
   *
   * @param actionClass The action class the results are being built for.
   * @param results The results map to put the result configs created into.
   * @param resultPath The calculated path to the resources.
   * @param resultPrefix The prefix for the result. This is usually <code>/resultPath/actionName
   *     </code>.
   * @param actionName The action name which is used only for logging in this implementation.
   * @param packageConfig The package configuration which is passed along in order to determine
   * @param resultsByExtension The map of extensions to result type configuration instances.
   */
  protected void createFromResources(
      Class<?> actionClass,
      Map<String, ResultConfig> results,
      final String resultPath,
      final String resultPrefix,
      final String actionName,
      PackageConfig packageConfig,
      Map<String, ResultTypeConfig> resultsByExtension) {
    if (LOG.isTraceEnabled()) {
      LOG.trace(
          "Searching for results in the Servlet container at [#0]" + " with result prefix of [#1]",
          resultPath,
          resultPrefix);
    }

    // Build from web application using the ServletContext
    @SuppressWarnings("unchecked")
    Set<String> paths =
        servletContext.getResourcePaths(flatResultLayout ? resultPath : resultPrefix);
    if (paths != null) {
      for (String path : paths) {
        if (LOG.isTraceEnabled()) {
          LOG.trace("Processing resource path [#0]", path);
        }

        String fileName = StringUtils.substringAfterLast(path, "/");
        if (StringUtils.isBlank(fileName) || StringUtils.startsWith(fileName, ".")) {
          if (LOG.isTraceEnabled()) LOG.trace("Ignoring file without name [#0]", path);
          continue;
        } else if (fileName.lastIndexOf(".") > 0) {
          String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);

          if (conventionsService.getResultTypesByExtension(packageConfig).get(suffix) == null) {
            if (LOG.isDebugEnabled())
              LOG.debug(
                  "No result type defined for file suffix : [#0]. Ignoring file #1",
                  suffix,
                  fileName);
            continue;
          }
        }

        makeResults(actionClass, path, resultPrefix, results, packageConfig, resultsByExtension);
      }
    }

    // Building from the classpath
    String classPathLocation =
        resultPath.startsWith("/") ? resultPath.substring(1, resultPath.length()) : resultPath;
    if (LOG.isTraceEnabled()) {
      LOG.trace(
          "Searching for results in the class path at [#0]"
              + " with a result prefix of [#1] and action name [#2]",
          classPathLocation,
          resultPrefix,
          actionName);
    }

    ResourceFinder finder = new ResourceFinder(classPathLocation, getClassLoaderInterface());
    try {
      Map<String, URL> matches = finder.getResourcesMap("");
      if (matches != null) {
        Test<URL> resourceTest = getResourceTest(resultPath, actionName);
        for (Map.Entry<String, URL> entry : matches.entrySet()) {
          if (resourceTest.test(entry.getValue())) {
            if (LOG.isTraceEnabled()) {
              LOG.trace("Processing URL [#0]", entry.getKey());
            }

            String urlStr = entry.getValue().toString();
            int index = urlStr.lastIndexOf(resultPrefix);
            String path = urlStr.substring(index);
            makeResults(
                actionClass, path, resultPrefix, results, packageConfig, resultsByExtension);
          }
        }
      }
    } catch (IOException ex) {
      if (LOG.isErrorEnabled())
        LOG.error("Unable to scan directory [#0] for results", ex, classPathLocation);
    }
  }
Example #22
0
  protected void processRequest(final HttpServletRequest req, final HttpServletResponse resp) {
    LanternUtils.addCSPHeader(resp);
    final String uri = req.getRequestURI();
    log.debug("Received URI: {}", uri);
    final String interactionStr = StringUtils.substringAfterLast(uri, "/");
    if (StringUtils.isBlank(interactionStr)) {
      log.debug("blank interaction");
      HttpUtils.sendClientError(resp, "blank interaction");
      return;
    }

    log.debug("Headers: " + HttpUtils.getRequestHeaders(req));

    if (!"XMLHttpRequest".equals(req.getHeader("X-Requested-With"))) {
      log.debug("invalid X-Requested-With");
      HttpUtils.sendClientError(resp, "invalid X-Requested-With");
      return;
    }

    if (!SecurityUtils.constantTimeEquals(model.getXsrfToken(), req.getHeader("X-XSRF-TOKEN"))) {
      log.debug(
          "X-XSRF-TOKEN wrong: got {} expected {}",
          req.getHeader("X-XSRF-TOKEN"),
          model.getXsrfToken());
      HttpUtils.sendClientError(resp, "invalid X-XSRF-TOKEN");
      return;
    }

    final int cl = req.getContentLength();
    String json = "";
    if (cl > 0) {
      try {
        json = IOUtils.toString(req.getInputStream());
      } catch (final IOException e) {
        log.error("Could not parse json?");
      }
    }

    log.debug("Body: '" + json + "'");

    final Interaction inter = Interaction.valueOf(interactionStr.toUpperCase());

    if (inter == Interaction.CLOSE) {
      if (handleClose(json)) {
        return;
      }
    }

    if (inter == Interaction.URL) {
      final String url = JsonUtils.getValueFromJson("url", json);
      if (!StringUtils.startsWith(url, "http://") && !StringUtils.startsWith(url, "https://")) {
        log.error("http(s) url expected, got {}", url);
        HttpUtils.sendClientError(resp, "http(s) urls only");
        return;
      }
      try {
        new URL(url);
      } catch (MalformedURLException e) {
        log.error("invalid url: {}", url);
        HttpUtils.sendClientError(resp, "invalid url");
        return;
      }

      final String cmd;
      if (SystemUtils.IS_OS_MAC_OSX) {
        cmd = "open";
      } else if (SystemUtils.IS_OS_LINUX) {
        cmd = "gnome-open";
      } else if (SystemUtils.IS_OS_WINDOWS) {
        cmd = "start";
      } else {
        log.error("unsupported OS");
        HttpUtils.sendClientError(resp, "unsupported OS");
        return;
      }
      try {
        if (SystemUtils.IS_OS_WINDOWS) {
          // On Windows, we have to quote the url to allow for
          // e.g. ? and & characters in query string params.
          // To quote the url, we supply a dummy first argument,
          // since otherwise start treats the first argument as a
          // title for the new console window when it's quoted.
          LanternUtils.runCommand(cmd, "\"\"", "\"" + url + "\"");
        } else {
          // on OS X and Linux, special characters in the url make
          // it through this call without our having to quote them.
          LanternUtils.runCommand(cmd, url);
        }
      } catch (IOException e) {
        log.error("open url failed");
        HttpUtils.sendClientError(resp, "open url failed");
        return;
      }
      return;
    }

    final Modal modal = this.model.getModal();

    log.debug(
        "processRequest: modal = {}, inter = {}, mode = {}",
        modal,
        inter,
        this.model.getSettings().getMode());

    if (handleExceptionalInteractions(modal, inter, json)) {
      return;
    }

    Modal switchTo = null;
    try {
      // XXX a map would make this more robust
      switchTo = Modal.valueOf(interactionStr);
    } catch (IllegalArgumentException e) {
    }
    if (switchTo != null && switchModals.contains(switchTo)) {
      if (!switchTo.equals(modal)) {
        if (!switchModals.contains(modal)) {
          this.internalState.setLastModal(modal);
        }
        Events.syncModal(model, switchTo);
      }
      return;
    }

    switch (modal) {
      case welcome:
        this.model.getSettings().setMode(Mode.unknown);
        switch (inter) {
          case GET:
            log.debug("Setting get mode");
            handleSetModeWelcome(Mode.get);
            break;
          case GIVE:
            log.debug("Setting give mode");
            handleSetModeWelcome(Mode.give);
            break;
        }
        break;
      case authorize:
        log.debug("Processing authorize modal...");
        this.internalState.setModalCompleted(Modal.authorize);
        this.internalState.advanceModal(null);
        break;
      case finished:
        this.internalState.setCompletedTo(Modal.finished);
        switch (inter) {
          case CONTINUE:
            log.debug("Processing continue");
            this.model.setShowVis(true);
            Events.sync(SyncPath.SHOWVIS, true);
            this.internalState.setModalCompleted(Modal.finished);
            this.internalState.advanceModal(null);
            break;
          case SET:
            log.debug("Processing set in finished modal...applying JSON\n{}", json);
            applyJson(json);
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            HttpUtils.sendClientError(
                resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter);
            break;
        }
        break;
      case firstInviteReceived:
        log.error("Processing invite received...");
        break;
      case lanternFriends:
        this.internalState.setCompletedTo(Modal.lanternFriends);
        switch (inter) {
          case FRIEND:
            this.friender.addFriend(email(json));
            break;
          case REJECT:
            this.friender.removeFriend(email(json));
            break;
          case CONTINUE:
            // This dialog always passes continue as of this writing and
            // not close.
          case CLOSE:
            log.debug("Processing continue/close for friends dialog");
            if (this.model.isSetupComplete()) {
              Events.syncModal(model, Modal.none);
            } else {
              this.internalState.setModalCompleted(Modal.lanternFriends);
              this.internalState.advanceModal(null);
            }
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            HttpUtils.sendClientError(
                resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter);
            break;
        }
        break;
      case none:
        break;
      case notInvited:
        switch (inter) {
          case RETRY:
            Events.syncModal(model, Modal.authorize);
            break;
            // not currently implemented:
            // case REQUESTINVITE:
            //    Events.syncModal(model, Modal.requestInvite);
            //    break;
          default:
            log.error("Unexpected interaction: " + inter);
            break;
        }
        break;
      case proxiedSites:
        this.internalState.setCompletedTo(Modal.proxiedSites);
        switch (inter) {
          case CONTINUE:
            if (this.model.isSetupComplete()) {
              Events.syncModal(model, Modal.none);
            } else {
              this.internalState.setModalCompleted(Modal.proxiedSites);
              this.internalState.advanceModal(null);
            }
            break;
          case LANTERNFRIENDS:
            log.debug("Processing lanternFriends from proxiedSites");
            Events.syncModal(model, Modal.lanternFriends);
            break;
          case SET:
            if (!model.getSettings().isSystemProxy()) {
              String msg =
                  "Because you are using manual proxy "
                      + "configuration, you may have to restart your "
                      + "browser for your updated proxied sites list "
                      + "to take effect.";
              model.addNotification(msg, MessageType.info, 30);
              Events.sync(SyncPath.NOTIFICATIONS, model.getNotifications());
            }
            applyJson(json);
            break;
          case SETTINGS:
            log.debug("Processing settings from proxiedSites");
            Events.syncModal(model, Modal.settings);
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            HttpUtils.sendClientError(resp, "unexpected interaction for proxied sites");
            break;
        }
        break;
      case requestInvite:
        log.info("Processing request invite");
        switch (inter) {
          case CANCEL:
            this.internalState.setModalCompleted(Modal.requestInvite);
            this.internalState.advanceModal(Modal.notInvited);
            break;
          case CONTINUE:
            applyJson(json);
            this.internalState.setModalCompleted(Modal.proxiedSites);
            // TODO: need to do something here
            this.internalState.advanceModal(null);
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            HttpUtils.sendClientError(resp, "unexpected interaction for request invite");
            break;
        }
        break;
      case requestSent:
        log.debug("Process request sent");
        break;
      case settings:
        switch (inter) {
          case GET:
            log.debug("Setting get mode");
            // Only deal with a mode change if the mode has changed!
            if (modelService.getMode() == Mode.give) {
              // Break this out because it's set in the subsequent
              // setMode call
              final boolean everGet = model.isEverGetMode();
              this.modelService.setMode(Mode.get);
              if (!everGet) {
                // need to do more setup to switch to get mode from
                // give mode
                model.setSetupComplete(false);
                model.setModal(Modal.proxiedSites);
                Events.syncModel(model);
              } else {
                // This primarily just triggers a setup complete event,
                // which triggers connecting to proxies, setting up
                // the local system proxy, etc.
                model.setSetupComplete(true);
              }
            }
            break;
          case GIVE:
            log.debug("Setting give mode");
            this.modelService.setMode(Mode.give);
            break;
          case CLOSE:
            log.debug("Processing settings close");
            Events.syncModal(model, Modal.none);
            break;
          case SET:
            log.debug("Processing set in setting...applying JSON\n{}", json);
            applyJson(json);
            break;
          case RESET:
            log.debug("Processing reset");
            Events.syncModal(model, Modal.confirmReset);
            break;
          case PROXIEDSITES:
            log.debug("Processing proxied sites in settings");
            Events.syncModal(model, Modal.proxiedSites);
            break;
          case LANTERNFRIENDS:
            log.debug("Processing friends in settings");
            Events.syncModal(model, Modal.lanternFriends);
            break;

          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            HttpUtils.sendClientError(
                resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter);
            break;
        }
        break;
      case settingsLoadFailure:
        switch (inter) {
          case RETRY:
            modelIo.reload();
            Events.sync(SyncPath.NOTIFICATIONS, model.getNotifications());
            Events.syncModal(model, model.getModal());
            break;
          case RESET:
            backupSettings();
            Events.syncModal(model, Modal.welcome);
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            break;
        }
        break;
      case systemProxy:
        this.internalState.setCompletedTo(Modal.systemProxy);
        switch (inter) {
          case CONTINUE:
            log.debug("Processing continue in systemProxy", json);
            applyJson(json);
            Events.sync(SyncPath.SYSTEMPROXY, model.getSettings().isSystemProxy());
            this.internalState.setModalCompleted(Modal.systemProxy);
            this.internalState.advanceModal(null);
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            HttpUtils.sendClientError(resp, "error setting system proxy pref");
            break;
        }
        break;
      case updateAvailable:
        switch (inter) {
          case CLOSE:
            this.internalState.setModalCompleted(Modal.updateAvailable);
            this.internalState.advanceModal(null);
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            break;
        }
        break;
      case authorizeLater:
        log.error("Did not handle interaction {} for modal {}", inter, modal);
        break;
      case confirmReset:
        log.debug("Handling confirm reset interaction");
        switch (inter) {
          case CANCEL:
            log.debug("Processing cancel");
            Events.syncModal(model, Modal.settings);
            break;
          case RESET:
            handleReset();
            Events.syncModel(this.model);
            break;
          default:
            log.error("Did not handle interaction {} for modal {}", inter, modal);
            HttpUtils.sendClientError(
                resp, "Interaction not handled for modal: " + modal + " and interaction: " + inter);
        }
        break;
      case about: // fall through on purpose
      case sponsor:
        switch (inter) {
          case CLOSE:
            Events.syncModal(model, this.internalState.getLastModal());
            break;
          default:
            HttpUtils.sendClientError(resp, "invalid interaction " + inter);
        }
        break;
      case contact:
        switch (inter) {
          case CONTINUE:
            String msg;
            MessageType messageType;
            try {
              lanternFeedback.submit(json, this.model.getProfile().getEmail());
              msg = "Thank you for contacting Lantern.";
              messageType = MessageType.info;
            } catch (Exception e) {
              log.error("Error submitting contact form: {}", e);
              msg = "Error sending message. Please check your " + "connection and try again.";
              messageType = MessageType.error;
            }
            model.addNotification(msg, messageType, 30);
            Events.sync(SyncPath.NOTIFICATIONS, model.getNotifications());
            // fall through because this should be done in both cases:
          case CANCEL:
            Events.syncModal(model, this.internalState.getLastModal());
            break;
          default:
            HttpUtils.sendClientError(resp, "invalid interaction " + inter);
        }
        break;
      case giveModeForbidden:
        if (inter == Interaction.CONTINUE) {
          //  need to do more setup to switch to get mode from give mode
          model.getSettings().setMode(Mode.get);
          model.setSetupComplete(false);
          this.internalState.advanceModal(null);
          Events.syncModal(model, Modal.proxiedSites);
          Events.sync(SyncPath.SETUPCOMPLETE, false);
        }
        break;
      default:
        log.error("No matching modal for {}", modal);
    }
    this.modelIo.write();
  }