0001: /**********************************************************************************
0002: * $URL:https://source.sakaiproject.org/svn/osp/trunk/reports/api-impl/src/java/org/theospi/portfolio/reports/model/impl/ReportsManagerImpl.java $
0003: * $Id:ReportsManagerImpl.java 9134 2006-05-08 20:28:42Z chmaurer@iupui.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.theospi.portfolio.reports.model.impl;
0021:
0022: import org.apache.commons.codec.digest.DigestUtils;
0023: import org.hibernate.HibernateException;
0024: import org.jdom.CDATA;
0025: import org.jdom.Document;
0026: import org.jdom.Element;
0027: import org.jdom.input.SAXBuilder;
0028: import org.jdom.output.XMLOutputter;
0029: import org.jdom.transform.JDOMResult;
0030: import org.jdom.transform.JDOMSource;
0031: import org.quartz.*;
0032: import org.sakaiproject.api.app.scheduler.JobBeanWrapper;
0033: import org.sakaiproject.api.app.scheduler.SchedulerManager;
0034: import org.sakaiproject.authz.api.SecurityService;
0035: import org.sakaiproject.authz.cover.FunctionManager;
0036: import org.sakaiproject.component.app.scheduler.jobs.SpringJobBeanWrapper;
0037: import org.sakaiproject.component.cover.ComponentManager;
0038: import org.sakaiproject.component.cover.ServerConfigurationService;
0039: import org.sakaiproject.content.api.ContentCollection;
0040: import org.sakaiproject.content.api.ContentCollectionEdit;
0041: import org.sakaiproject.content.api.ContentHostingService;
0042: import org.sakaiproject.content.api.ContentResource;
0043: import org.sakaiproject.entity.api.ResourceProperties;
0044: import org.sakaiproject.entity.api.ResourcePropertiesEdit;
0045: import org.sakaiproject.event.cover.NotificationService;
0046: import org.sakaiproject.exception.*;
0047: import org.sakaiproject.metaobj.security.AuthenticationManager;
0048: import org.sakaiproject.metaobj.security.AuthorizationFacade;
0049: import org.sakaiproject.metaobj.security.AuthorizationFailedException;
0050: import org.sakaiproject.metaobj.security.model.AuthZMap;
0051: import org.sakaiproject.metaobj.shared.mgt.IdManager;
0052: import org.sakaiproject.metaobj.shared.model.Agent;
0053: import org.sakaiproject.metaobj.shared.model.Id;
0054: import org.sakaiproject.metaobj.shared.model.IdImpl;
0055: import org.sakaiproject.metaobj.shared.model.MimeType;
0056: import org.sakaiproject.metaobj.worksite.mgt.WorksiteManager;
0057: import org.sakaiproject.site.api.Site;
0058: import org.sakaiproject.site.cover.SiteService;
0059: import org.sakaiproject.tool.api.Session;
0060: import org.sakaiproject.tool.api.ToolSession;
0061: import org.sakaiproject.tool.cover.SessionManager;
0062: import org.sakaiproject.tool.cover.ToolManager;
0063: import org.sakaiproject.user.api.User;
0064: import org.sakaiproject.user.api.UserDirectoryService;
0065: import org.springframework.beans.BeansException;
0066: import org.springframework.beans.factory.BeanFactory;
0067: import org.springframework.beans.factory.BeanFactoryAware;
0068: import org.springframework.beans.factory.ListableBeanFactory;
0069: import org.springframework.beans.factory.xml.XmlBeanFactory;
0070: import org.springframework.core.io.InputStreamResource;
0071: import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
0072: import org.theospi.portfolio.reports.model.*;
0073: import org.theospi.portfolio.security.Authorization;
0074: import org.theospi.portfolio.security.impl.AllowAllSecurityAdvisor;
0075: import org.theospi.portfolio.shared.model.OspException;
0076:
0077: import javax.faces.context.FacesContext;
0078: import javax.servlet.http.HttpServletResponse;
0079: import javax.sql.DataSource;
0080: import javax.xml.transform.Transformer;
0081: import javax.xml.transform.TransformerFactory;
0082: import javax.xml.transform.stream.StreamResult;
0083: import javax.xml.transform.stream.StreamSource;
0084: import java.io.*;
0085: import java.sql.Connection;
0086: import java.sql.PreparedStatement;
0087: import java.sql.ResultSet;
0088: import java.sql.SQLException;
0089: import java.text.ParseException;
0090: import java.text.SimpleDateFormat;
0091: import java.util.*;
0092:
0093: /**
0094: * This class is a singleton that manages the reports on a general basis
0095: * <p/>
0096: * <p/>
0097: * When getting the reports a user can run this class checks the
0098: * "osp.reports.useWarehouse" sakai.properties property. 0 is no reports. 1 is
0099: * the warehouse reports. 2 is live data reports. and 3 is both warehouse and
0100: * live data reports. The default is 1. The default report has a setting of
0101: * operating on the warehouse.
0102: * <p/>
0103: * The dataSource is for the data warehouse data source. If it is set then that
0104: * source is used. If it is not set then the code tries to load in the data warehouse
0105: * dataSource. It does this because that is the default dw dataSource. The
0106: * data warehouse is not deployed then the dw dataSource won't exist. If it is referenced
0107: * in the components.xml then there would be errors at startup. Thus we don't reference
0108: * it there and programmatically pull it. This way it could be null (when dw is not
0109: * deployed) and then the dataSource falls back to the sakai dataSource.
0110: * <p/>
0111: * the sakai.properties property "osp.reports.forceColumnLabelUppercase" is used to standardize
0112: * the column label. MySQL will keep the column titles exactly as specified in the query.
0113: * Oracle on the other hand seems to make all the column labels uppercase. This makes writing
0114: * a query and an xsl that works in both databases more difficult. This defaults to 1 (otherwise know as true)
0115: * Set this property to 0 and the column titles will pass through like the old behavior
0116: *
0117: * @author andersjb
0118: */
0119: public class ReportsManagerImpl extends HibernateDaoSupport implements
0120: ReportsManager, BeanFactoryAware {
0121: /**
0122: * Enebles logging
0123: */
0124:
0125: private AuthenticationManager authnManager;
0126: /**
0127: * The global list of reports
0128: */
0129: private List reportDefinitions;
0130:
0131: /**
0132: * Class for converting a Id string to an Id class
0133: */
0134: private IdManager idManager = null;
0135:
0136: /**
0137: * the sakai class that manages permissions
0138: */
0139: private AuthorizationFacade authzManager;
0140:
0141: /**
0142: * The class that generates the database connection. it is the data warehouse data source
0143: */
0144: private DataSource dataSource = null;
0145:
0146: /**
0147: * The class that generates the database connection. it is the sakai data source
0148: */
0149: private DataSource sakaiDataSource = null;
0150:
0151: /**
0152: * an internal variable for whether or not the database connection should be closed after its use
0153: */
0154: private boolean canCloseConnection = true;
0155:
0156: /**
0157: * used to hash a reference so the hash isn't straight from the reference
0158: */
0159: private String secretKey = "ospReports";
0160:
0161: /**
0162: * used to allow artifacts to be downloaded (through adding an advisor)
0163: */
0164: private SecurityService securityService;
0165:
0166: private JobBeanWrapper jobBeanWrapper = null;
0167: /**
0168: * This is used to standardize the case of the column labels. This is helpful because
0169: * MySQL uses the same case as determined by the query. Oracle makes them all uppercase.
0170: * This makes it easier to write the xsl in a database agnostic way
0171: */
0172: private Boolean forceColumnLabelUppercase;
0173:
0174: private SchedulerManager schedulerManager;
0175: private org.theospi.portfolio.security.AuthorizationFacade ospAuthzManager;
0176:
0177: private boolean autoDdl = true;
0178:
0179: protected BeanFactory beanFactory;
0180:
0181: public void setBeanFactory(BeanFactory beanFactory)
0182: throws BeansException {
0183: this .beanFactory = beanFactory;
0184: }
0185:
0186: /**
0187: * convert between the user formatted date and the database formatted date
0188: */
0189: private static SimpleDateFormat userDateFormat = new SimpleDateFormat(
0190: "MM/dd/yyyy");
0191: private static SimpleDateFormat dbDateFormat = new SimpleDateFormat(
0192: "yyyy-MM-dd");
0193:
0194: /**
0195: * Tells us if the global database reportDefinitions was loaded
0196: */
0197: private ContentHostingService contentHosting;
0198:
0199: public List definedDefintions;
0200: /**
0201: * the name of key in the session into which the result is saved into
0202: */
0203: private static final String CURRENT_RESULTS_TAG = "org.theospi.portfolio.reports.model.ReportsManager.currentResults";
0204:
0205: /**
0206: * Called on after the startup of the singleton. This sets the global
0207: * list of functions which will have permission managed by sakai
0208: *
0209: * @throws Exception
0210: */
0211: protected void init() throws Exception {
0212: logger.info("init() ReportsManagerImpl");
0213: // register functions
0214: FunctionManager
0215: .registerFunction(ReportFunctions.REPORT_FUNCTION_CREATE);
0216: FunctionManager
0217: .registerFunction(ReportFunctions.REPORT_FUNCTION_RUN);
0218: FunctionManager
0219: .registerFunction(ReportFunctions.REPORT_FUNCTION_VIEW);
0220: FunctionManager
0221: .registerFunction(ReportFunctions.REPORT_FUNCTION_EDIT);
0222: FunctionManager
0223: .registerFunction(ReportFunctions.REPORT_FUNCTION_DELETE);
0224: FunctionManager
0225: .registerFunction(ReportFunctions.REPORT_FUNCTION_SHARE);
0226:
0227: if (isAutoDdl()) {
0228: initDefinedReportDefinitions();
0229: }
0230: }
0231:
0232: public AuthenticationManager getAuthnManager() {
0233: return authnManager;
0234: }
0235:
0236: public void setAuthnManager(AuthenticationManager authnManager) {
0237: this .authnManager = authnManager;
0238: }
0239:
0240: public BeanFactory getBeanFactory() {
0241: return beanFactory;
0242: }
0243:
0244: public void setParentBeanFactory(BeanFactory beanFactory) {
0245: this .beanFactory = beanFactory;
0246: }
0247:
0248: public org.theospi.portfolio.security.AuthorizationFacade getOspAuthzManager() {
0249: return ospAuthzManager;
0250: }
0251:
0252: public void setOspAuthzManager(
0253: org.theospi.portfolio.security.AuthorizationFacade ospAuthzManager) {
0254: this .ospAuthzManager = ospAuthzManager;
0255: }
0256:
0257: /**
0258: * {@inheritDoc}
0259: */
0260: public void setReportDefinitions(List reportDefinitions) {
0261: List reportDefs = new ArrayList();
0262: Iterator iter = reportDefinitions.iterator();
0263: while (iter.hasNext()) {
0264: ReportDefinition rd = (ReportDefinition) iter.next();
0265: rd.finishLoading();
0266: reportDefs.add(rd);
0267: }
0268: this .reportDefinitions = reportDefs;
0269: }
0270:
0271: public List getReportDefinitions() {
0272:
0273: //load any reportDefinitions in the database
0274: List reportsDefs = loadReportsFromDB();
0275: setReportDefinitions(reportsDefs);
0276: return this .reportDefinitions;
0277: }
0278:
0279: public boolean isValidRole(String roleStr) {
0280: if (roleStr != null && roleStr.length() > 0) {
0281: String currentRole = getCurrentSite().getMember(
0282: SessionManager.getCurrentSessionUserId()).getRole()
0283: .getId().toString();
0284: String[] roles = roleStr.split(",");
0285: for (int i = 0; i < roles.length; i++) {
0286: String role = roles[i];
0287: if (role.trim().equals(currentRole)) {
0288: return true;
0289: }
0290: }
0291: } else {
0292: return true;
0293: }
0294: return false;
0295:
0296: }
0297:
0298: public boolean isValidWorksiteType(String typesStr) {
0299: if (typesStr != null && typesStr.length() > 0) {
0300: String[] types = typesStr.split(",");
0301: for (int i = 0; i < types.length; i++) {
0302: String type = types[i];
0303: if (type.trim().equals(getCurrentSiteType())) {
0304: return true;
0305: }
0306: }
0307: } else {
0308: return true;
0309: }
0310: return false;
0311:
0312: }
0313:
0314: /**
0315: * Given the param of whether or not the report is using the warehouse, should it be displayed is returned.
0316: * This works off the "osp.reports.useWarehouse" sakai.properties property. If there is no property
0317: * then we will only show the warehouse reports.
0318: * <p/>
0319: * If the input is null, then we automatically assume that it is using the warehouse (set to true).
0320: * <p/>
0321: * If the property is 0 then we don't show any report. If bit 0 of the property is set then show
0322: * the data warehouse reports. If bit 1 of the property is set then show the direct reports. aka.
0323: * 0=no reports, 1= warehouse reports, 2= live data reports, 3= warehouse and live data reports
0324: *
0325: * @param usesWarehouse
0326: * @return
0327: */
0328: protected boolean hasWarehouseSetting(Boolean usesWarehouse) {
0329: int warehousePref = ServerConfigurationService.getInt(
0330: "osp.reports.useWarehouse", 1);
0331:
0332: if (warehousePref == 0) {
0333: return false;
0334: }
0335:
0336: if (usesWarehouse == null) {
0337: usesWarehouse = Boolean.TRUE;
0338: }
0339:
0340: // if bit 0 is set, show warehouse reports
0341: if ((warehousePref & 1) != 0
0342: && usesWarehouse.booleanValue() == true) {
0343: return true;
0344: }
0345:
0346: if ((warehousePref & 2) != 0
0347: && usesWarehouse.booleanValue() == false) {
0348: return true;
0349: }
0350:
0351: return false;
0352: }
0353:
0354: /**
0355: * This is the setter for the idManager
0356: */
0357: public void setIdManager(IdManager idManager) {
0358: this .idManager = idManager;
0359: }
0360:
0361: /**
0362: * This is the getter for the idManager
0363: *
0364: * @return IdManager
0365: */
0366: public IdManager getIdManager() {
0367: return idManager;
0368: }
0369:
0370: /**
0371: * This is the setter for the idManager
0372: */
0373: public void setDataSource(DataSource dataSource) {
0374: this .dataSource = dataSource;
0375: }
0376:
0377: /**
0378: * {@inheritDoc}
0379: */
0380: public DataSource getDataSource() {
0381: configureDataSource();
0382:
0383: int warehousePref = ServerConfigurationService.getInt(
0384: "osp.reports.useWarehouse", 1);
0385:
0386: if (warehousePref == 1) {
0387: return dataSource;
0388: } else if (warehousePref == 2) {
0389: return sakaiDataSource;
0390: }
0391:
0392: throw new RuntimeException(
0393: "Tried to get the report data source but the source was ambiguous.");
0394: }
0395:
0396: /**
0397: * {@inheritDoc}
0398: */
0399: public DataSource getDataSourceUseWarehouse(boolean useWarehouse) {
0400: configureDataSource();
0401:
0402: if (useWarehouse) {
0403: return dataSource;
0404: } else {
0405: return sakaiDataSource;
0406: }
0407: }
0408:
0409: /**
0410: * This function sets up the data warehouse data source. If the dataSource exists then nothing changes.
0411: * Thus if the dataSource is set in the components.xml then it will use that for the data warehouse
0412: * data source. Also if the dataSource has already been set up then this is skipped.
0413: * <p/>
0414: * So, if there is no dataSource set in the components.xml then we will default to the data warehouse
0415: * defined data source. This is needed because the data warehouse may not be loaded and thus the dataSource
0416: * bean wouldn't be defined. If we reference the dw dataSource when it doesn't exist then problems can
0417: * happen during startup. Thus we load the dw dataSource dynamically. If the dw dataSource doesn't
0418: * exist then we skip to the sakai dataSource.
0419: */
0420: private void configureDataSource() {
0421: if (dataSource == null) {
0422: dataSource = (DataSource) ComponentManager
0423: .get("org.theospi.portfolio.warehouse.intf.DataWarehouseManager.dataSource");
0424: if (dataSource == null) {
0425: dataSource = sakaiDataSource;
0426: }
0427: }
0428: }
0429:
0430: /**
0431: * {@inheritDoc}
0432: */
0433: public List getCurrentUserResults() {
0434: Session s = SessionManager.getCurrentSession();
0435:
0436: boolean runReports = can(ReportFunctions.REPORT_FUNCTION_RUN);
0437: boolean viewReports = can(ReportFunctions.REPORT_FUNCTION_VIEW);
0438:
0439: List returned = new ArrayList();
0440:
0441: if (viewReports | runReports) {
0442: List results = getHibernateTemplate().findByNamedQuery(
0443: "findResultsByUser", s.getUserId());
0444:
0445: Iterator iter = results.iterator();
0446: while (iter.hasNext()) {
0447: ReportResult r = (ReportResult) iter.next();
0448:
0449: r.setIsSaved(true);
0450: r.setOwner(true);
0451: }
0452: returned.addAll(results);
0453: }
0454:
0455: if (runReports) {
0456: List liveReports = getHibernateTemplate().findByNamedQuery(
0457: "findReportsByUser", s.getUserId());
0458:
0459: Iterator iter = liveReports.iterator();
0460: while (iter.hasNext()) {
0461: Report r = (Report) iter.next();
0462:
0463: r.getReportParams().size();
0464:
0465: r.connectToDefinition(getReportDefinitions());
0466: r.setIsSaved(true);
0467: }
0468:
0469: returned.addAll(liveReports);
0470: }
0471:
0472: return returned;
0473: }
0474:
0475: /**
0476: * Loads the global database reportDefinitions if they haven't been loaded yet
0477: * This is a stub.
0478: */
0479: private List loadReportsFromDB() {
0480: List reportDefArray = new ArrayList();
0481: List reportDefs = getHibernateTemplate().findByNamedQuery(
0482: "findReportDefinitionFiles");
0483:
0484: for (Iterator i = reportDefs.iterator(); i.hasNext();) {
0485: ReportDefinitionXmlFile xmlFile = (ReportDefinitionXmlFile) i
0486: .next();
0487:
0488: ListableBeanFactory beanFactory = new XmlBeanFactory(
0489: new InputStreamResource(new ByteArrayInputStream(
0490: xmlFile.getXmlFile())), getBeanFactory());
0491: ReportDefinition repDef = getReportDefBean(beanFactory);
0492: repDef.finishLoading();
0493: repDef.setDbLoaded(true);
0494: if (isValidWorksiteType(repDef.getSiteType())
0495: && isValidRole(repDef.getRole())
0496: && hasWarehouseSetting(repDef.getUsesWarehouse())) {
0497: reportDefArray.add(repDef);
0498: }
0499: }
0500: return reportDefArray;
0501:
0502: }
0503:
0504: /**
0505: * {@inheritDoc}
0506: */
0507: public ReportResult loadResult(ReportResult result) {
0508: ReportResult reportResult = (ReportResult) getHibernateTemplate()
0509: .get(ReportResult.class, result.getResultId());
0510:
0511: //load the report too
0512: Report report = reportResult.getReport();
0513:
0514: String function = report.getIsLive() ? ReportFunctions.REPORT_FUNCTION_RUN
0515: : ReportFunctions.REPORT_FUNCTION_VIEW;
0516:
0517: getAuthzManager().checkPermission(
0518: function,
0519: getIdManager().getId(
0520: ToolManager.getCurrentPlacement().getId()));
0521:
0522: //set the report and report result to that of already been saved
0523: reportResult.setIsSaved(true);
0524: report.setIsSaved(true);
0525:
0526: //link the report deinition
0527: report.connectToDefinition(getReportDefinitions());
0528:
0529: reportResult.setReport(report);
0530:
0531: //give back the result
0532: return reportResult;
0533: }
0534:
0535: /**
0536: * {@inheritDoc}
0537: */
0538: public String getReportResultKey(ReportResult result, String ref) {
0539: String hashCode = DigestUtils.md5Hex(ref + getSecretKey());
0540:
0541: return hashCode;
0542: }
0543:
0544: /**
0545: * {@inheritDoc}
0546: */
0547: public void checkReportAccess(String id, String ref) {
0548: String hashCode = DigestUtils.md5Hex(ref + getSecretKey());
0549:
0550: if (!hashCode.equals(id)) {
0551: throw new AuthorizationFailedException();
0552: }
0553:
0554: getSecurityService().pushAdvisor(new AllowAllSecurityAdvisor());
0555: }
0556:
0557: public void setCurrentResult(ReportResult result) {
0558: ToolSession session = SessionManager.getCurrentToolSession();
0559: session.setAttribute(CURRENT_RESULTS_TAG, result);
0560: }
0561:
0562: /**
0563: * Pulls the ReportResults out of the session
0564: *
0565: * @return ReportResult
0566: */
0567: public ReportResult getCurrentResult() {
0568: ToolSession session = SessionManager.getCurrentToolSession();
0569: return (ReportResult) session.getAttribute(CURRENT_RESULTS_TAG);
0570: }
0571:
0572: /**
0573: * Given an id, this method finds and returns the ReportDefinition
0574: *
0575: * @param Id
0576: * @return ReportDefinition
0577: */
0578: public ReportDefinition findReportDefinition(String Id) {
0579: Iterator iter = getReportDefinitions().iterator();
0580:
0581: while (iter.hasNext()) {
0582: ReportDefinition rd = (ReportDefinition) iter.next();
0583: if (rd.getIdString().equals(Id)) {
0584: return rd;
0585: }
0586: }
0587: return null;
0588: }
0589:
0590: // *************************************************************************
0591: // *************************************************************************
0592: // The process functions (non-getter/setter)
0593:
0594: /**
0595: * {@inheritDoc}
0596: */
0597: public void createReportParameters(Report report) {
0598: List reportDefParams = report.getReportDefinition()
0599: .getReportDefinitionParams();
0600: ArrayList reportParams = new ArrayList(reportDefParams.size());
0601:
0602: Iterator iter = reportDefParams.iterator();
0603:
0604: while (iter.hasNext()) {
0605: ReportDefinitionParam rdp = (ReportDefinitionParam) iter
0606: .next();
0607:
0608: ReportParam rp = new ReportParam();
0609:
0610: rp.setReportDefinitionParam(rdp);
0611: rp.setReport(report);
0612:
0613: // if the parameter is static then copy the value, otherwise it is filled by user
0614: if (rdp.getValueType().equals(
0615: ReportDefinitionParam.VALUE_TYPE_STATIC)) {
0616: rp.setValue(replaceSystemValues(rdp.getValue()));
0617: }
0618: reportParams.add(rp);
0619: }
0620: report.setReportParams(reportParams);
0621: }
0622:
0623: /**
0624: * Does a test to ensure that the parameters are valid
0625: * One can get to the parameter definitions through the
0626: * report parameter.
0627: *
0628: * @param parameters a Collection of ReportParam
0629: */
0630: public boolean validateParameters(Collection parameters) {
0631: return true;
0632: }
0633:
0634: /**
0635: * {@inheritDoc}
0636: */
0637: public Report createReport(ReportDefinition reportDefinition) {
0638: getAuthzManager().checkPermission(
0639: ReportFunctions.REPORT_FUNCTION_CREATE,
0640: getIdManager().getId(
0641: ToolManager.getCurrentPlacement().getId()));
0642:
0643: Report report = new Report(reportDefinition);
0644:
0645: //Create the report parameters
0646: createReportParameters(report);
0647:
0648: Session s = SessionManager.getCurrentSession();
0649: report.setUserId(s.getUserId());
0650: report.setCreationDate(new Date());
0651:
0652: return report;
0653: }
0654:
0655: /**
0656: * This function generates the sql connection.
0657: * If the dataSource connection fails then we want to fail over to
0658: * the hibernate session connection. If the usesWarehouse param is null then
0659: * the connection should default to use the warehouse
0660: *
0661: * @return Connection
0662: * @throws HibernateException
0663: * @throws SQLException
0664: */
0665: public Connection getConnection(Boolean useWarehouse)
0666: throws HibernateException, SQLException {
0667: Connection con = null;
0668:
0669: if (useWarehouse == null) {
0670: con = getDataSourceUseWarehouse(true).getConnection();
0671: } else {
0672: con = getDataSourceUseWarehouse(useWarehouse.booleanValue())
0673: .getConnection();
0674: }
0675:
0676: canCloseConnection = true;
0677:
0678: //fail over to the session connection
0679: if (con == null) {
0680: org.hibernate.Session session = getSession();
0681:
0682: con = session.connection();
0683: //as of hibernate 3.1 you must close your connections
0684: //http://www.hibernate.org/250.html
0685: canCloseConnection = true;
0686: }
0687:
0688: return con;
0689: }
0690:
0691: /**
0692: * This closes the database connection if it was pulled from the
0693: * data warehouse. (IOW, doesn't close if the connection came from
0694: * the hibernate session)
0695: *
0696: * @param connection
0697: * @throws SQLException
0698: * @deprecated ? should this method even be used now that both sources require connections to be closed?
0699: */
0700: public void closeConnection(Connection connection)
0701: throws SQLException {
0702: if (canCloseConnection) {
0703: connection.close();
0704: }
0705: }
0706:
0707: /**
0708: * gathers the data for dropdown/list box.
0709: *
0710: * @return String
0711: */
0712: public String generateSQLParameterValue(ReportParam reportParam) {
0713: Connection connection = null;
0714: PreparedStatement stmt = null;
0715: ResultSet rs = null;
0716: String results = "[]";
0717: StringBuffer strbuffer = new StringBuffer();
0718: try {
0719: connection = getConnection(reportParam
0720: .getReportDefinitionParam().getReportDefinition()
0721: .getUsesWarehouse());
0722: stmt = connection
0723: .prepareStatement(replaceSystemValues(reportParam
0724: .getReportDefinitionParam().getValue()));
0725:
0726: rs = stmt.executeQuery();
0727: strbuffer.append("[");
0728: int columns = rs.getMetaData().getColumnCount();
0729: while (rs.next()) {
0730: if (columns >= 2) {
0731: strbuffer.append("(");
0732: }
0733: if (columns >= 1) {
0734: strbuffer.append(rs.getString(1));
0735: }
0736: if (columns >= 2) {
0737: strbuffer.append(";");
0738: strbuffer.append(rs.getString(2));
0739: strbuffer.append(")");
0740: }
0741: strbuffer.append(",");
0742: }
0743: strbuffer.append("]");
0744: results = strbuffer.toString();
0745: } catch (SQLException e) {
0746: logger.error("", e);
0747: throw new OspException(e);
0748: } catch (HibernateException e) {
0749: logger.error("", e);
0750: throw new OspException(e);
0751: } finally {
0752: //ensure that the results set is clsoed
0753: if (rs != null) {
0754: try {
0755: rs.close();
0756: } catch (SQLException e) {
0757: if (logger.isDebugEnabled()) {
0758: logger
0759: .debug("loadArtifactTypes(String, Map) caught "
0760: + e);
0761: }
0762: }
0763: }
0764: //ensure that the stmt is closed
0765: if (stmt != null) {
0766: try {
0767: stmt.close();
0768: } catch (SQLException e) {
0769: if (logger.isDebugEnabled()) {
0770: logger
0771: .debug("loadArtifactTypes(String, Map) caught "
0772: + e);
0773: }
0774: }
0775: }
0776: if (connection != null) {
0777: try {
0778: closeConnection(connection);
0779: } catch (Exception e) {
0780: if (logger.isDebugEnabled()) {
0781: logger.error("", e);
0782: }
0783: }
0784: }
0785: }
0786: return results;
0787: }
0788:
0789: /**
0790: * gets the xsl tranform file, does the transform on the Results,
0791: * then applies the post processor.
0792: * <p/>
0793: * The result is a file being placed into the output Stream.
0794: *
0795: * @param params
0796: * @param out
0797: * @throws IOException
0798: */
0799: public String packageForDownload(Map params, OutputStream out)
0800: throws IOException {
0801: ReportResult result = getCurrentResult();
0802:
0803: String exportResultsId = ((String[]) params.get(EXPORT_XSL_ID))[0];
0804: ReportXsl xslt = result.getReport().getReportDefinition()
0805: .findReportXslByRuntimeId(exportResultsId);
0806: xslt.setReportDefinition(result.getReport()
0807: .getReportDefinition());
0808: String fileData = transform(result, xslt);
0809:
0810: if (xslt.getResultsPostProcessor() != null) {
0811: out.write(xslt.getResultsPostProcessor().postProcess(
0812: fileData));
0813: } else {
0814: out.write(fileData.getBytes());
0815: }
0816:
0817: //Blank filename for now -- no more dangerous, since the request is in the form of a filename
0818: return "";
0819:
0820: }
0821:
0822: /**
0823: * {@inheritDoc}
0824: */
0825: public ReportResult generateResults(Report report)
0826: throws ReportExecutionException {
0827: ReportResult rr = new ReportResult();
0828:
0829: ReportDefinition rd = report.getReportDefinition();
0830: if (rd == null) {
0831: report.connectToDefinition(getReportDefinitions());
0832: rd = report.getReportDefinition();
0833: }
0834: rr.setCreationDate(new Date());
0835: Element reportElement = new Element("reportResult");
0836: Document document = new Document(reportElement);
0837:
0838: // replace the parameters with the values
0839: List reportParams = report.getReportParams();
0840:
0841: int index = -1;
0842: for (Iterator i = rd.getQuery().iterator(); i.hasNext();) {
0843: StringBuffer nextQuery = new StringBuffer(
0844: replaceSystemValues((String) i.next()));
0845: if (index > -1) {
0846: // <extraReportResult index="0">, <extraReportResult index="1"> etc.
0847: Element currentReportResult = new Element(
0848: "extraReportResult");
0849: currentReportResult.setAttribute("index", String
0850: .valueOf(index));
0851: reportElement.addContent(currentReportResult);
0852: executeQuery(nextQuery, reportParams, report,
0853: currentReportResult, rr, rd, false);
0854: } else {
0855: executeQuery(nextQuery, reportParams, report,
0856: reportElement, rr, rd, true);
0857: }
0858: index++;
0859: }
0860:
0861: rr.setCreationDate(new Date());
0862: rr.setReport(report);
0863: rr.setTitle(report.getTitle());
0864: rr.setKeywords(report.getKeywords());
0865: rr.setDescription(report.getDescription());
0866: rr.setUserId(report.getUserId());
0867: rr.setXml((new XMLOutputter()).outputString(document));
0868:
0869: rr = postProcessResult(rd, rr);
0870:
0871: return rr;
0872:
0873: }
0874:
0875: /**
0876: * executes the query converting the results into xml and updating the report
0877: *
0878: * @param query
0879: * @param reportParams
0880: * @param report
0881: * @param reportElement
0882: * @param rr
0883: * @param rd
0884: * @param isFirstResult - true if this is the first sql query in the report, otherwise this should be false
0885: */
0886: protected void executeQuery(StringBuffer query, List reportParams,
0887: Report report, Element reportElement, ReportResult rr,
0888: ReportDefinition rd, boolean isFirstResult) {
0889: // get the query from the Definition and replace the values
0890: // no should be able to put in a system parameter into a report parameter and have it work
0891: // so replace the system values before processing the report parameters
0892: Connection connection = null;
0893: PreparedStatement stmt = null;
0894:
0895: try {
0896: connection = getConnection(report.getReportDefinition()
0897: .getUsesWarehouse());
0898:
0899: query = replaceForMultiSet(query, reportParams);
0900: stmt = connection.prepareStatement(query.toString());
0901: //If there are params, place them with values in the query
0902: if (reportParams != null) {
0903: Iterator iter = reportParams.iterator();
0904: int paramIndex = 0;
0905:
0906: // loop through all the parameters and find in query for replacement
0907: while (iter.hasNext()) {
0908:
0909: // get the paremeter and associated parameter definition
0910: ReportParam rp = (ReportParam) iter.next();
0911: ReportDefinitionParam rdp = rp
0912: .getReportDefinitionParam();
0913: if (ReportDefinitionParam.VALUE_TYPE_MULTI_OF_SET
0914: .equals(rdp.getValueType())
0915: || ReportDefinitionParam.VALUE_TYPE_MULTI_OF_QUERY
0916: .equals(rdp.getValueType())) {
0917:
0918: for (Iterator i = rp.getListValue().iterator(); i
0919: .hasNext();) {
0920: stmt.setString(paramIndex + 1, i.next()
0921: .toString());
0922: paramIndex++;
0923: }
0924:
0925: } else if (rp.getValue() == null) {
0926: throw new OspException(
0927: "The Report Parameter Value was blank. Offending parameter: "
0928: + rdp.getParamName());
0929: } else {
0930: String value = rp.getValue();
0931:
0932: // Dates need to be formatted from user format to database format
0933: if (ReportDefinitionParam.TYPE_DATE.equals(rdp
0934: .getType())) {
0935: value = dbDateFormat.format(userDateFormat
0936: .parse(rp.getValue()));
0937: if ("oracle".equals(rd.getVendor())) {
0938: SimpleDateFormat oracleFormat = new SimpleDateFormat(
0939: "dd-MMM-yyyy");
0940: value = oracleFormat
0941: .format(userDateFormat.parse(rp
0942: .getValue()));
0943: }
0944: }
0945: stmt.setString(paramIndex + 1, value);
0946: paramIndex++;
0947: }
0948:
0949: }
0950: }
0951:
0952: // run the query
0953: ResultSet rs = null;
0954: int resultSetIndex = 0;
0955:
0956: rs = stmt.executeQuery();
0957:
0958: boolean makeUppercase = true;
0959: if (forceColumnLabelUppercase != null) {
0960: makeUppercase = forceColumnLabelUppercase
0961: .booleanValue();
0962: }
0963:
0964: String forceProperty = ServerConfigurationService
0965: .getString("osp.reports.forceColumnLabelUppercase");
0966: if (forceProperty != null && forceProperty.length() > 0) {
0967: makeUppercase = Integer.parseInt(forceProperty) == 1;
0968: }
0969:
0970: int columns = rs.getMetaData().getColumnCount();
0971:
0972: String[] columnNames = new String[columns];
0973:
0974: for (int i = 0; i < columns; i++) {
0975: columnNames[i] = rs.getMetaData().getColumnLabel(i + 1);
0976: if (makeUppercase) {
0977: columnNames[i] = columnNames[i].toUpperCase();
0978: }
0979: }
0980:
0981: if (isFirstResult) {
0982: Element docAttrNode = new Element("attributes");
0983: Element attr = new Element("title");
0984: attr.setText(report.getTitle());
0985: reportElement.addContent(attr);
0986:
0987: attr = new Element("description");
0988: attr.setText(report.getDescription());
0989: reportElement.addContent(attr);
0990:
0991: attr = new Element("keywords");
0992: attr.setText(report.getKeywords());
0993: reportElement.addContent(attr);
0994:
0995: attr = new Element("runDate");
0996: attr.setText(rr.getCreationDate().toString());
0997: reportElement.addContent(attr);
0998:
0999: attr = new Element("isWarehouseReport");
1000: attr.setText(report.getReportDefinition()
1001: .getUsesWarehouse().toString());
1002: reportElement.addContent(attr);
1003:
1004: attr = new Element("isLiveReport");
1005: attr.setText(Boolean.toString(report.getIsLive()));
1006: reportElement.addContent(attr);
1007:
1008: attr = new Element("isSavedReport");
1009: attr.setText(Boolean.toString(report.getIsSaved()));
1010: reportElement.addContent(attr);
1011:
1012: attr = new Element("accessUrl");
1013: attr.setText(ServerConfigurationService.getAccessUrl());
1014: reportElement.addContent(attr);
1015: reportElement.addContent(docAttrNode);
1016: }
1017:
1018: Element paramsNode = new Element("parameters");
1019:
1020: if (reportParams != null) {
1021: Iterator iter = report.getReportParams().iterator();
1022:
1023: // loop through all the parameters
1024: while (iter.hasNext()) {
1025:
1026: // get the paremeter and associated parameter definition
1027: ReportParam rp = (ReportParam) iter.next();
1028: ReportDefinitionParam rdp = rp
1029: .getReportDefinitionParam();
1030:
1031: Element paramNode = new Element("parameter");
1032:
1033: paramNode.setAttribute("title", rdp.getTitle());
1034: paramNode.setAttribute("name", rdp.getParamName());
1035: paramNode.setAttribute("type", rdp.getType());
1036:
1037: paramNode.setText(rp.getValue());
1038:
1039: paramsNode.addContent(paramNode);
1040: }
1041: }
1042: reportElement.addContent(paramsNode);
1043:
1044: Element columnsNode = new Element("columns");
1045: for (int i = 0; i < columnNames.length; i++) {
1046:
1047: Element column = new Element("column");
1048: column.setAttribute("colIndex", "" + i);
1049: column.setAttribute("title", columnNames[i]);
1050: columnsNode.addContent(column);
1051: }
1052: reportElement.addContent(columnsNode);
1053:
1054: Element datarowsNode = new Element("data");
1055: while (rs.next()) {
1056:
1057: Element dataRow = new Element("datarow");
1058:
1059: dataRow.setAttribute("index", "" + resultSetIndex++);
1060: datarowsNode.addContent(dataRow);
1061:
1062: for (int i = 0; i < columns; i++) {
1063:
1064: String data = rs.getString(i + 1);
1065:
1066: Element columnNode = new Element("element");
1067:
1068: dataRow.addContent(columnNode);
1069:
1070: columnNode.setAttribute("colIndex", "" + i);
1071: columnNode.setAttribute("colName", columnNames[i]);
1072:
1073: if (data == null) {
1074: columnNode.setAttribute("isNull", "true");
1075: data = "";
1076: }
1077: columnNode.addContent(new CDATA(data));
1078: }
1079: }
1080: reportElement.addContent(datarowsNode);
1081:
1082: } catch (SQLException e) {
1083: logger.error("", e);
1084: throw new OspException(e);
1085: } catch (ParseException e) {
1086: logger.error("", e);
1087: throw new ReportExecutionException(e);
1088: } catch (HibernateException e) {
1089: logger.error("", e);
1090: throw new OspException(e);
1091: } finally {
1092: try {
1093: stmt.close();
1094: } catch (Exception e) {
1095: logger.error("", e);
1096: }
1097: try {
1098: closeConnection(connection);
1099: } catch (Exception e) {
1100: logger.error("", e);
1101: }
1102: }
1103:
1104: }
1105:
1106: /**
1107: * applies all the post processing filters and returns the processed results
1108: *
1109: * @param rd
1110: * @param rr
1111: * @return results
1112: */
1113: protected ReportResult postProcessResult(ReportDefinition rd,
1114: ReportResult rr) {
1115: List resultProcessors = rd.getResultProcessors();
1116: if (resultProcessors != null) {
1117: for (Iterator i = resultProcessors.iterator(); i.hasNext();) {
1118: ResultProcessor processor = (ResultProcessor) i.next();
1119: rr = processor.process(rr);
1120: }
1121: }
1122: return rr;
1123: }
1124:
1125: public StringBuffer replaceForMultiSet(StringBuffer inQuery,
1126: List reportParams) {
1127: if (reportParams == null) {
1128: return inQuery;
1129: }
1130: Iterator iter = reportParams.iterator();
1131: // loop through all the parameters and find in query for replacement
1132: while (iter.hasNext()) {
1133:
1134: // get the paremeter and associated parameter definition
1135: ReportParam rp = (ReportParam) iter.next();
1136: ReportDefinitionParam rdp = rp.getReportDefinitionParam();
1137: if (ReportDefinitionParam.VALUE_TYPE_MULTI_OF_SET
1138: .equals(rdp.getValueType())
1139: || ReportDefinitionParam.VALUE_TYPE_MULTI_OF_QUERY
1140: .equals(rdp.getValueType())) {
1141:
1142: if (rp.getListValue().size() > 1) {
1143: int index = inQuery.indexOf("(?)");
1144: inQuery.delete(index, index + 3);
1145: StringBuffer tempString = new StringBuffer("(");
1146: for (int i = 0; i < rp.getListValue().size(); i++) {
1147: tempString.append("?,");
1148: }
1149: tempString.delete(tempString.length() - 1,
1150: tempString.length());
1151: tempString.append(") ");
1152: inQuery.insert(index + 2, tempString);
1153: }
1154: }
1155: }
1156: return inQuery;
1157: }
1158:
1159: /**
1160: * {@inheritDoc}
1161: */
1162: public String replaceSystemValues(String inString) {
1163:
1164: Session s = SessionManager.getCurrentSession();
1165:
1166: Map map = new HashMap();
1167: map.put("{userid}", s.getUserId());
1168: //system values are stored in session if report is scheduled through quartz
1169: if (s.getAttribute("toolid") == null) {
1170: UserDirectoryService dirServ = org.sakaiproject.user.cover.UserDirectoryService
1171: .getInstance();
1172: User u = dirServ.getCurrentUser();
1173: map.put("{userdisplayname}", u.getDisplayName());
1174: map.put("{useremail}", u.getEmail());
1175: map.put("{userfirstname}", u.getFirstName());
1176: map.put("{userlastname}", u.getLastName());
1177: map.put("{worksiteid}", ToolManager.getCurrentPlacement()
1178: .getContext());
1179: map.put("{toolid}", ToolManager.getCurrentPlacement()
1180: .getId());
1181: } else {
1182: map.put("{userdisplayname}", s
1183: .getAttribute("userdisplayname"));
1184: map.put("{useremail}", s.getAttribute("useremail"));
1185: map.put("{userfirstname}", s.getAttribute("userfirstname"));
1186: map.put("{userlastname}", s.getAttribute("userlastname"));
1187: map.put("{worksiteid}", s.getAttribute("worksiteid"));
1188: map.put("{toolid}", s.getAttribute("toolid"));
1189: }
1190:
1191: Iterator iter = map.keySet().iterator();
1192: StringBuffer str = new StringBuffer(inString);
1193:
1194: // loop through all the parameters and find in query for replacement
1195: while (iter.hasNext()) {
1196:
1197: // get the paremeter and associated parameter definition
1198: String key = (String) iter.next();
1199:
1200: int i = str.indexOf(key);
1201:
1202: // Loop until no instances exist
1203: while (i != -1) {
1204:
1205: // replace the parameter with the value
1206: str.delete(i, i + key.length());
1207: str.insert(i, (String) map.get(key));
1208:
1209: // look for a second instance
1210: i = str.indexOf(key);
1211: }
1212: }
1213:
1214: return str.toString();
1215: }
1216:
1217: /**
1218: * {@inheritDoc}
1219: */
1220: public String transform(ReportResult reportResult,
1221: ReportXsl reportXsl) {
1222: try {
1223:
1224: JDOMResult result = new JDOMResult();
1225: SAXBuilder builder = new SAXBuilder();
1226: StreamSource xsltSource;
1227: if (reportXsl.getResource() == null) {
1228: xsltSource = new StreamSource(loadXslFromDB(reportXsl));
1229: } else {
1230: xsltSource = new StreamSource(reportXsl.getResource()
1231: .getInputStream());
1232: }
1233: Transformer transformer = TransformerFactory.newInstance()
1234: .newTransformer(xsltSource);
1235: Document rootElement = builder.build(new StringReader(
1236: reportResult.getXml()));
1237:
1238: ByteArrayOutputStream sourceOut = new ByteArrayOutputStream();
1239: StreamResult resultstream = new StreamResult(sourceOut);
1240:
1241: transformer.transform(new JDOMSource(rootElement),
1242: resultstream);
1243:
1244: return sourceOut.toString();
1245:
1246: } catch (Exception e) {
1247: logger.error("", e);
1248: throw new OspException(e);
1249: }
1250: }
1251:
1252: public InputStream loadXslFromDB(ReportXsl reportXsl) {
1253: ByteArrayInputStream inputStream = null;
1254: List xsls = getHibernateTemplate()
1255: .find(
1256: "from ReportXslFile r where reportDefId = ? and reportXslFileRef = ?",
1257: new Object[] {
1258: reportXsl.getReportDefinition()
1259: .getIdString(),
1260: reportXsl.getXslLink() });
1261: for (Iterator i = xsls.iterator(); i.hasNext();) {
1262: ReportXslFile xslFile = (ReportXslFile) i.next();
1263: inputStream = new ByteArrayInputStream(xslFile.getXslFile());
1264: }
1265: return inputStream;
1266: }
1267:
1268: private String getResourceFrom(String file) {
1269: String componentsRoot = System
1270: .getProperty(ComponentManager.SAKAI_COMPONENTS_ROOT_SYS_PROP);
1271:
1272: return componentsRoot + "osp-reports-components/WEB-INF/"
1273: + file;
1274: }
1275:
1276: private void writeFile(String fileString, String fileName,
1277: String contentType) {
1278: FacesContext faces = FacesContext.getCurrentInstance();
1279: HttpServletResponse response = (HttpServletResponse) faces
1280: .getExternalContext().getResponse();
1281: protectAgainstInstantDeletion(response);
1282: response.setContentType(contentType);
1283: response.setHeader("Content-disposition",
1284: "attachment; filename=" + fileName + ".csv");
1285: response.setContentLength(fileString.length());
1286: OutputStream out = null;
1287: try {
1288: out = response.getOutputStream();
1289: out.write(fileString.getBytes());
1290: out.flush();
1291: } catch (IOException e) {
1292: e.printStackTrace();
1293: } finally {
1294: try {
1295: if (out != null) {
1296: out.close();
1297: }
1298: } catch (IOException e) {
1299: e.printStackTrace();
1300: }
1301: }
1302: faces.responseComplete();
1303: }
1304:
1305: /**
1306: * THIS IS TAKEN FROM GRADEBOOK: org.sakai.tool.gradebook.ui.ExportBean
1307: * <p/>
1308: * Try to head off a problem with downloading files from a secure HTTPS
1309: * connection to Internet Explorer.
1310: * <p/>
1311: * When IE sees it's talking to a secure server, it decides to treat all hints
1312: * or instructions about caching as strictly as possible. Immediately upon
1313: * finishing the download, it throws the data away.
1314: * <p/>
1315: * Unfortunately, the way IE sends a downloaded file on to a helper
1316: * application is to use the cached copy. Having just deleted the file,
1317: * it naturally isn't able to find it in the cache. Whereupon it delivers
1318: * a very misleading error message like:
1319: * "Internet Explorer cannot download roster from sakai.yoursite.edu.
1320: * Internet Explorer was not able to open this Internet site. The requested
1321: * site is either unavailable or cannot be found. Please try again later."
1322: * <p/>
1323: * There are several ways to turn caching off, and so to be safe we use
1324: * several ways to turn it back on again.
1325: * <p/>
1326: * This current workaround should let IE users save the files to disk.
1327: * Unfortunately, errors may still occur if a user attempts to open the
1328: * file directly in a helper application from a secure web server.
1329: * <p/>
1330: * TODO Keep checking on the status of this.
1331: */
1332: private static void protectAgainstInstantDeletion(
1333: HttpServletResponse response) {
1334: response.reset(); // Eliminate the added-on stuff
1335: response.setHeader("Pragma", "public"); // Override old-style cache control
1336: response
1337: .setHeader("Cache-Control",
1338: "public, must-revalidate, post-check=0, pre-check=0, max-age=0"); // New-style
1339: }
1340:
1341: /**
1342: * {@inheritDoc}
1343: */
1344: public void saveReportResult(ReportResult result) {
1345: getHibernateTemplate().saveOrUpdate(result.getReport());
1346: getHibernateTemplate().saveOrUpdate(result);
1347:
1348: // the user can't save results that have already been saved
1349: result.getReport().setIsSaved(true);
1350: result.setIsSaved(true);
1351: }
1352:
1353: /**
1354: * {@inheritDoc}
1355: */
1356: public void saveReport(Report report) {
1357: getHibernateTemplate().saveOrUpdate(report);
1358:
1359: // the user can't save reports that have already been saved
1360: report.setIsSaved(true);
1361: }
1362:
1363: /**
1364: * {@inheritDoc}
1365: */
1366: public void deleteReportResult(ReportResult result) {
1367:
1368: checkPermission(ReportFunctions.REPORT_FUNCTION_DELETE);
1369:
1370: getHibernateTemplate().delete(result);
1371:
1372: // if we are deleting the result, then if the report it came from is not on display then delete the report too
1373: if (!result.getReport().getDisplay()
1374: || !result.getReport().getIsLive()) {
1375: deleteReport(result.getReport(), false);
1376: }
1377: }
1378:
1379: /**
1380: * {@inheritDoc}
1381: */
1382: public void deleteReport(Report report, boolean deactivate) {
1383: boolean deleteAction = false, deactivateAction = false;
1384:
1385: checkPermission(ReportFunctions.REPORT_FUNCTION_DELETE);
1386:
1387: report = (Report) getHibernateTemplate().get(Report.class,
1388: report.getReportId());
1389:
1390: List results = getHibernateTemplate().findByNamedQuery(
1391: "findResultsByReport", report);
1392:
1393: if (report.getIsLive()) {
1394: if (results.size() == 0) {
1395: deleteAction = true;
1396: } else if (deactivate) {
1397: deactivateAction = true;
1398: }
1399: } else { //the report is not live so delete any report results
1400: for (Iterator i = results.iterator(); i.hasNext();) {
1401: getHibernateTemplate().delete(i.next());
1402: }
1403: deleteAction = true;
1404: }
1405:
1406: if (deleteAction) {
1407: getHibernateTemplate().delete(report);
1408: } else if (deactivateAction) {
1409: report.setDisplay(false);
1410: getHibernateTemplate().saveOrUpdate(report);
1411: }
1412: }
1413:
1414: public String getSecretKey() {
1415: return secretKey;
1416: }
1417:
1418: public void setSecretKey(String secretKey) {
1419: this .secretKey = secretKey;
1420: }
1421:
1422: public SecurityService getSecurityService() {
1423: return securityService;
1424: }
1425:
1426: public void setSecurityService(SecurityService securityService) {
1427: this .securityService = securityService;
1428: }
1429:
1430: private Site getCurrentSite() {
1431: try {
1432: if (ToolManager.getCurrentPlacement() != null) {
1433: return SiteService.getSite(ToolManager
1434: .getCurrentPlacement().getContext());
1435: }
1436: //if this job is running because of scheduler
1437: org.sakaiproject.tool.api.Session sakaiSession = SessionManager
1438: .getCurrentSession();
1439: return SiteService.getSite((String) sakaiSession
1440: .getAttribute("worksiteid"));
1441:
1442: } catch (IdUnusedException iue) {
1443: return null;
1444: }
1445: }
1446:
1447: /**
1448: * Returns the type of current worksite
1449: *
1450: * @return String
1451: */
1452: private String getCurrentSiteType() {
1453: return getCurrentSite() != null ? getCurrentSite().getType()
1454: : "";
1455: }
1456:
1457: public AuthorizationFacade getAuthzManager() {
1458: return authzManager;
1459: }
1460:
1461: public void setAuthzManager(AuthorizationFacade authzManager) {
1462: this .authzManager = authzManager;
1463: }
1464:
1465: protected void checkPermission(String function) {
1466: getAuthzManager().checkPermission(
1467: function,
1468: getIdManager().getId(
1469: ToolManager.getCurrentPlacement().getId()));
1470: }
1471:
1472: /**
1473: * {@inheritDoc}
1474: */
1475: public Map getAuthorizationsMap() {
1476: return new AuthZMap(getAuthzManager(),
1477: ReportFunctions.REPORT_FUNCTION_PREFIX, getIdManager()
1478: .getId(
1479: ToolManager.getCurrentPlacement()
1480: .getId()));
1481: }
1482:
1483: protected boolean can(String function) {
1484: return new Boolean(getAuthzManager().isAuthorized(
1485: function,
1486: getIdManager().getId(
1487: ToolManager.getCurrentPlacement().getId())))
1488: .booleanValue();
1489: }
1490:
1491: /**
1492: * {@inheritDoc}
1493: */
1494: public boolean isMaintaner() {
1495: return new Boolean(getAuthzManager()
1496: .isAuthorized(
1497: WorksiteManager.WORKSITE_MAINTAIN,
1498: getIdManager().getId(
1499: ToolManager.getCurrentPlacement()
1500: .getContext()))).booleanValue();
1501: }
1502:
1503: /**
1504: * {@inheritDoc}
1505: */
1506: public void checkEditAccess() {
1507: checkPermission(ReportFunctions.REPORT_FUNCTION_EDIT);
1508: }
1509:
1510: public DataSource getSakaiDataSource() {
1511: return sakaiDataSource;
1512: }
1513:
1514: public void setSakaiDataSource(DataSource sakaiDataSource) {
1515: this .sakaiDataSource = sakaiDataSource;
1516: }
1517:
1518: public Boolean getForceColumnLabelUppercase() {
1519: return forceColumnLabelUppercase;
1520: }
1521:
1522: public void setForceColumnLabelUppercase(
1523: Boolean forceColumnLabelUppercase) {
1524: this .forceColumnLabelUppercase = forceColumnLabelUppercase;
1525: }
1526:
1527: private ReportDefinitionXmlFile importReport(
1528: ContentResource resource) {
1529: ReportDefinitionXmlFile bean = null;
1530:
1531: try {
1532:
1533: bean = new ReportDefinitionXmlFile(resource);
1534:
1535: } catch (Exception e) {
1536: e.printStackTrace();
1537: }
1538: return bean;
1539: }
1540:
1541: public ContentHostingService getContentHosting() {
1542: return contentHosting;
1543: }
1544:
1545: public void setContentHosting(ContentHostingService contentHosting) {
1546: this .contentHosting = contentHosting;
1547: }
1548:
1549: public List getDefinedDefintions() {
1550: return definedDefintions;
1551: }
1552:
1553: public void setDefinedDefintions(List definedDefintions) {
1554: this .definedDefintions = definedDefintions;
1555: }
1556:
1557: public boolean importResource(Id worksiteId, String nodeId)
1558: throws UnsupportedFileTypeException, ImportException,
1559: OspException {
1560:
1561: String id = getContentHosting().resolveUuid(nodeId);
1562: try {
1563: ContentResource resource = getContentHosting().getResource(
1564: id);
1565: MimeType mimeType = new MimeType(resource.getContentType());
1566:
1567: if (mimeType.equals(new MimeType("application/xml"))
1568: || mimeType.equals(new MimeType("text/xml"))) {
1569: ListableBeanFactory beanFactory = new XmlBeanFactory(
1570: new InputStreamResource(resource
1571: .streamContent()));
1572: ReportDefinitionXmlFile bean = importReport(resource);
1573: if (bean != null) {
1574: saveReportDef(bean, beanFactory);
1575: }
1576: return bean != null;
1577: } else {
1578: throw new UnsupportedFileTypeException(
1579: "Unsupported file type");
1580: }
1581:
1582: } catch (ServerOverloadException soe) {
1583: logger.warn(soe);
1584:
1585: } catch (PermissionException pe) {
1586: logger
1587: .warn(
1588: "Failed loading content: no permission to view file",
1589: pe);
1590: } catch (TypeException te) {
1591: logger.warn("Wrong type", te);
1592: } catch (IdUnusedException iue) {
1593: logger.warn("UnusedId: ", iue);
1594: }
1595: return false;
1596: }
1597:
1598: public void saveReportDef(ReportDefinitionXmlFile xmlFile,
1599: ListableBeanFactory beanFactory) throws OspException {
1600:
1601: ReportDefinition reportDef = getReportDefBean(beanFactory);
1602: List reportDefList = new ArrayList();
1603: reportDefList.add(reportDef);
1604: xmlFile.setReportDefId(reportDef.getIdString());
1605: xmlFile.setReportXslFiles(processXSLFiles(reportDef, xmlFile));
1606: getHibernateTemplate().saveOrUpdate(xmlFile);
1607: }
1608:
1609: public Set processXSLFiles(ReportDefinition reportDef,
1610: ReportDefinitionXmlFile xmlFile) throws OspException {
1611: Set xslsList = new HashSet();
1612:
1613: ReportXsl defaultXsl = reportDef.getDefaultXsl();
1614:
1615: if (defaultXsl == null) {
1616: return xslsList;
1617: } else {
1618: List xsls = reportDef.getXsls();
1619: for (Iterator i = xsls.iterator(); i.hasNext();) {
1620: ReportXsl xsl = (ReportXsl) i.next();
1621: ReportXslFile xslFile = new ReportXslFile(xsl,
1622: getContentHosting());
1623: xslFile.setReportDefId(reportDef.getIdString());
1624: xslFile.setReportXslFileRef(xsl.getXslLink());
1625: xslFile.setReportDef(xmlFile);
1626: xslsList.add(xslFile);
1627: }
1628:
1629: }
1630:
1631: return xslsList;
1632:
1633: }
1634:
1635: public void deleteReportDefXmlFile(ReportDefinition reportDef) {
1636:
1637: checkPermission(ReportFunctions.REPORT_FUNCTION_DELETE);
1638: List xsls = getHibernateTemplate().find(
1639: "from ReportXslFile r where reportDefId = ?",
1640: reportDef.getIdString());
1641: for (Iterator i = xsls.iterator(); i.hasNext();) {
1642: getHibernateTemplate().delete(i.next());
1643: }
1644: List results = getHibernateTemplate().find(
1645: "from ReportDefinitionXmlFile r where reportDefId = ?",
1646: reportDef.getIdString());
1647: for (Iterator i = results.iterator(); i.hasNext();) {
1648: getHibernateTemplate().delete(i.next());
1649: }
1650: }
1651:
1652: public ReportDefinition getReportDefBean(
1653: ListableBeanFactory beanFactory) {
1654: Map beanMap = beanFactory
1655: .getBeansOfType(ReportDefinition.class);
1656: for (Iterator i = beanMap.values().iterator(); i.hasNext();) {
1657: return (ReportDefinition) i.next();
1658: }
1659: return null;
1660: }
1661:
1662: public void saveXslFile(ReportXslFile reportXslFile) {
1663: getHibernateTemplate().saveOrUpdate(reportXslFile);
1664: }
1665:
1666: protected void initDefinedReportDefinitions() {
1667: getSecurityService().pushAdvisor(new AllowAllSecurityAdvisor());
1668:
1669: org.sakaiproject.tool.api.Session sakaiSession = SessionManager
1670: .getCurrentSession();
1671: String userId = sakaiSession.getUserId();
1672: sakaiSession.setUserId("admin");
1673: sakaiSession.setUserEid("admin");
1674: List definitions = new ArrayList();
1675:
1676: try {
1677: for (Iterator i = getDefinedDefintions().iterator(); i
1678: .hasNext();) {
1679: definitions
1680: .add(processDefinedDefinition((ReportsDefinitionWrapper) i
1681: .next()));
1682: }
1683:
1684: } finally {
1685: getSecurityService().popAdvisor();
1686: sakaiSession.setUserEid(userId);
1687: sakaiSession.setUserId(userId);
1688: }
1689:
1690: }
1691:
1692: protected ReportDefinitionXmlFile processDefinedDefinition(
1693: ReportsDefinitionWrapper wrapper) {
1694: ReportDefinitionXmlFile definition = getReportDefinition(wrapper
1695: .getIdValue());
1696:
1697: if (definition == null) {
1698: definition = new ReportDefinitionXmlFile();
1699: definition.setReportDefId(wrapper.getIdValue());
1700: }
1701:
1702: updateDefinition(wrapper, definition);
1703: return definition;
1704: }
1705:
1706: protected void updateDefinition(ReportsDefinitionWrapper wrapper,
1707: ReportDefinitionXmlFile def) {
1708: try {
1709:
1710: InputStream stream = getClass().getResourceAsStream(
1711: wrapper.getDefinitionFileLocation());
1712: if (stream == null) {
1713: new RuntimeException(
1714: "Loaded Report Definition failed: "
1715: + wrapper.getDefinitionFileLocation());
1716: }
1717: Set xslFiles = new HashSet();
1718: def.setXmlFile(readStreamToBytes(getClass()
1719: .getResourceAsStream(
1720: wrapper.getDefinitionFileLocation())));
1721:
1722: ListableBeanFactory beanFactory = new XmlBeanFactory(
1723: new InputStreamResource(
1724: getClass()
1725: .getResourceAsStream(
1726: wrapper
1727: .getDefinitionFileLocation())),
1728: getBeanFactory());
1729: ReportDefinition repDef = getReportDefBean(beanFactory);
1730: List xsls = repDef.getXsls();
1731: for (Iterator i = xsls.iterator(); i.hasNext();) {
1732: ReportXsl xsl = (ReportXsl) i.next();
1733: ReportXslFile xslFile = new ReportXslFile();
1734: if (getClass().getResourceAsStream(xsl.getXslLink()) != null) {
1735: xslFile.setXslFile(readStreamToBytes(getClass()
1736: .getResourceAsStream(xsl.getXslLink())));
1737: }
1738: xslFile.setReportDefId(repDef.getIdString());
1739: xslFile.setReportXslFileRef(xsl.getXslLink());
1740: xslFile.setReportDef(def);
1741: xslFiles.add(xslFile);
1742:
1743: }
1744: def.setReportXslFiles(xslFiles);
1745: getHibernateTemplate().saveOrUpdate(def);
1746: } catch (Exception e) {
1747: e.printStackTrace();
1748: }
1749: }
1750:
1751: public ReportDefinitionXmlFile getReportDefinition(String id) {
1752: return (ReportDefinitionXmlFile) getHibernateTemplate().get(
1753: ReportDefinitionXmlFile.class, id);
1754: }
1755:
1756: public Report getReportById(String id) {
1757: Report report = (Report) getHibernateTemplate().get(
1758: Report.class, new IdImpl(id, null));
1759: report.connectToDefinition(getReportDefinitions());
1760: return report;
1761: }
1762:
1763: private byte[] readStreamToBytes(InputStream inStream)
1764: throws IOException {
1765: ByteArrayOutputStream bytes = new ByteArrayOutputStream();
1766: byte data[] = new byte[10 * 1024];
1767:
1768: int count;
1769: while ((count = inStream.read(data, 0, 10 * 1024)) != -1) {
1770: bytes.write(data, 0, count);
1771: }
1772: byte[] tmp = bytes.toByteArray();
1773: bytes.close();
1774: return tmp;
1775: }
1776:
1777: public List getReportsByViewer() {
1778: Agent viewer = getAuthnManager().getAgent();
1779: Collection reportAuthzs = getOspAuthzManager()
1780: .getAuthorizations(viewer,
1781: ReportFunctions.REPORT_FUNCTION_VIEW, null);
1782:
1783: List results = new ArrayList();
1784: for (Iterator i = reportAuthzs.iterator(); i.hasNext();) {
1785: Id resultId = ((Authorization) i.next()).getQualifier();
1786: List result = getReportResults(resultId);
1787: for (Iterator iter = result.iterator(); iter.hasNext();) {
1788: results.add(iter.next());
1789: }
1790: }
1791: return results;
1792: }
1793:
1794: List getReportResults(Id resultId) {
1795:
1796: boolean viewReports = can(ReportFunctions.REPORT_FUNCTION_VIEW);
1797:
1798: List returned = new ArrayList();
1799:
1800: if (viewReports) {
1801: List results = getHibernateTemplate().findByNamedQuery(
1802: "findResultsById", resultId);
1803:
1804: Iterator iter = results.iterator();
1805: while (iter.hasNext()) {
1806: ReportResult r = (ReportResult) iter.next();
1807:
1808: r.setIsSaved(true);
1809: }
1810: returned.addAll(results);
1811: }
1812: return returned;
1813: }
1814:
1815: protected String createResource(ByteArrayOutputStream bos,
1816: String name, String description, String type) {
1817:
1818: ContentResource resource = null;
1819: ResourcePropertiesEdit resourceProperties = getContentHosting()
1820: .newResourceProperties();
1821: resourceProperties.addProperty(
1822: ResourceProperties.PROP_DISPLAY_NAME, name);
1823: resourceProperties.addProperty(
1824: ResourceProperties.PROP_DESCRIPTION, description);
1825: resourceProperties.addProperty(
1826: ResourceProperties.PROP_CONTENT_ENCODING, "UTF-8");
1827:
1828: getSecurityService().pushAdvisor(new AllowAllSecurityAdvisor());
1829:
1830: org.sakaiproject.tool.api.Session sakaiSession = SessionManager
1831: .getCurrentSession();
1832: String userId = sakaiSession.getUserId();
1833: sakaiSession.setUserId(userId);
1834: sakaiSession.setUserEid(userId);
1835:
1836: try {
1837:
1838: ContentCollectionEdit groupCollection = getContentHosting()
1839: .addCollection(
1840: getUserCollection().getId()
1841: + "savedReports/");
1842: groupCollection.getPropertiesEdit().addProperty(
1843: ResourceProperties.PROP_DISPLAY_NAME,
1844: "Saved Reports");
1845: groupCollection.getPropertiesEdit().addProperty(
1846: ResourceProperties.PROP_DESCRIPTION,
1847: "Folder for Saved Report Results");
1848: getContentHosting().commitCollection(groupCollection);
1849: } catch (IdUsedException e) {
1850: // ignore... it is already there.
1851: if (logger.isDebugEnabled()) {
1852: logger.debug(e);
1853: }
1854: } catch (Exception e) {
1855: throw new RuntimeException(e);
1856: }
1857:
1858: try {
1859: String id = getUserCollection().getId() + "Saved Reports/"
1860: + name;
1861: getContentHosting().removeResource(id);
1862: } catch (TypeException e) {
1863: // ignore, must be new
1864: if (logger.isDebugEnabled()) {
1865: logger.debug(e);
1866: }
1867: } catch (IdUnusedException e) {
1868: // ignore, must be new
1869: if (logger.isDebugEnabled()) {
1870: logger.debug(e);
1871: }
1872: } catch (PermissionException e) {
1873: // ignore, must be new
1874: if (logger.isDebugEnabled()) {
1875: logger.debug(e);
1876: }
1877: } catch (InUseException e) {
1878: // ignore, must be new
1879: if (logger.isDebugEnabled()) {
1880: logger.debug(e);
1881: }
1882: }
1883:
1884: try {
1885: resource = getContentHosting().addResource(name,
1886: getUserCollection().getId() + "savedReports/", 100,
1887: type, bos.toByteArray(), resourceProperties,
1888: NotificationService.NOTI_NONE);
1889: } catch (Exception e) {
1890: throw new RuntimeException(e);
1891: }
1892:
1893: return "savedReports/" + name;
1894: }
1895:
1896: public String processSaveResultsToResources(
1897: ReportResult reportResult) throws IOException {
1898: ByteArrayOutputStream bos = new ByteArrayOutputStream();
1899: Report report = reportResult.getReport();
1900: report.connectToDefinition(getReportDefinitions());
1901: ReportXsl xslt = report.getReportDefinition().getDefaultXsl();
1902: xslt.setReportDefinition(report.getReportDefinition());
1903: String fileData = transform(reportResult, xslt);
1904:
1905: if (xslt.getResultsPostProcessor() != null) {
1906: bos.write(xslt.getResultsPostProcessor().postProcess(
1907: fileData));
1908: } else {
1909: bos.write(fileData.getBytes());
1910: }
1911: return createResource(bos, reportResult.getTitle() + ".html",
1912: reportResult.getTitle(), "text/html");
1913:
1914: }
1915:
1916: protected ContentCollection getUserCollection()
1917: throws TypeException, IdUnusedException,
1918: PermissionException {
1919: User user = org.sakaiproject.user.cover.UserDirectoryService
1920: .getCurrentUser();
1921: String userId = user.getId();
1922: String wsId = SiteService.getUserSiteId(userId);
1923: String wsCollectionId = getContentHosting().getSiteCollection(
1924: wsId);
1925: ContentCollection collection = getContentHosting()
1926: .getCollection(wsCollectionId);
1927: return collection;
1928: }
1929:
1930: public SchedulerManager getSchedulerManager() {
1931: return schedulerManager;
1932: }
1933:
1934: public void setSchedulerManager(SchedulerManager schedulerManager) {
1935: this .schedulerManager = schedulerManager;
1936: }
1937:
1938: public void execute(JobExecutionContext jobExecutionContext)
1939: throws JobExecutionException {
1940: getSecurityService().pushAdvisor(new AllowAllSecurityAdvisor());
1941: org.sakaiproject.tool.api.Session sakaiSession = SessionManager
1942: .getCurrentSession();
1943: String sessionUserId = sakaiSession.getUserId();
1944: try {
1945: Map details = jobExecutionContext.getJobDetail()
1946: .getJobDataMap();
1947: String reportId = (String) details.get("reportId");
1948: String userId = (String) details.get("userId");
1949: sakaiSession.setAttribute("userdisplayname",
1950: (String) details.get("userdisplayname"));
1951: sakaiSession.setAttribute("useremail", (String) details
1952: .get("useremail"));
1953: sakaiSession.setAttribute("userfirstname", (String) details
1954: .get("userfirstname"));
1955: sakaiSession.setAttribute("userlastname", (String) details
1956: .get("userlastname"));
1957: sakaiSession.setAttribute("worksiteid", (String) details
1958: .get("worksiteid"));
1959: sakaiSession.setAttribute("toolid", (String) details
1960: .get("toolid"));
1961: sakaiSession.setUserId(userId);
1962: sakaiSession.setUserEid(userId);
1963: Report report = getReportById(reportId);
1964: if (report != null) {
1965: ReportResult result = generateResults(report);
1966: result.setIsSaved(true);
1967: result.setTitle(result.getTitle() + " - "
1968: + result.getCreationDate());
1969: processSaveResultsToResources(result);
1970: saveReportResult(result);
1971: } else {
1972: schedulerManager.getScheduler().deleteJob(
1973: jobExecutionContext.getJobDetail().getName(),
1974: reportGroup);
1975: }
1976: } catch (Exception e) {
1977: e.printStackTrace();
1978: } finally {
1979: getSecurityService().popAdvisor();
1980: sakaiSession.setUserEid(sessionUserId);
1981: sakaiSession.setUserId(sessionUserId);
1982: }
1983:
1984: }
1985:
1986: public void processDeleteJobs(JobDetail jobDetail) {
1987: try {
1988: schedulerManager.getScheduler().deleteJob(
1989: jobDetail.getName(), reportGroup);
1990: } catch (SchedulerException e) {
1991: logger.error("Scheduler Down");
1992: }
1993: }
1994:
1995: public JobDetail processCreateJob(Report report) {
1996: Scheduler scheduler = getSchedulerManager().getScheduler();
1997: UserDirectoryService dirServ = org.sakaiproject.user.cover.UserDirectoryService
1998: .getInstance();
1999: User u = dirServ.getCurrentUser();
2000: if (scheduler == null) {
2001: logger.error("Scheduler is down!");
2002: }
2003: JobDetail jd = null;
2004: try {
2005:
2006: JobBeanWrapper job = getJobBeanWrapper();
2007: if (job != null) {
2008:
2009: jd = scheduler.getJobDetail(report.getReportId()
2010: .toString(), reportGroup);
2011: if (jd == null) {
2012: jd = new JobDetail(report.getReportId().toString(),
2013: reportGroup, job.getJobClass(), false,
2014: true, true);
2015: jd.getJobDataMap().put(
2016: JobBeanWrapper.SPRING_BEAN_NAME,
2017: job.getBeanId());
2018: jd.getJobDataMap().put(JobBeanWrapper.JOB_TYPE,
2019: job.getJobType());
2020: jd.getJobDataMap().put("reportId",
2021: report.getReportId().getValue());
2022: jd.getJobDataMap().put("userId",
2023: SessionManager.getCurrentSessionUserId());
2024: jd.getJobDataMap().put("userdisplayname",
2025: u.getDisplayName());
2026: jd.getJobDataMap().put("useremail", u.getEmail());
2027: jd.getJobDataMap().put("userfirstname",
2028: u.getFirstName());
2029: jd.getJobDataMap().put("userlastname",
2030: u.getLastName());
2031: jd.getJobDataMap().put(
2032: "worksiteid",
2033: ToolManager.getCurrentPlacement()
2034: .getContext());
2035: jd.getJobDataMap().put("toolid",
2036: ToolManager.getCurrentPlacement().getId());
2037:
2038: scheduler.addJob(jd, false);
2039: }
2040: } else {
2041: jd = new JobDetail(report.getReportId().toString(),
2042: reportGroup, SpringJobBeanWrapper.class, false,
2043: true, true);
2044: scheduler.addJob(jd, false);
2045: }
2046: } catch (Exception e) {
2047: logger.error("Failed to create job");
2048: }
2049: return jd;
2050: }
2051:
2052: public JobBeanWrapper getJobBeanWrapper() {
2053: return jobBeanWrapper;
2054: }
2055:
2056: public void setJobBeanWrapper(JobBeanWrapper jobBeanWrapper) {
2057: this .jobBeanWrapper = jobBeanWrapper;
2058: }
2059:
2060: public boolean isAutoDdl() {
2061: return autoDdl;
2062: }
2063:
2064: public void setAutoDdl(boolean autoDdl) {
2065: this.autoDdl = autoDdl;
2066: }
2067:
2068: }
|