package gr.ntua.ivml.mint.actions;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import gr.ntua.ivml.mint.db.DB;
import gr.ntua.ivml.mint.persistent.BlobWrap;
import gr.ntua.ivml.mint.persistent.DataUpload;
import gr.ntua.ivml.mint.persistent.Mapping;
import gr.ntua.ivml.mint.persistent.Organization;
import gr.ntua.ivml.mint.persistent.Thesaurus;
import gr.ntua.ivml.mint.persistent.ThesaurusAssignment;
import gr.ntua.ivml.mint.persistent.User;
import gr.ntua.ivml.mint.persistent.XpathHolder;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.hibernate.Hibernate;
import com.opensymphony.xwork2.ActionContext;
@Results( {
@Result(name = "input", location = "editor.jsp"),
@Result(name = "error", location = "error.jsp", type = "redirectAction"),
@Result(name = "success", location = "ajaxthesaurus.jsp") })
public class ThesaurusAction extends GeneralAction {
private static final int MAX_LABEL_LENGTH = 20;
protected final Logger log = Logger.getLogger(getClass());
private String result;
private String uploadId;
private String thesaurusId;
private String action;
private String xpath;
private String mappingId;
private String filename;
private String contentType;
//Used for storing/retrieving thesaurus
private String description;
private String title;
private String url;
private String contact;
private File uploadFile;
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String getXpath() {
return xpath;
}
public void setXpath(String xpath) {
log.info("*** Xpath from request set to : " + xpath);
this.xpath = xpath;
}
public String getThesaurusId() {
return thesaurusId;
}
public void setThesaurusId(String thesaurusId) {
this.thesaurusId = thesaurusId;
}
public String getMappingId() {
return mappingId;
}
public void setMappingId(String mappingId) {
this.mappingId = mappingId;
}
///////////////////////////////////////////////
public void setUploadFileContentType(String contentType) {
this.contentType = contentType;
}
public void setUploadFileFileName(String filename) {
this.filename = filename;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public File getUploadFile() {
return uploadFile;
}
public void setUploadFile(File uploadFile) {
this.uploadFile = uploadFile;
}
///////////////////////////////////////////////
@Action(value = "ThesaurusAjax")
public String execute() throws Exception {
log.info("********************");
log.info("Thesaurus action - " + action);
log.info("upload id: " + uploadId);
log.info("Xpath: " + xpath);
if (action.equalsIgnoreCase("STATS")) {
//Return statistics
handleStatsRequest();
} else if(action.equalsIgnoreCase("LIST")) {
//Return list of thesauri for specified tree
handleThesaurusList();
} else if(action.equalsIgnoreCase("LABELS")) {
//Return list of labels for specific tree and thesauri
handleLabelList();
} else if(action.equalsIgnoreCase("SAVE")) {
//Save thesaurus
saveThesaurus();
} else if(action.equalsIgnoreCase("EDIT")) {
//Edit thesaurus
editThesaurus();
} else if(action.equalsIgnoreCase("EDIT_FORM")) {
//Create edit form for thesaurus
thesaurusEditForm();
} else if(action.equalsIgnoreCase("ASSIGN")) {
//Assign thesaurus to node
createThesaurusAssignment();
} else if(action.equalsIgnoreCase("UNASSIGN")) {
//Delete assignment of thesaurus to node
deleteThesaurusAssignment();
} else if(action.equalsIgnoreCase("DELETE")) {
//Delete thesaurus
deleteThesaurus();
} else if(action.equalsIgnoreCase("APPLY_THESAURUS")) {
//Apply current thesaurus assignments to current mapping
applyThesaurusToMapping();
}
log.info("********************");
return "success";
}
private void deleteThesaurus() {
try {
result = "ERROR";
Thesaurus t = DB.getThesaurusDAO().findById(Long.valueOf(thesaurusId), false);
if((t != null) && (hasAccess(t.getOrganization()))) {
boolean r = DB.getThesaurusDAO().delete(Long.valueOf(thesaurusId));
if(r)
result = "OK";
}
} catch(Exception e) {
log.info("Error deleting thesaurus: " + e.getMessage());
result = "Error deleting thesaurus... <!--" + e.getMessage() + " -->";
}
}
private void deleteThesaurusAssignment() {
try {
result = "ERROR";
log.info("deleteThesaurusAssignment -> Mapping id: " + mappingId);
ThesaurusAssignment ta = DB.getThesaurusAssignmentDAO().findById(Long.valueOf(mappingId), false);
if((ta != null) && (hasAccess(ta.getUser().getOrganization()))) {
boolean r = DB.getThesaurusAssignmentDAO().delete(Long.valueOf(mappingId));
if(r)
result = "OK";
}
} catch(Exception e) {
log.info("Error deleting thesaurus assignment: " + e.getMessage());
result = "Error deleting thesaurus assignment... <!--" + e.getMessage() + " -->";
}
}
private void createThesaurusAssignment() {
try {
log.info("Creating new thesaurus assignment...");
log.info("\tThesaurus ID: " + thesaurusId);
log.info("\tData Upload ID: " + uploadId);
Thesaurus t = DB.getThesaurusDAO().findById(Long.valueOf(thesaurusId), false);
DataUpload d = DB.getDataUploadDAO().findById(Long.valueOf(uploadId), false);
persistThesaurusAssignment(t, d, findXpathHolder());
result = "Succesfully added!";
} catch(Exception e) {
log.info("Error assigning thesaurus: " + e.getMessage());
result = "Error assigning thesaurus... <!--" + e.getMessage() + " -->";
}
}
private void applyThesaurusToMapping() {
try {
int count = 0;
log.info("Applying mappings of thesarus with id " + thesaurusId + " to current mapping (" + uploadId + ")...");
Thesaurus t = DB.getThesaurusDAO().findById(Long.valueOf(thesaurusId), false);
DataUpload du = DB.getDataUploadDAO().findById(Long.valueOf(uploadId), false);
List l = DB.getThesaurusDAO().findDistinctXpathsByThesaurusId(t);
log.info("Detected total of " + l.size() + " already existing mappings");
if(l == null) {
log.info("Empty list of assignments - cannot apply...");
} else {
Iterator iter = l.iterator();
while(iter.hasNext()) {
//Attempt to find xpath
String xpath = (String) iter.next();
XpathHolder xpathHolder = findXpathHolder(xpath);
if((xpathHolder != null) && (!DB.getThesaurusAssignmentDAO().existsAssignment(xpathHolder, t, du))) {
//Xpath exists also in this tree, apply thesaurus
persistThesaurusAssignment(t, du, xpathHolder);
log.info("Applied thesaurus '" + t.getTitle() + "' to " + xpath);
count++;
}
}
}
result = "Applied thesaurus to " + count + " nodes";
log.info(result);
} catch(Exception e) {
log.info("Error applying thesaurus to current mapping: " + e.getMessage());
result = "Error";
}
}
private void saveThesaurus() {
try {
DataUpload du = DB.getDataUploadDAO().findById(Long.valueOf(uploadId), false);
Date now = new Date();
Thesaurus t = new Thesaurus();
t.setDescription(description);
t.setTitle(title);
t.setUploadDate(now);
t.setUrl(url);
t.setContactPerson(contact);
//find current user and set him as owner of this thesaurus
User u = getUser();
t.setOwner(u);
t.setOrganization(du.getOrganization());
if(uploadFile != null) {
log.info("Creating file: " + uploadFile.getName());
log.info("Original filename:" + filename);
FileInputStream fis = new FileInputStream( uploadFile );
BlobWrap data = new BlobWrap();
data.setData(Hibernate.createBlob(fis, (int) uploadFile.length()));
log.info("Created file: " + uploadFile.getName());
t.setFile(data);
t.setFilename(filename);
t.setContentType(contentType);
}
DB.getThesaurusDAO().makePersistent(t);
result = t.getDbID().toString();
if(uploadFile != null) {
log.info("BlobWrapper id:" + t.getFile().getDbID());
}
} catch(Exception e) {
result = "Error";
log.info("Error saving thesaurus: " + e.getMessage());
}
}
private void editThesaurus() {
try {
Date now = new Date();
Thesaurus t = DB.getThesaurusDAO().findById(Long.valueOf(thesaurusId), false);
boolean access = hasAccess(t.getOrganization());
if((t != null) && access) {
t.setDescription(description);
t.setTitle(title);
t.setUploadDate(now);
t.setUrl(url);
t.setContactPerson(contact);
DB.getThesaurusDAO().makePersistent(t);
result = t.getDbID().toString();
} else {
result = "Couldn't update thesaurus";
}
} catch(Exception e) {
result = "Error";
log.info("Error saving thesaurus: " + e.getMessage());
}
}
private void thesaurusEditForm() {
try {
Date now = new Date();
Thesaurus t = DB.getThesaurusDAO().findById(Long.valueOf(thesaurusId), false);
JSONObject object = new JSONObject();
object.put("thesaurusId", t.getDbID());
object.put("title", t.getTitle());
object.put("url", t.getUrl());
object.put("contact", t.getContactPerson());
object.put("description", t.getDescription());
result = object.toString();
log.info(result);
} catch(Exception e) {
result = "Error";
log.info("Error converting thesaurus to JSON: " + e.getMessage(), e);
}
}
private void handleLabelList() {
try {
StringBuffer out = new StringBuffer();
out.append("<ul id=\"active_labels\" class=\"labels\">\n");
Thesaurus thesaurus = DB.getThesaurusDAO().getById(Long.valueOf(thesaurusId), false);
DataUpload dataUpload = DB.getDataUploadDAO().getById(Long.valueOf(uploadId), false);
if((thesaurus != null) && (dataUpload != null)) {
List<ThesaurusAssignment> metadata = DB.getThesaurusAssignmentDAO().getByThesaurusAndDataUpload(thesaurus, dataUpload);
for( ThesaurusAssignment t: metadata) {
log.info(" *** Is thesaurus assign null? " + (t == null));
log.info(" *** Is thesaurus' xpath null? " + (t.getXpath() == null));
String label = t.getXpath().getXpath();
if(label.length() > MAX_LABEL_LENGTH )
label = label.substring(0, 8) + "..." + label.substring(label.length()- 8);
out.append("<li class=\"blue\"><span>" + label + "<span>" + t.getXpath().getXpath()+ "</span></span><a href=\"#\" onclick=\"javascript:deleteAssign(" + t.getDbID() + ")\"></a></li>\n");
}
}
out.append("</ul>\n");
result = out.toString();
} catch(Exception e) {
result = "<span class=\"error\">Error reading thesauri mappings</span>\n";
log.info("Error reading thesauri mappings: " + e.getMessage(), e);
}
}
private void handleThesaurusList() {
StringBuffer out = new StringBuffer();
out.append("<ul id=\"thesaurus_list\" class=\"thesaurus_list\">\n");
DataUpload du = DB.getDataUploadDAO().findById(Long.valueOf(uploadId), false);
List<Thesaurus> thesauri = DB.getThesaurusDAO().findByOrganizationAndDependants(du.getOrganization());
log.info("Returning thesauri list for organization " + du.getOrganization().getName());
int rowCount = 1;
for( Thesaurus t: thesauri) {
out.append("<li class=\"thesurus_row" + rowCount + "\" onclick=\"javascript:selectThesaurus(" + t.getDbID() + ", '" + t.getTitle() + "');\">" + t.getTitle() + " - " + t.getOrganization().getName() + "</li>\n");
rowCount = (rowCount % 2) + 1;
}
out.append("</ul>\n");
result = out.toString();
}
private void handleStatsRequest() {
try {
XpathHolder node = findXpathHolder();
XpathHolder childNode = node.getChild("text()");
if(childNode == null) {
result = "No statistics for selected node...";
} else {
this.result = generateStatsForXpathHolder(childNode);
}
} catch (Exception e) {
log.info("Error: " + e.getMessage());
result = "Error retrieving stats...";
}
}
//Utility methods
private String generateStatsForXpathHolder(XpathHolder xp) {
StringBuffer out = new StringBuffer();
DB.getXMLNodeDAO().getStatsForXpaths(xp.getXmlObject());
List<Object[]> elements = xp.getCountByValue(30);
out.append("<table class=\"stats-table\">");
out.append("<tr><th>Value</th><th>Frequency</th></tr>");
for (Object[] oa : elements) {
String value = (String) oa[0];
Long valueCount = (Long) oa[1];
out.append("<tr>");
out.append("<td> " + value + "</td>");
out.append("<td> " + valueCount + "</td>");
out.append("</tr>");
}
out.append("</table>");
return out.toString();
}
private XpathHolder findXpathHolder() {
DataUpload du = DB.getDataUploadDAO().findById(Long.parseLong(uploadId), false);
XpathHolder xp = du.getXmlObject().getRoot().getByRelativePathWithPrefix(xpath,true);
if(xp != null) {
log.info(" +++ Xpath Holder found!!!");
} else {
log.info(" +++ Didn't find xpath holder for " + xpath);
}
return xp;
}
private void persistThesaurusAssignment(Thesaurus t, DataUpload du, XpathHolder xph) throws Exception {
if(hasAccess(du.getOrganization()) && hasAccess(t.getOrganization())) {
ThesaurusAssignment ta = new ThesaurusAssignment();
ta.setAssignDate(new Date());
ta.setThesaurus(t);
XpathHolder node = xph;
ta.setXpath(node);
ta.setDataUpload(du);
User u = getUser();
ta.setUser(u);
DB.getThesaurusAssignmentDAO().makePersistent(ta);
} else {
throw new IllegalAccessError("User doesn't have access to this thesaurus or mapping");
}
}
private XpathHolder findXpathHolder(String xpath) {
DataUpload du = DB.getDataUploadDAO().findById(Long.parseLong(uploadId), false);
XpathHolder xp = du.getXmlObject().getRoot().getByRelativePathWithPrefix(xpath,true);
if(xp != null) {
log.info(" +++ Xpath Holder found!!!");
} else {
log.info(" +++ Didn't find xpath holder for " + xpath);
}
return xp;
}
/**
* Checks if current user belongs to the same organization hierarchy as o
*
* @param o
* @return
*/
private boolean hasAccess(Organization o) {
User u = getUser();
return u.getAccessibleOrganizations().contains(o);
}
}