/* * Copyright (C) 2011 Marius Giepz * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.saiku.adhoc.rest; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Properties; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Response.Status; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.map.JsonMappingException; import org.pentaho.platform.engine.core.system.PentahoBase; import org.pentaho.reporting.libraries.formula.parser.ParseException; import org.saiku.adhoc.exceptions.SaikuAdhocException; import org.saiku.adhoc.exceptions.SaikuClientException; import org.saiku.adhoc.messages.Messages; import org.saiku.adhoc.model.dto.DisplayName; import org.saiku.adhoc.model.dto.ElementFormat; import org.saiku.adhoc.model.dto.FilterResult; import org.saiku.adhoc.model.dto.FilterValue; import org.saiku.adhoc.model.dto.HtmlReport; import org.saiku.adhoc.model.dto.Position; import org.saiku.adhoc.model.dto.PrptSolutionFileInfo; import org.saiku.adhoc.model.dto.SavedQuery; import org.saiku.adhoc.model.dto.SolutionFileInfo; import org.saiku.adhoc.model.master.SaikuColumn; import org.saiku.adhoc.model.master.SaikuReportSettings; import org.saiku.adhoc.model.metadata.impl.MetadataModelInfo; import org.saiku.adhoc.service.EditorService; import org.saiku.adhoc.service.cda.CdaQueryService; import org.saiku.adhoc.service.report.ReportGeneratorService; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Path("/saiku-adhoc/rest/query") @Scope("request") @XmlAccessorType(XmlAccessType.NONE) public class QueryResource extends PentahoBase { /** * */ private static final long serialVersionUID = 1L; private Log log = LogFactory.getLog(QueryResource.class); private CdaQueryService queryService; private EditorService editorService; private ReportGeneratorService reportGeneratorService; @GET @Produces({"application/json" }) @Path("/{queryname}/json") public SavedQuery getModelJson(@PathParam("queryname") String queryName){ if (log.isDebugEnabled()) { log.debug("REST:GET " + queryName + " saveQuery"); } if (log.isDebugEnabled()) { log.debug("REST:GET " + queryName + " saveQuery"); } try { String json = editorService.getModelJson(queryName); return new SavedQuery(queryName, null, json); } catch (JsonGenerationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonMappingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } @GET @Produces({ "application/json" }) @Path("/{queryname}/result") public String executeQuery(@PathParam("queryname") String sessionId) { String result; try{ result = queryService.runQuery(sessionId, sessionId); }catch (Exception e) { log.error("Cannot generate report (" + sessionId + ")",e); throw new SaikuClientException(e.getMessage()); } if(!result.equals("")){ return result; }else{ throw new SaikuClientException( Messages.getErrorString("CdaQueryService.ERROR_0001_QUERY_RETURNED_NO_DATA") ); } } @POST @Consumes({ "application/json" }) @Path("/{queryname}") public Status createQuery(MetadataModelInfo modelInfo, @PathParam("queryname") String sessionId) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " createQuery"); } try { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " createQuery"); } editorService.createNewModel(sessionId, modelInfo); return Status.OK; } catch (Exception e) { e.printStackTrace(); //log.error(e.getCause()); return Status.INTERNAL_SERVER_ERROR; } } @GET @Produces({"application/json" }) @Path("/{queryname}/properties") public Properties getProperties(@PathParam("queryname") String queryName) { if (log.isDebugEnabled()) { log.debug("REST:GET " + queryName + " getProperties"); } return queryService.getProperties(queryName); } @POST @Produces({"application/json" }) @Path("/{queryname}/properties") public Properties setProperties( @PathParam("queryname") String queryName, String properties) { if (log.isDebugEnabled()) { log.debug("REST:POST " + queryName + " setProperties\t" + properties); } try { Properties props = new Properties(); StringReader sr = new StringReader(properties); props.load(sr); return queryService.setProperties(queryName, props); } catch(Exception e) { log.error("Cannot set properties for query (" + queryName + ")",e); //return something return queryService.getProperties(queryName); } } @POST @Produces({"application/json" }) @Path("/{queryname}/properties/{propertyKey}") public Properties setProperties( @PathParam("queryname") String queryName, @PathParam("propertyKey") String propertyKey, @FormParam("propertyValue") String propertyValue) { if (log.isDebugEnabled()) { log.debug("REST:POST " + queryName + " setProperties "+ propertyKey + "=" + propertyValue); } try{ Properties props = new Properties(); props.put(propertyKey, propertyValue); return queryService.setProperties(queryName, props); }catch(Exception e){ log.error("Cannot set property (" + propertyKey + " ) for query (" + queryName + ")",e); return null; } } @GET @Produces({ "application/json" }) @Path("/{queryname}/FILTER/CATEGORY/{category}/COLUMN/{column}/result") public FilterResult getFilterValues( @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String column) throws SaikuAdhocException { if (log.isDebugEnabled()) { log.debug("REST:GET " + sessionId + " getFilterValues category="+ category + " column=" + column); } try { return queryService.getFilterResult(sessionId, category, column); } catch (Exception e) { final String message = e.getCause() != null ? e.getCause().getClass().getName() + " - " + e.getCause().getMessage() : e.getClass().getName() + " - " + e.getMessage(); log.error(message, e); throw new SaikuAdhocException("Encoding not supported", e); } } @GET @Produces({ "application/json" }) @Path("/{queryname}/report/{page}") public HtmlReport generateReport( @PathParam("queryname") String sessionId, //@PathParam("template") String template, @PathParam("page") String page){ if (log.isDebugEnabled()) { log.debug("REST:GET " + sessionId + " generate"); } try { HtmlReport report = new HtmlReport(); Integer acceptedPage = Integer.parseInt(page) - 1; reportGeneratorService.renderReportHtml(sessionId, null, report, acceptedPage); return report; }catch (Exception e) { log.error("Cannot generate report (" + sessionId + ")",e); throw new SaikuClientException(e.getMessage()); } } @GET @Produces({ "application/json" }) @Path("/{queryname}/ROWLIMIT/{rowlimit}") public Status setRowlimit( @PathParam("queryname") String sessionId, @PathParam("rowlimit") String rowlimit) { try { editorService.setRowlimit(sessionId, rowlimit); return Status.OK; } catch (Exception e) { log.error("Cannot set rowlimit", e); return Status.INTERNAL_SERVER_ERROR; } } @GET @Produces({ "application/json" }) @Path("/{queryname}/DISTINCT/{distinct}") public Status setDistinct( @PathParam("queryname") String sessionId, @PathParam("distinct") String distinct) { try { editorService.setDistinct(sessionId, Boolean.valueOf(distinct)); return Status.OK; } catch (Exception e) { log.error("Cannot set distinct", e); return Status.INTERNAL_SERVER_ERROR; } } @POST @Path("/{queryname}/COLUMNS/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}") public DisplayName addColumn( Position position, @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String businessColumn, @PathParam("position") Integer pos) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " addColumn uid=" + position.getUid() + " position=" + position.getPosition() + " category=" + category + " column=" + businessColumn); } try { return editorService.addColumn(sessionId, category, businessColumn, position); } catch (Exception e) { log.error("Cannot add column " + businessColumn + " to query (" + sessionId + ")", e); String error = ExceptionUtils.getRootCauseMessage(e); String clientMessage = Messages.getErrorString(error); throw new SaikuClientException(clientMessage); } } @DELETE @Path("/{queryname}/COLUMNS/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}") public Status removeColumn( @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String businessColumn, @PathParam("position") Integer position) { if (log.isDebugEnabled()) { log.debug("REST:DELETE " + sessionId + " removeColumn position=" + position + " category=" + category + " column=" + businessColumn); } try { editorService.removeColumn(sessionId, category, businessColumn, position); return Status.OK; } catch (Exception e) { log.error("Cannot remove column " + businessColumn + " from query (" + sessionId + ")", e); return Status.INTERNAL_SERVER_ERROR; } } @POST @Path("/{queryname}/FILTER/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}") public Status addFilter( Position position, @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String businessColumn) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " addFilter position=" + position + " category=" + category + " column=" + businessColumn); } try { editorService.addFilter(sessionId, category, businessColumn, position); return Status.OK; } catch (Exception e) { log.error("Cannot add Filter " + businessColumn + " to query (" + sessionId + ")", e); return Status.INTERNAL_SERVER_ERROR; } } @DELETE @Path("/{queryname}/FILTER/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}") public Status removeFilter( @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String businessColumn, @PathParam("position") Integer position) { if (log.isDebugEnabled()) { log.debug("REST:DELETE " + sessionId + " removeFilter position=" + position + " category=" + category + " column=" + businessColumn); } try { editorService.removeFilter(sessionId, category, businessColumn, position); return Status.OK; } catch (Exception e) { log.error("Cannot remove Filter " + businessColumn + " from query (" + sessionId + ")", e); return Status.INTERNAL_SERVER_ERROR; } } @POST @Consumes({ "application/json" }) @Path("/{queryname}/FILTER/CATEGORY/{category}/COLUMN/{column}/VALUES") public Status setFilterValues( ArrayList<FilterValue> selection, @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String businessColumn) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " setFilterValues " + "category=" + category + " column=" + businessColumn); } try { editorService.setFilterValues(sessionId, category, businessColumn, selection); return Status.OK; } catch (Exception e) { // log.error("Cannot remove column "+ businessColumn+ // " from query (" + queryName + ")",e); return Status.INTERNAL_SERVER_ERROR; } } @POST @Path("/{queryname}/GROUP/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}") public Status addGroup( Position position, @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String businessColumn, @PathParam("position") Integer pos) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " addGroup uid=" + position.getUid() + " position=" + position.getPosition() + " category=" + category + " column=" + businessColumn); } try { editorService.addGroup(sessionId, category, businessColumn, position); return Status.OK; } catch (Exception e) { log.error("Cannot add Group " + businessColumn + " to query (" + sessionId + ")", e); return Status.INTERNAL_SERVER_ERROR; } } @DELETE @Path("/{queryname}/GROUP/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}") public Status removeGroup( @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String businessColumn, @PathParam("position") Integer position) { if (log.isDebugEnabled()) { log.debug("REST:DELETE " + sessionId + " removeGroup position=" + position + " category=" + category + " column=" + businessColumn); } try { editorService.removeGroup(sessionId, category, businessColumn, position); return Status.OK; } catch (Exception e) { log.error("Cannot remove Group " + businessColumn + " from query (" + sessionId + ")", e); return Status.INTERNAL_SERVER_ERROR; } } @GET @Produces({ "application/json" }) @Path("/{queryname}/COLUMNS/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}/config") public SaikuColumn getColumnConfig( @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String column, @PathParam("position") Integer position) { if (log.isDebugEnabled()) { log.debug("REST:GET " + sessionId + " getColumnConfig position=" + position + " category=" + category + " column=" + column); } try { return editorService.getColumnConfig(sessionId, category, column, position); } catch (Exception e) { log.error("Cannot execute Query", e); } return null; } @POST @Consumes({ "application/json" }) @Path("/{queryname}/COLUMNS/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}/config") public DisplayName setColumnConfig(SaikuColumn config, @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String column, @PathParam("position") Integer position) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " setColumnConfig position=" + position + " category=" + category + " column=" + column); } try { return editorService.setColumnConfig(sessionId, category, column, position, config); }catch(ParseException e){ log.error("Formula is not valid", e); String error = Messages.getErrorString("ReportGeneratorService.ERROR_0007_INVALID_FORMULA"); throw new SaikuClientException(error); } catch (Exception e1) { log.error("Cannot config column", e1); String error = ExceptionUtils.getRootCauseMessage(e1); throw new SaikuClientException(error); } } @POST @Consumes({ "application/json" }) @Path("/{queryname}/COLUMNS/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}/SORT/{order}") public Status setColumnSort( @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String column, @PathParam("position") Integer position, @PathParam("order") String order) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " sort position=" + position + " category=" + category + " column=" + column); } try { editorService.setColumnSort(sessionId, category, column, position, order); return Status.OK; } catch (Exception e) { e.printStackTrace(); return Status.INTERNAL_SERVER_ERROR; } } @POST @Consumes({ "application/json" }) @Path("/{queryname}/GROUP/CATEGORY/{category}/COLUMN/{column}/POSITION/{position}/SORT/{order}") public Status setGroupSort( @PathParam("queryname") String sessionId, @PathParam("category") String category, @PathParam("column") String column, @PathParam("position") Integer position, @PathParam("order") String order) { if (log.isDebugEnabled()) { log.debug("REST:POST " + sessionId + " sort position=" + position + " category=" + category + " column=" + column); } try { editorService.setGroupSort(sessionId, category, column, position, order); return Status.OK; } catch (Exception e) { e.printStackTrace(); return Status.INTERNAL_SERVER_ERROR; } } @Override public Log getLogger() { return log; } public void setQueryService(CdaQueryService queryService) { this.queryService = queryService; } public void setEditorService(EditorService editorService) { this.editorService = editorService; } public void setReportGeneratorService( ReportGeneratorService reportGeneratorService) { this.reportGeneratorService = reportGeneratorService; } @GET @Produces({ "application/json" }) @Path("/{queryname}/SETTINGS") public SaikuReportSettings getReportSettings( @PathParam("queryname") String sessionId) { try { return editorService.getReportSettings(sessionId); } catch (Exception e) { log.error("Cannot get settings", e); String error = ExceptionUtils.getRootCauseMessage(e); throw new SaikuClientException(error); } } @POST @Consumes({ "application/json" }) @Path("/{queryname}/SETTINGS") public void setReportSettings( SaikuReportSettings settings, @PathParam("queryname") String sessionId) { try { editorService.setReportSettings(sessionId,settings); } catch (Exception e) { log.error("Cannot set settings", e); String error = ExceptionUtils.getRootCauseMessage(e); throw new SaikuClientException(error); } } @GET @Produces({ "application/json" }) @Path("/{queryname}/FORMAT/ELEMENT/{id}") public ElementFormat getElementFormat( @PathParam("queryname") String sessionId, @PathParam("id") String id) { try { //return editorService.getColumnConfig(sessionId,id); return editorService.getElementFormat(sessionId, id); } catch (Exception e) { log.error("Cannot execute Query", e); } return null; } @POST @Consumes({ "application/json" }) @Path("/{queryname}/FORMAT/ELEMENT/{id}") public DisplayName setElementFormat(ElementFormat format, @PathParam("queryname") String sessionId, @PathParam("id") String id) { try { return editorService.setElementFormat(sessionId, format, id); } catch (Exception e) { log.error("Cannot set element format", e); String error = ExceptionUtils.getRootCauseMessage(e); throw new SaikuClientException(error); } } @POST @Path("/{queryname}/EXPORT/PRPT") public void exportPrpt( PrptSolutionFileInfo file, @PathParam("queryname") String sessionId) { try { reportGeneratorService.savePrpt(sessionId, file.getPath(),file.getFile(), file.getUser(),file.getPassword()); } catch (Exception e) { log.error("Cannot export prpt (" + sessionId + ")",e); String clientMessage = Messages.getErrorString(e.getMessage()); throw new SaikuClientException(clientMessage); } } @POST @Path("/{queryname}/EXPORT/CDA") public Status exportCda( SolutionFileInfo file, @PathParam("queryname") String sessionId) { try { reportGeneratorService.saveCda(sessionId, file.getPath(),file.getFile()); return Status.OK; } catch (Exception e) { return Status.INTERNAL_SERVER_ERROR; } } }