@Override
  public void startImportAllProblemsFromCourse(Course source, Course dest)
      throws CloudCoderAuthenticationException {
    User authenticatedUser =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    // Make sure that the authenticated user is registered as an instructor for
    // both the source and destination courses.
    boolean sourceInstructor = false, destInstructor = false;
    List<? extends Object[]> courses = Database.getInstance().getCoursesForUser(authenticatedUser);
    for (Object[] triple : courses) {
      CourseRegistration reg = (CourseRegistration) triple[2];
      if (reg.getCourseId() == source.getId() && reg.getRegistrationType().isInstructor()) {
        sourceInstructor = true;
      }
      if (reg.getCourseId() == dest.getId() && reg.getRegistrationType().isInstructor()) {
        destInstructor = true;
      }
    }

    // Create a FutureImportCourseResult
    FutureImportCourseResult result = new FutureImportCourseResult();
    getThreadLocalRequest()
        .getSession()
        .setAttribute(SessionAttributeKeys.FUTURE_IMPORT_COURSE_RESULT_KEY, result);

    if (!sourceInstructor || !destInstructor) {
      result.set(new OperationResult(false, "Permission denied (not an instructor)"));
      return;
    }

    // Start the actual operation
    result.start(source, dest, authenticatedUser);
  }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getCourseAndCourseRegistrations()
   */
  @Override
  public CourseAndCourseRegistration[] getCourseAndCourseRegistrations()
      throws CloudCoderAuthenticationException {
    // make sure the client has authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    logger.info("Loading courses and registrations for user " + user.getUsername());

    List<? extends Object[]> resultList = Database.getInstance().getCoursesForUser(user);

    CourseAndCourseRegistration[] result = new CourseAndCourseRegistration[resultList.size()];
    int count = 0;
    for (Object[] tuple : resultList) {
      Course course = (Course) tuple[0];
      Term term = (Term) tuple[1];
      course.setTerm(term);
      CourseRegistration reg = (CourseRegistration) tuple[2];

      CourseAndCourseRegistration obj = new CourseAndCourseRegistration();
      obj.setCourse(course);
      obj.setCourseRegistration(reg);

      result[count++] = obj;
    }

    return result;
  }
 /* (non-Javadoc)
  * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#startQuiz(org.cloudcoder.app.shared.model.Problem, int)
  */
 @Override
 public Quiz startQuiz(Problem problem, int section) throws CloudCoderAuthenticationException {
   // Make sure user is authenticated
   User user =
       ServletUtil.checkClientIsAuthenticated(
           getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);
   return Database.getInstance().startQuiz(user, problem, section);
 }
 @Override
 public NamedTestResult[] getTestResultsForSubmission(Problem problem, SubmissionReceipt receipt)
     throws CloudCoderAuthenticationException {
   User authenticatedUser =
       ServletUtil.checkClientIsAuthenticated(
           getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);
   return Database.getInstance().getTestResultsForSubmission(authenticatedUser, problem, receipt);
 }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getTestCasesForProblem(int)
   */
  @Override
  public TestCase[] getTestCasesForProblem(int problemId) throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    return Database.getInstance().getTestCasesForProblem(user, true, problemId);
  }
  @Override
  public Integer[] getSectionsForCourse(Course course) throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    return Database.getInstance().getSectionsForCourse(course, user);
  }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#endQuiz(org.cloudcoder.app.shared.model.Quiz)
   */
  @Override
  public Boolean endQuiz(Quiz quiz) throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    return Database.getInstance().endQuiz(user, quiz);
  }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#setModuleName(org.cloudcoder.app.shared.model.Problem, java.lang.String)
   */
  @Override
  public Module setModule(Problem problem, String moduleName)
      throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    return Database.getInstance().setModule(user, problem, moduleName);
  }
 @Override
 public OperationResult deleteProblem(Course course, Problem problem)
     throws CloudCoderAuthenticationException {
   // Make sure a user is authenticated
   User user =
       ServletUtil.checkClientIsAuthenticated(
           getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);
   boolean result = Database.getInstance().deleteProblem(user, course, problem);
   return new OperationResult(
       result, result ? "Problem deleted successfully" : "Could not delete problem");
 }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getBestSubmissionReceipts(org.cloudcoder.app.shared.model.Problem)
   */
  @Override
  public UserAndSubmissionReceipt[] getBestSubmissionReceipts(Problem problem, int section)
      throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    // Return best submission receipts for each user in course
    List<UserAndSubmissionReceipt> result =
        Database.getInstance().getBestSubmissionReceipts(problem, section, user);
    return result.toArray(new UserAndSubmissionReceipt[result.size()]);
  }
 /* (non-Javadoc)
  * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getTestCaseNamesForProblem(int)
  */
 @Override
 public String[] getTestCaseNamesForProblem(int problemId)
     throws CloudCoderAuthenticationException {
   // Make sure user is authenticated
   User user =
       ServletUtil.checkClientIsAuthenticated(
           getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);
   TestCase[] testCaseList = Database.getInstance().getTestCasesForProblem(user, false, problemId);
   String[] result = new String[testCaseList.length];
   for (int i = 0; i < testCaseList.length; i++) {
     result[i] = testCaseList[i].getTestCaseName();
   }
   return result;
 }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getModulesForCourse(org.cloudcoder.app.shared.model.Course)
   */
  @Override
  public Module[] getModulesForCourse(Course course) throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    Module[] modulesForCourse = Database.getInstance().getModulesForCourse(user, course);

    // Sort using ModuleNameComparator
    Arrays.sort(modulesForCourse, new ModuleNameComparator());

    return modulesForCourse;
  }
 @Override
 public TestCase[] getNonSecretTestCasesForProblem(int problemId)
     throws CloudCoderAuthenticationException {
   User user =
       ServletUtil.checkClientIsAuthenticated(
           getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);
   TestCase[] testCases = Database.getInstance().getTestCasesForProblem(user, false, problemId);
   ArrayList<TestCase> nonSecretTestCases = new ArrayList<TestCase>();
   for (TestCase tc : testCases) {
     if (!tc.isSecret()) {
       nonSecretTestCases.add(tc);
     }
   }
   return nonSecretTestCases.toArray(new TestCase[nonSecretTestCases.size()]);
 }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#storeProblemAndTestCaseList(org.cloudcoder.app.shared.model.ProblemAndTestCaseList)
   */
  @Override
  public ProblemAndTestCaseList storeProblemAndTestCaseList(
      ProblemAndTestCaseList problemAndTestCaseList, Course course)
      throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    // Store in database
    Database.getInstance().storeProblemAndTestCaseList(problemAndTestCaseList, course, user);

    // Return updated object
    return problemAndTestCaseList;
  }
  @Override
  public Problem[] getProblems(Course course) throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    List<Problem> resultList =
        Database.getInstance().getProblemsInCourse(user, course).getProblemList();
    for (Problem p : resultList) {
      logger.info(p.getTestname() + " - " + p.getBriefDescription());
    }

    return resultList.toArray(new Problem[resultList.size()]);
  }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getProblemAndSubscriptionReceipts(org.cloudcoder.app.shared.model.Course)
   */
  @Override
  public ProblemAndSubmissionReceipt[] getProblemAndSubscriptionReceipts(
      Course course, User forUser, Module module) throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    logger.info(
        "getting problems/submission receipts for authenticated user " + user.getUsername());

    List<ProblemAndSubmissionReceipt> resultList =
        Database.getInstance()
            .getProblemAndSubscriptionReceiptsInCourse(user, course, forUser, module);
    logger.info("Received " + resultList.size() + " problems/submission receipts");
    return resultList.toArray(new ProblemAndSubmissionReceipt[resultList.size()]);
  }
  @Override
  public SubmissionReceipt[] getAllSubmissionReceiptsForUser(Problem problem, User user)
      throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User authenticatedUser =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    // Make sure authenticated user is an instructor
    CourseRegistrationList regList =
        Database.getInstance().findCourseRegistrations(authenticatedUser, problem.getCourseId());
    if (!regList.isInstructor()) {
      return new SubmissionReceipt[0];
    }

    return Database.getInstance().getAllSubmissionReceiptsForUser(problem, user);
  }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#findCurrentQuiz(org.cloudcoder.app.shared.model.Problem)
   */
  @Override
  public Quiz findCurrentQuiz(Problem problem) throws CloudCoderAuthenticationException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    // Find current quiz (if any)
    Quiz quiz = Database.getInstance().findCurrentQuiz(user, problem);

    if (quiz != null) {
      // Set the end time to the current time: this allows the client
      // to compute how long the quiz has been active
      quiz.setEndTime(System.currentTimeMillis());
    }

    return quiz;
  }
  @Override
  public void submit(int problemId, String programText)
      throws CloudCoderAuthenticationException, SubmissionException {
    // Make sure that client is authenticated and has permission to edit the given problem
    User user = ServletUtil.checkClientIsAuthenticated(getThreadLocalRequest());

    HttpSession session = getThreadLocalRequest().getSession();

    // The Problem should be stored in the user's session
    Problem problem = (Problem) session.getAttribute(SessionAttributeKeys.PROBLEM_KEY);
    if (problem == null || problem.getProblemId() != problemId) {
      throw new CloudCoderAuthenticationException();
    }

    // Insert a full-text change into the database.
    Change fullTextChange =
        new Change(
            ChangeType.FULL_TEXT,
            0,
            0,
            0,
            0,
            System.currentTimeMillis(),
            user.getId(),
            problem.getProblemId(),
            programText);
    Database.getInstance().storeChanges(new Change[] {fullTextChange});

    // Get test cases.  (TODO: cache them?)
    List<TestCase> testCaseList = Database.getInstance().getTestCasesForProblem(problemId);

    ISubmitService submitService = DefaultSubmitService.getInstance();

    logger.info("Passing submission to submit service...");
    IFutureSubmissionResult future = submitService.submitAsync(problem, testCaseList, programText);

    // Put the full-text Change and IFutureSubmissionResult in the user's session.
    addSessionObjects(session, fullTextChange, future);
  }
  @Override
  public void run(Problem problem, String programText, TestCase[] testCases)
      throws CloudCoderAuthenticationException, SubmissionException {
    // Make sure that client is authenticated and has permission to edit the given problem
    User user =
        ServletUtil.checkClientIsAuthenticated(getThreadLocalRequest(), RunServiceImpl.class);

    HttpSession session = getThreadLocalRequest().getSession();

    // TODO Don't insert into the DB yet, until we have some kind of a virtual file system
    // (or something like it)
    //        Change fullTextChange = new Change(
    //                ChangeType.FULL_TEXT,
    //                0, 0, 0, 0,
    //                System.currentTimeMillis(),
    //                user.getId(), problem.getProblemId(),
    //                programText);
    //        Database.getInstance().storeChanges(new Change[]{fullTextChange});

    ISubmitService submitService = DefaultSubmitService.getInstance();

    logger.info("Passing submission to submit service...");

    // Convert TestCase[] to List<TestCase> to match ISubmitService
    List<TestCase> listTestCases = new LinkedList<TestCase>();
    for (TestCase tc : testCases) {
      listTestCases.add(tc);
    }

    IFutureSubmissionResult future = submitService.submitAsync(problem, listTestCases, programText);

    // put the future into the session
    session.setAttribute(SessionAttributeKeys.FUTURE_SUBMISSION_RESULT_KEY, future);

    // Put the full-text Change and IFutureSubmissionResult in the user's session.
    // addSessionObjects(session, fullTextChange, future);
  }
  @Override
  public SubmissionResult checkSubmission()
      throws CloudCoderAuthenticationException, SubmissionException {
    // Make sure user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(getThreadLocalRequest(), RunServiceImpl.class);

    HttpSession session = getThreadLocalRequest().getSession();

    // Retrieve session objects for submission
    IFutureSubmissionResult future =
        (IFutureSubmissionResult)
            session.getAttribute(SessionAttributeKeys.FUTURE_SUBMISSION_RESULT_KEY);

    if (future == null) {
      throw new SubmissionException("No pending submission in session");
    }

    // See if the SubmissionResult is ready
    SubmissionResult result;
    try {
      result = future.waitFor(IFutureSubmissionResult.STANDARD_POLL_WAIT_MS);
    } catch (SubmissionException e) {
      // If poll() throws an exception, the submission completed
      // with an error, but it did complete, so clear the session objects.
      session.removeAttribute(SessionAttributeKeys.FUTURE_SUBMISSION_RESULT_KEY);
      throw e;
    } catch (InterruptedException e) {
      logger.error("checkSubmission interrupted unexpectedly", e);
      return null;
    }
    if (result == null) {
      // submission result not ready yet
      return null;
    }

    // Re-number the test results
    // The Builder thinks it is returning database keys
    // which it doesn't know so it sets everything to -1
    int i = 1;
    for (TestResult r : result.getTestResults()) {
      r.setId(i);
      i++;
    }

    // We are just trusting that the submission result is for the
    // correct problem...

    // TODO Put results into DB once we have a meta-file system set up
    //        SubmissionReceipt receipt = createSubmissionReceipt(fullTextChange, result, user,
    // problem);
    //        Database.getInstance().insertSubmissionReceipt(receipt, result.getTestResults());
    //
    //        int numResult=0;
    //        if (result!=null && result.getTestResults()!=null) {
    //            numResult=result.getTestResults().length;
    //        }
    //        logger.info("Compilation "+result.getCompilationResult()+", received " +numResult+"
    // TestResults");
    //
    //        // Clear session objects for submission
    //        session.removeAttribute(SessionAttributeKeys.FUTURE_SUBMISSION_RESULT_KEY);
    return result;
  }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.SubmitService#checkSubmission()
   */
  @Override
  public SubmissionResult checkSubmission()
      throws CloudCoderAuthenticationException, SubmissionException {
    // Make sure user is authenticated
    User user = ServletUtil.checkClientIsAuthenticated(getThreadLocalRequest());

    HttpSession session = getThreadLocalRequest().getSession();

    // The Problem should be stored in the user's session
    Problem problem = (Problem) session.getAttribute(SessionAttributeKeys.PROBLEM_KEY);
    if (problem == null) {
      throw new CloudCoderAuthenticationException();
    }

    // Retrieve session objects for submission
    IFutureSubmissionResult future =
        (IFutureSubmissionResult)
            session.getAttribute(SessionAttributeKeys.FUTURE_SUBMISSION_RESULT_KEY);
    Change fullTextChange =
        (Change) session.getAttribute(SessionAttributeKeys.FULL_TEXT_CHANGE_KEY);

    if (future == null) {
      throw new SubmissionException("No pending submission in session");
    }
    if (fullTextChange == null) {
      throw new SubmissionException("No full-text change for pending submission in session");
    }

    // See if the SubmissionResult is ready
    SubmissionResult result;
    try {
      result = future.poll();
    } catch (SubmissionException e) {
      // If poll() throws an exception, the submission completed
      // with an error, but it did complete, so clear the session objects.
      clearSessionObjects(session);
      throw e;
    }
    if (result == null) {
      // submission result not ready yet
      return null;
    }

    // We are just trusting that the submission result is for the
    // correct problem...

    // Add a SubmissionReceipt to the database
    SubmissionReceipt receipt = createSubmissionReceipt(fullTextChange, result, user, problem);
    Database.getInstance().insertSubmissionReceipt(receipt, result.getTestResults());

    int numResult = 0;
    if (result != null && result.getTestResults() != null) {
      numResult = result.getTestResults().length;
    }
    logger.info(
        "Compilation "
            + result.getCompilationResult()
            + ", received "
            + numResult
            + " TestResults");

    // Clear session objects for submission
    clearSessionObjects(session);

    return result;
  }
  /* (non-Javadoc)
   * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#submitExercise(org.cloudcoder.app.shared.model.ProblemAndTestCaseList, java.lang.String, java.lang.String)
   */
  @Override
  public OperationResult submitExercise(
      ProblemAndTestCaseList exercise, String repoUsername, String repoPassword)
      throws CloudCoderAuthenticationException {
    logger.warn("Sharing exercise: " + exercise.getProblem().getTestname());

    // Only a course instructor may share an exercise.
    User authenticatedUser =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);
    Course course = new Course();
    course.setId(exercise.getProblem().getCourseId());
    Database.getInstance().reloadModelObject(course);
    CourseRegistrationList regList =
        Database.getInstance().findCourseRegistrations(authenticatedUser, course);
    if (!regList.isInstructor()) {
      return new OperationResult(false, "You must be an instructor to share an exercise");
    }

    // Get the exercise repository URL
    ConfigurationSetting repoUrlSetting =
        Database.getInstance().getConfigurationSetting(ConfigurationSettingName.PUB_REPOSITORY_URL);
    if (repoUrlSetting == null) {
      return new OperationResult(false, "URL of exercise repository is not configured");
    }
    String repoUrl = repoUrlSetting.getValue();
    if (repoUrl.endsWith("/")) {
      repoUrl = repoUrl.substring(0, repoUrl.length() - 1);
    }

    HttpPost post = new HttpPost(repoUrl + "/exercisedata");

    // Encode an Authorization header using the provided repository username and password.
    String authHeaderValue =
        "Basic "
            + DatatypeConverter.printBase64Binary(
                (repoUsername + ":" + repoPassword).getBytes(Charset.forName("UTF-8")));
    // System.out.println("Authorization: " + authHeaderValue);
    post.addHeader("Authorization", authHeaderValue);

    // Convert the exercise to a JSON string
    StringEntity entity;
    StringWriter sw = new StringWriter();
    try {
      JSONConversion.writeProblemAndTestCaseData(exercise, sw);
      entity = new StringEntity(sw.toString(), ContentType.create("application/json", "UTF-8"));
    } catch (IOException e) {
      return new OperationResult(false, "Could not convert exercise to JSON: " + e.getMessage());
    }
    post.setEntity(entity);

    // POST the exercise to the repository
    HttpClient client = new DefaultHttpClient();
    try {
      HttpResponse response = client.execute(post);

      StatusLine statusLine = response.getStatusLine();

      if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
        // Update the exercise's shared flag so we have a record that it was shared.
        exercise.getProblem().setShared(true);
        Database.getInstance().storeProblemAndTestCaseList(exercise, course, authenticatedUser);

        return new OperationResult(
            true, "Exercise successfully published to the repository - thank you!");
      } else if (statusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
        return new OperationResult(
            false, "Authentication with repository failed - incorrect username/password?");
      } else {
        return new OperationResult(
            false, "Failed to publish exercise to repository: " + statusLine.getReasonPhrase());
      }
    } catch (ClientProtocolException e) {
      return new OperationResult(false, "Error sending exercise to repository: " + e.getMessage());
    } catch (IOException e) {
      return new OperationResult(false, "Error sending exercise to repository: " + e.getMessage());
    } finally {
      client.getConnectionManager().shutdown();
    }
  }
  @Override
  public ShareExercisesResult submitExercises(
      Problem[] problems, String repoUsername, String repoPassword)
      throws CloudCoderAuthenticationException {
    logger.warn("Sharing " + problems.length + " exercises");

    // create the result place holder
    ShareExercisesResult result = new ShareExercisesResult(problems.length);

    if (problems.length == 0) {
      result.failAll("No problems to be shared!");
      return result;
    }

    // Only a course instructor may share an exercise.
    User authenticatedUser =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);
    Course course = new Course();
    course.setId(problems[0].getCourseId());
    Database.getInstance().reloadModelObject(course);
    CourseRegistrationList regList =
        Database.getInstance().findCourseRegistrations(authenticatedUser, course);
    if (!regList.isInstructor()) {
      result.failAll("You must be an instructor to share an exercise");
      return result;
    }

    // Get the exercise repository URL
    ConfigurationSetting repoUrlSetting =
        Database.getInstance().getConfigurationSetting(ConfigurationSettingName.PUB_REPOSITORY_URL);
    if (repoUrlSetting == null) {
      result.failAll("URL of exercise repository is not configured");
      return result;
    }
    String repoUrl = repoUrlSetting.getValue();
    if (repoUrl.endsWith("/")) {
      repoUrl = repoUrl.substring(0, repoUrl.length() - 1);
    }

    HttpPost post = new HttpPost(repoUrl + "/exercisedata");

    // Encode an Authorization header using the provided repository username and password.
    String authHeaderValue =
        "Basic "
            + DatatypeConverter.printBase64Binary(
                (repoUsername + ":" + repoPassword).getBytes(Charset.forName("UTF-8")));
    // System.out.println("Authorization: " + authHeaderValue);
    post.addHeader("Authorization", authHeaderValue);

    // Now go through and upload each problem
    // For now, we do this one at a time
    // In the future we could send problems and test cases
    // to the repo in bulk, and add a new web service to handle it

    for (Problem p : problems) {
      // Look up the test cases
      List<TestCase> testCaseList = Database.getInstance().getTestCasesForProblem(p.getProblemId());
      ProblemAndTestCaseList exercise = new ProblemAndTestCaseList();
      exercise.setProblem(p);
      exercise.setTestCaseList(testCaseList);

      // Convert the exercise to a JSON string
      StringEntity entity;
      StringWriter sw = new StringWriter();
      try {
        JSONConversion.writeProblemAndTestCaseData(exercise, sw);
        entity = new StringEntity(sw.toString(), ContentType.create("application/json", "UTF-8"));
      } catch (IOException e) {
        // fail remaining test cases and return our results thus far
        // some exercises may have been successfully shared
        result.failRemaining("Could not convert exercise to JSON: " + e.getMessage());
        return result;
      }
      post.setEntity(entity);

      // POST the exercise to the repository
      HttpClient client = new DefaultHttpClient();
      try {
        HttpResponse response = client.execute(post);

        StatusLine statusLine = response.getStatusLine();

        if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
          // Update the exercise's shared flag so we have a record that it was shared.
          exercise.getProblem().setShared(true);
          exercise.getProblem().setProblemAuthorship(ProblemAuthorship.IMPORTED);
          Database.getInstance().storeProblemAndTestCaseList(exercise, course, authenticatedUser);
          result.success();
        } else if (statusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
          result.failRemaining(
              "Authentication with repository failed - incorrect username/password?");
          return result;
        } else {
          result.failRemaining(
              "Failed to publish exercise to repository: " + statusLine.getReasonPhrase());
          return result;
        }
      } catch (ClientProtocolException e) {
        result.failRemaining("Error sending exercise to repository: " + e.getMessage());
        return result;
      } catch (IOException e) {
        result.failRemaining("Error sending exercise to repository: " + e.getMessage());
        return result;
      } finally {
        client.getConnectionManager().shutdown();
      }
    }
    result.allSucceeded(
        "Successfully uploaded " + problems.length + " exercise to repository.  Thanks!");
    return result;
  }
  @Override
  public ProblemAndTestCaseList importExercise(Course course, String exerciseHash)
      throws CloudCoderAuthenticationException {
    if (course == null || exerciseHash == null) {
      throw new IllegalArgumentException();
    }

    // Make sure a user is authenticated
    User user =
        ServletUtil.checkClientIsAuthenticated(
            getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class);

    // Find user's registration in the course: if user is not instructor,
    // import is not allowed
    CourseRegistrationList reg = Database.getInstance().findCourseRegistrations(user, course);
    if (!reg.isInstructor()) {
      throw new CloudCoderAuthenticationException(
          "Only an instructor can import a problem in a course");
    }

    // Attempt to load the problem from the exercise repository.
    ConfigurationSetting repoUrlSetting =
        Database.getInstance().getConfigurationSetting(ConfigurationSettingName.PUB_REPOSITORY_URL);
    if (repoUrlSetting == null) {
      logger.error("Repository URL configuration setting is not set");
      return null;
    }

    // GET the exercise from the repository
    HttpGet get = new HttpGet(repoUrlSetting.getValue() + "/exercisedata/" + exerciseHash);
    ProblemAndTestCaseList exercise = null;

    HttpClient client = new DefaultHttpClient();
    try {
      HttpResponse response = client.execute(get);

      HttpEntity entity = response.getEntity();

      ContentType contentType = ContentType.getOrDefault(entity);
      Reader reader = new InputStreamReader(entity.getContent(), contentType.getCharset());

      exercise = new ProblemAndTestCaseList();
      exercise.setTestCaseList(new TestCase[0]);
      JSONConversion.readProblemAndTestCaseData(
          exercise,
          ReflectionFactory.forClass(Problem.class),
          ReflectionFactory.forClass(TestCase.class),
          reader);

      // Set the course id
      exercise.getProblem().setCourseId(course.getId());
    } catch (IOException e) {
      logger.error("Error importing exercise from repository", e);
      return null;
    } finally {
      client.getConnectionManager().shutdown();
    }

    // Set "when assigned" and "when due" to reasonable default values
    long now = System.currentTimeMillis();
    exercise.getProblem().setWhenAssigned(now);
    exercise.getProblem().setWhenDue(now + 48L * 60L * 60L * 1000L);

    // Set problem authorship as IMPORTED
    exercise.getProblem().setProblemAuthorship(ProblemAuthorship.IMPORTED);

    // For IMPORTED problems, parent_hash is actually the hash of the problem
    // itself.  If the problem is modified (and the authorship changed
    // to IMPORTED_AND_MODIFIED), then the (unchanged) parent_hash value
    // really does reflect the "parent" problem.
    exercise.getProblem().setParentHash(exerciseHash);

    // Store the exercise in the database
    exercise = Database.getInstance().storeProblemAndTestCaseList(exercise, course, user);

    return exercise;
  }