package jplagWebService.serverImpl;
/**
* @author Emeric Kwemou, Moritz Kroll
*/
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Date;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.rpc.server.ServiceLifecycle;
import javax.xml.rpc.server.ServletEndpointContext;
import jplagWebService.server.FinishRequestData;
import jplagWebService.server.JPlagException;
import jplagWebService.server.JPlagTyp;
import jplagWebService.server.LanguageInfo;
import jplagWebService.server.MailTemplateArray;
import jplagWebService.server.NotifyDevelopersParams;
import jplagWebService.server.RequestData;
import jplagWebService.server.RequestDataArray;
import jplagWebService.server.ServerInfo;
import jplagWebService.server.SetDeveloperStateParams;
import jplagWebService.server.SetMailTemplateParams;
import jplagWebService.server.SetUserDataParams;
import jplagWebService.server.StartResultDownloadData;
import jplagWebService.server.StartSubmissionUploadParams;
import jplagWebService.server.Status;
import jplagWebService.server.UpdateUserInfoParams;
import jplagWebService.server.UserDataArray;
import jplagWebService.serverAccess.AccessStructure;
import jplagWebService.serverAccess.JPlagServerAccessHandler;
import jplagWebService.serverAccess.StatusDecorator;
import jplagWebService.serverAccess.UserAdmin;
public class JPlagTypImpl implements JPlagTyp, Remote, ServiceLifecycle {
private ServletEndpointContext servletEndpointContext = null;
/**
* Singleton object. Will be initialized in the init() method
*/
private static JPlagCentral JPLAG_CENTRAL = null;
/**
* Minimal time between two getStatus request of the same user.
*/
private static final long MINIMAL_DIFF_TIME = 10000;
private static final String[] javasuffixes = { ".java", ".jav", ".JAVA", ".JAV" };
private static final String[] schemesuffixes = { ".scm", ".SCM" };
private static final String[] csuffixes = { ".cpp", ".CPP", ".c++", ".C++", ".c", ".C", ".h", ".H", ".hpp", ".HPP" };
private static final String[] textsuffixes = { ".txt", ".TXT", ".asc", ".ASC", ".tex", ".TEX" };
private static final String[] cssuffixes = { ".cs", ".CS" };// @formatter:off
public static final LanguageInfo[] languageInfos = {
// new LanguageInfo("java12", javasuffixes, 9),
new LanguageInfo("java15", javasuffixes, 8),
new LanguageInfo("java15dm", javasuffixes, 8),
new LanguageInfo("java17", javasuffixes, 8),
new LanguageInfo("scheme", schemesuffixes, 13),
new LanguageInfo("c/c++", csuffixes, 12),
new LanguageInfo("text", textsuffixes, 5),
// new LanguageInfo("char", textsuffixes, 10),
new LanguageInfo("c#-1.2", cssuffixes, 8) }; // @formatter:on
public static final String[] countryLanguages = { "en", "de", "fr", "es" };
/**
* Initializes the web service and starts the main thread
*/
public void init(Object context) throws ServiceException {
servletEndpointContext = (ServletEndpointContext) context;
// ensure that entry and result directories exist
AccessStructure.ensureExistence();
// create and start jplagCentral thread
JPLAG_CENTRAL = JPlagCentral.getInstance();
JPLAG_CENTRAL.start();
}
/**
* Sets a stop flag for the main thread
*/
public void destroy() {
servletEndpointContext = null;
JPLAG_CENTRAL.stopCentral();
JPLAG_CENTRAL = null;
}
private String getUsername() {
SOAPMessageContext smc = (SOAPMessageContext) servletEndpointContext.getMessageContext();
return JPlagServerAccessHandler.extractUsername(smc);
}
public ServerInfo getServerInfo() throws JPlagException, RemoteException {
String username = getUsername();
JPLAG_CENTRAL.getUserAdmin().updateLastUsage(username);
return new ServerInfo(JPlagCentral.getUserInfo(username), languageInfos, countryLanguages, JPlagCentral.listSubmissions(username));
}
// TODO: Perhaps get rid of the step over AccessStructure to make it clearer
public java.lang.String compareSource(jplagWebService.server.Option arguments, javax.mail.internet.MimeMultipart inputZipFile)
throws JPlagException, RemoteException {
String username = getUsername();
JPlagCentral.checkQuota(username);
JPLAG_CENTRAL.getUserAdmin().incrementSubmissionCounter(username);
AccessStructure struct = new AccessStructure(username, arguments, inputZipFile);
JPlagCentral.addToReadyQueue(struct);
return struct.getSubmissionID();
}
public String startSubmissionUpload(StartSubmissionUploadParams params) throws JPlagException, RemoteException {
if (params.getData().length < 1 || params.getData().length > 81920) {
System.out.println("startSubmissionUpload: data.length=" + params.getData().length);
throw new JPlagException("startSubmissionUploadException", "The size of the data array is invalid! Must be non empty and"
+ " 80 kB at maximum!", "Create correct data parts!");
}
String username = getUsername();
JPlagCentral.checkQuota(username);
JPLAG_CENTRAL.getUserAdmin().incrementSubmissionCounter(username);
AccessStructure struct = new AccessStructure(username, params.getSubmissionParams());
struct.getDecorator().setState(StatusDecorator.UPLOADING);
JPLAG_CENTRAL.getTransferManager().startUpload(struct, params.getFilesize(), params.getData());
return struct.getSubmissionID();
}
public int continueSubmissionUpload(byte[] data) throws JPlagException, RemoteException {
String username = getUsername();
if (data.length < 1 || data.length > 81920) {
System.out.println("startSubmissionUpload: data.length=" + data.length);
JPLAG_CENTRAL.getTransferManager().cancelUpload(username, null);
throw new JPlagException("continueSubmissionUploadException", "The size of the data array is invalid! Must be non empty and"
+ " 80 kB at maximum!", "Create correct data parts!");
}
JPLAG_CENTRAL.getTransferManager().writeNextPart(username, data);
return 0;
}
/**
* @param submissionID
* : Used to retrieve the submission of this user.
* @return Status object, containing all information about the state of
* operation on the submission with ID 'submissionID'
* @throws jplag.server.JPlagException
* this exception occurs when a submissionID is not a valid one
* @throws java.rmi.RemoteException
*/
public Status getStatus(java.lang.String submissionID) throws JPlagException, RemoteException {
String username = getUsername();
AccessStructure struct = JPlagCentral.search(JPlagCentral.ALLQUEUES, submissionID); // Search on all queues
/**
* Here we want to solve any getStatus flooding problem. In fact, this
* problem is very difficult to solve because an user could send
* getStatus request through different Threads
*/
if (struct == null || !struct.getUsername().equals(username)) {
/**
* In this situation, the access is denied or the submission does
* not exist. JPlagTyp_Impl just waits 10 second and then sends the
* exception or error message to the user.
*/
try {
Thread.sleep(MINIMAL_DIFF_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (struct != null) {
System.out.println("Wrong username (" + username + ") for " + "submission ID " + submissionID);
}
throw new JPlagException("statusException", "Submission does not exist!", "Please check submission ID " + "and username!");
} else {
/**
* The submission exists for this user, so check whether enough time
* has elapsed since the last status request
*/
long difference_time = System.currentTimeMillis() - struct.getLastStatusRequest();
try {
if (difference_time < MINIMAL_DIFF_TIME)
Thread.sleep(MINIMAL_DIFF_TIME - difference_time);
} catch (InterruptedException e) {
e.printStackTrace();
}
struct.setLastStatusRequest();
return struct.getDecorator().getStatus();
}
}
public javax.mail.internet.MimeMultipart getResult(String submissionID) throws JPlagException, RemoteException {
String username = getUsername();
// Search on terminatedQueue
AccessStructure struct = JPlagCentral.search(JPlagCentral.TERMINATEDQUEUE, submissionID);
if (struct == null || !struct.getUsername().equals(username)) {
throw new JPlagException("resultException", "Submission does not exist!", "Please check submission ID " + "and username!");
}
Status status = struct.getDecorator().getStatus();
if (status == null) {
throw new JPlagException("resultException", "Unable to retrieve status for submission!",
"Please check submission ID and username!");
} else if (status.getState() >= 400) {
throw new JPlagException("resultException", "Submission has been completed with errors! " + "Results not available!",
"You need to remove the errors and submit again!");
} else if (status.getState() < 300) {
throw new JPlagException("resultException", "Submission has not been completed yet!",
"Please check submission ID or try again " + "later!");
} else {
// Compare source finished without an error
return struct.getResult();
}
}
public StartResultDownloadData startResultDownload(String submissionID) throws JPlagException, RemoteException {
String username = getUsername();
// Search on terminatedQueue
AccessStructure struct = JPlagCentral.search(JPlagCentral.TERMINATEDQUEUE, submissionID);
if (struct == null || !struct.getUsername().equals(username)) {
throw new JPlagException("resultException", "Submission does not exist!", "Please check submission ID " + "and username!");
}
Status status = struct.getDecorator().getStatus();
if (status == null) {
throw new JPlagException("resultException", "Unable to retrieve status for submission!",
"Please check submission ID and username!");
} else if (status.getState() >= 400) {
throw new JPlagException("resultException", "Submission has been completed with errors! " + "Results not available!",
"You need to remove the errors and submit again!");
} else if (status.getState() < 300) {
throw new JPlagException("resultException", "Submission has not been completed yet!",
"Please check submission ID or try again " + "later!");
} else {
// Compare source finished without an error
return JPLAG_CENTRAL.getTransferManager().startDownload(struct);
}
}
public byte[] continueResultDownload(int dummy) throws JPlagException, RemoteException {
String username = getUsername();
return JPLAG_CENTRAL.getTransferManager().readNextPart(username);
}
public int cancelSubmission(String submissionID) throws JPlagException, RemoteException {
String username = getUsername();
AccessStructure struct = JPlagCentral.search(JPlagCentral.ALLQUEUES, submissionID);
if (struct == null || !struct.getUsername().equals(username)) {
if (struct == null) {
// not in entry or result list? check up- and downloads
if (JPLAG_CENTRAL.getTransferManager().cancelTransfer(username, submissionID))
return 0;
return 0;
}
throw new JPlagException("cancelException", "Submission does not exist!", "Please check submission ID " + "and username!");
}
Status status = struct.getDecorator().getStatus();
if (status == null) {
throw new JPlagException("cancelException", "Unable to retrieve status for submission!",
"Please check submission ID and username!");
}
System.out.println("[" + new Date() + "] User " + username + " cancels submission " + struct.getSubmissionID());
JPlagCentral.cancelSubmission(struct);
return 0;
}
private void logInvalidAccessAndThrow(String methodName, String user) throws JPlagException {
// log invalid access, wait a bit and throw an exception
System.out.println(methodName + ": " + user + " tried to access this function on " + new Date());
try {
Thread.sleep(10);
} catch (Exception ex) {
}
throw new JPlagException(methodName, "You don't have the rights to access this function!",
"Your username has been logged. Go away!");
}
/**
* Checks whether the current user has enough rights (mask parameter) to
* access the function with the given name
*
* @throws JPlagException
* when the user doesn't have those rights. The access will also
* be logged and the user has to wait 10 seconds.
*/
private int assertUser(String methodName, int mask) throws JPlagException {
String user = getUsername();
int userstate = JPLAG_CENTRAL.getUserAdmin().getState(user);
if ((userstate & mask) == 0)
logInvalidAccessAndThrow(methodName, user);
return userstate;
}
public UserDataArray getUserDataArray(int dummy) throws JPlagException, RemoteException {
int state = assertUser("getUserDataArray", UserAdmin.MASK_ANYADMIN);
return JPLAG_CENTRAL.getUserAdmin().getUserDataArray(getUsername(), (state & UserAdmin.MASK_JPLAGADMIN) == 0);
}
public int setUserData(SetUserDataParams params) throws JPlagException, RemoteException {
int state = assertUser("setUserData", UserAdmin.MASK_ANYADMIN);
JPLAG_CENTRAL.getUserAdmin().setUserData(params.getUserdata(), params.getOldUsername(), getUsername(),
(state & UserAdmin.MASK_JPLAGADMIN) == 0);
return 0;
}
public int updateUserInfo(UpdateUserInfoParams params) throws JPlagException, RemoteException {
JPLAG_CENTRAL.getUserAdmin().updateUserInfo(getUsername(), params.getNewPassword(), params.getNewEmailSecond(),
params.getNewHomepage());
return 0;
}
public boolean requestAccount(RequestData data) throws JPlagException, RemoteException {
assertUser("requestAccount", UserAdmin.USER_SERVERPAGE);
return JPLAG_CENTRAL.getUserAdmin().requestAccount(data);
}
public RequestDataArray getAccountRequests(boolean lengthOnly) throws JPlagException, RemoteException {
assertUser("getAccountRequests", UserAdmin.MASK_ANYADMIN);
return new RequestDataArray(JPLAG_CENTRAL.getUserAdmin().getRequestAdmin().getRequests(lengthOnly));
}
public int finishAccountRequest(FinishRequestData finishData) throws JPlagException, RemoteException {
assertUser("finishAccountRequest", UserAdmin.MASK_JPLAGADMIN);
JPLAG_CENTRAL.getUserAdmin().finishAccountRequest(finishData, getUsername());
return 0;
}
public int extendAccount(String extendCode) throws JPlagException, RemoteException {
assertUser("extendAccount", UserAdmin.USER_SERVERPAGE);
JPLAG_CENTRAL.getUserAdmin().extendAccount(extendCode);
return 0;
}
public MailTemplateArray getMailTemplates(int type) throws JPlagException, RemoteException {
assertUser("getMailTemplates", UserAdmin.MASK_JPLAGADMIN);
return new MailTemplateArray(JPLAG_CENTRAL.getMailTemplateAdmin().getMailTemplates(type));
}
public int setMailTemplate(SetMailTemplateParams params) throws JPlagException, RemoteException {
assertUser("setMailTemplate", UserAdmin.MASK_JPLAGADMIN);
JPLAG_CENTRAL.getMailTemplateAdmin().setMailTemplate(params.getType(), params.getTemplate());
return 0;
}
public int notifyDevelopers(NotifyDevelopersParams params) throws JPlagException, RemoteException {
assertUser("notifyDevelopers", UserAdmin.MASK_JPLAGADMIN);
JPLAG_CENTRAL.getUserAdmin().notifyDevelopers(params.getSubject(), params.getMessage());
return 0;
}
public int setDeveloperState(SetDeveloperStateParams params) throws JPlagException, RemoteException {
assertUser("setDeveloperState", UserAdmin.USER_SERVERPAGE);
int curstate = JPLAG_CENTRAL.getUserAdmin().getLoginState(params.getUsername(), params.getPassword());
if ((curstate & UserAdmin.MASK_EXPIRED) != 0) {
throw new JPlagException("setDeveloperState", "Access denied!",
"Your account has expired! Please contact the JPlag administrator to reactivate it!");
} else if ((curstate & UserAdmin.MASK_DEACTIVATED) != 0) {
throw new JPlagException("setDeveloperState", "Access denied!",
"Your account has been deactivated! Please contact the JPlag administrator to reactivate it!");
} else if (curstate == UserAdmin.USER_INVALID) {
throw new JPlagException("setDeveloperState", "Access denied!", "Wrong username or password!");
}
JPLAG_CENTRAL.getUserAdmin().setDeveloperState(params.getUsername(), params.isDeveloper());
return 0;
}
}