package ro.nextreports.server.service;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import org.apache.wicket.model.StringResourceModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import ro.nextreports.server.StorageConstants;
import ro.nextreports.server.domain.Analysis;
import ro.nextreports.server.domain.Entity;
import ro.nextreports.server.domain.Folder;
import ro.nextreports.server.domain.Link;
import ro.nextreports.server.domain.ReportResultEvent;
import ro.nextreports.server.etl.OrientDbUtils;
import ro.nextreports.server.exception.DuplicationException;
import ro.nextreports.server.exception.NotFoundException;
import ro.nextreports.server.util.AnalysisUtil;
import ro.nextreports.server.util.PermissionUtil;
import ro.nextreports.server.util.ServerUtil;
import ro.nextreports.server.web.security.SecurityUtil;
public class DefaultAnalysisService implements AnalysisService {
private static final Logger LOG = LoggerFactory.getLogger(DefaultAnalysisService.class);
private StorageService storageService;
private SecurityService securityService;
private ReportService reportService;
@Required
public void setStorageService(StorageService storageService) {
this.storageService = storageService;
}
@Required
public void setSecurityService(SecurityService securityService) {
this.securityService = securityService;
}
@Required
public void setReportService(ReportService reportService) {
this.reportService = reportService;
}
private String getUsername() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
private String getMyAnalysisPath() {
return getMyAnalysisPath(getUsername());
}
private String getMyAnalysisPath(String creator) {
return StorageConstants.ANALYSIS_ROOT + "/" + creator;
}
@Transactional(readOnly=true)
public String getAnalysisPath(Analysis analysis, String creator) {
String id = analysis.getId();
if (id == null) {
return getMyAnalysisPath(creator) + "/" + analysis.getName();
}
try {
return storageService.getEntityPath(id);
} catch (NotFoundException e) {
// never happening
throw new RuntimeException(e);
}
}
@Transactional
public List<Analysis> getMyAnalysis() {
Entity[] entities;
try {
checkAnalysisPath();
entities = storageService.getEntitiesByClassName(getMyAnalysisPath(), Analysis.class.getName());
System.out.println("***** myAnalysis path = " +getMyAnalysisPath());
return getAnalysis(entities);
} catch (NotFoundException e) {
// never happening
throw new RuntimeException(e);
}
}
@Transactional
public List<Analysis> getAnalysisByTable(String tableName) {
Entity[] entities;
try {
checkAnalysisPath();
entities = storageService.getEntitiesByClassName(StorageConstants.ANALYSIS_ROOT, Analysis.class.getName());
return getAnalysis(entities, tableName);
} catch (NotFoundException e) {
// never happening
throw new RuntimeException(e);
}
}
public List<Link> getAnalysisLinks() {
return getAnalysisLinks(PermissionUtil.getRead(), ServerUtil.getUsername());
}
public List<Link> getAnalysisLinks(String user) {
return getAnalysisLinks(PermissionUtil.getRead(), user);
}
public List<Link> getWritableAnalysisLinks() {
return getAnalysisLinks(PermissionUtil.getWrite(), ServerUtil.getUsername());
}
private List<Link> getAnalysisLinks(int permission, String user) {
// TODO improve filtering
Entity[] entities;
try {
entities = storageService.getEntitiesByClassName(StorageConstants.ANALYSIS_ROOT, Analysis.class.getName());
} catch (NotFoundException e) {
// never happening
throw new RuntimeException(e);
}
List<Entity> tmp = new ArrayList<Entity>();
String analysisPath = StorageConstants.ANALYSIS_ROOT + "/" + user;
for (Entity entity : entities) {
if (!entity.getPath().startsWith(analysisPath)) {
tmp.add(entity);
}
}
entities = new Entity[tmp.size()];
entities = tmp.toArray(entities);
List<Link> links = new ArrayList<Link>();
for (Entity entity : entities) {
try {
boolean hasRead = securityService.hasPermissionsById(user, permission, entity.getId());
if (hasRead) {
Link link = new Link(entity.getName(), entity.getPath());
link.setReference(entity.getId());
links.add(link);
}
} catch (NotFoundException e) {
// never happening
throw new RuntimeException(e);
}
}
Collections.sort(links, new Comparator<Link>() {
@Override
public int compare(Link o1, Link o2) {
return Collator.getInstance().compare(o1.getName(), o2.getName());
}
});
return links;
}
@Transactional
public String addAnalysis(Analysis analysis) {
try {
return storageService.addEntity(analysis);
} catch (DuplicationException e) {
// never happening
throw new RuntimeException(e);
}
}
@Transactional
public boolean checkAnalysisPath() {
String analysisPath = getMyAnalysisPath();
String username = getUsername();
if (!storageService.entityExists(analysisPath)) {
Folder analysisFolder = new Folder(username, analysisPath);
try {
storageService.addEntity(analysisFolder);
} catch (DuplicationException e) {
// never happening
throw new RuntimeException(e);
}
LOG.info("Created 'analysis' repository for user '" + username + "'");
return false;
}
return true;
}
private List<Analysis> getAnalysis(Entity[] entities) {
return getAnalysis(entities, null);
}
private List<Analysis> getAnalysis(Entity[] entities, String tableName) {
List<Analysis> analysis = new ArrayList<Analysis>();
for (Entity entity : entities) {
Analysis a = (Analysis)entity;
if (tableName != null) {
if (a.getTableName().equals(tableName)) {
analysis.add(a);
}
} else {
analysis.add(a);
}
}
Collections.sort(analysis, new Comparator<Analysis>() {
public int compare(Analysis o1, Analysis o2) {
return Collator.getInstance().compare(o1.getName(), o2.getName());
}
});
return analysis;
}
@Transactional
public void removeAnalysis(String analysisId) throws NotFoundException {
Analysis a = (Analysis)storageService.getEntityById(analysisId);
List<Analysis> list = getAnalysisByTable(a.getTableName());
int no = list.size();
storageService.removeEntityById(analysisId);
LOG.debug("**** For table " + a.getTableName() +" there are " + no + " analysis");
if (no == 1) {
//last analysis deleted, delete also the table
ODatabaseDocumentTx db = null;
try {
LOG.debug("**** Delete table : " + a.getTableName());
String prefix = SecurityUtil.getLoggedUsername() + "-";
db = new ODatabaseDocumentTx(getDatabasePath(), false).open("admin", "admin");
OrientDbUtils.dropClass(db, a.getTableName());
} catch (Throwable t) {
LOG.error(t.getMessage(), t);
} finally {
if (db != null) {
db.close();
}
}
}
}
@Transactional
public void modifyAnalysis(Analysis analysis) {
storageService.modifyEntity(analysis);
}
public String getDatabasePath() {
return "plocal:" + System.getProperty("nextserver.home") + "/analytics-data";
}
@Transactional
public void freeze(final Analysis analysis) {
final String message = new StringResourceModel("Analysis.freezed", null, new Object[] {analysis.getName()}).getString();
final ReportService service = reportService;
Runnable r = new Runnable() {
@Override
public void run() {
ODatabaseDocumentTx db = null;
ReportResultEvent event = null;
String freezeClassName;
try {
db = new ODatabaseDocumentTx(getDatabasePath(), false).open("admin", "admin");
freezeClassName = analysis.getTableName() + AnalysisUtil.FREEZE_MARKUP + UUID.randomUUID();
OrientDbUtils.duplicateClass(db, analysis.getTableName(), freezeClassName);
analysis.setFreezed(true);
analysis.setTableName(freezeClassName);
modifyAnalysis(analysis);
event = new ReportResultEvent(analysis.getCreatedBy(), analysis.getName(), AnalysisUtil.FREEZE_ACTION,
message);
} catch (Throwable t) {
// critical case
t.printStackTrace();
LOG.error(t.getMessage(), t);
// freezed unsuccessfull
analysis.setFreezed(false);
modifyAnalysis(analysis);
event = new ReportResultEvent(analysis.getCreatedBy(), analysis.getName(), AnalysisUtil.FREEZE_ACTION,
AnalysisUtil.FREEZE_FAILED + t.getMessage());
} finally {
if (db != null) {
db.close();
db = null;
}
}
service.notifyReportListener(event);
}
};
new Thread(r).start();
}
}