/* * Copyright (C) 2012 Peter boy (pboy@barkhof.uni-bremen.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.arsdigita.cms.docmgr.ui; import com.arsdigita.bebop.ActionLink; import com.arsdigita.bebop.Label; import com.arsdigita.bebop.Page; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.RequestLocal; import com.arsdigita.bebop.TabbedPane; import com.arsdigita.bebop.event.ActionEvent; import com.arsdigita.bebop.event.ActionListener; import com.arsdigita.bebop.event.PrintEvent; import com.arsdigita.bebop.event.PrintListener; import com.arsdigita.bebop.parameters.BigDecimalParameter; import com.arsdigita.cms.FileAsset; import com.arsdigita.cms.docmgr.Document; import com.arsdigita.dispatcher.DispatcherHelper; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.kernel.Kernel; import com.arsdigita.kernel.permissions.PrivilegeDescriptor; import com.arsdigita.persistence.AbstractTransactionListener; import com.arsdigita.persistence.Session; import com.arsdigita.persistence.SessionManager; import com.arsdigita.persistence.TransactionContext; import com.arsdigita.templating.PresentationManager; import com.arsdigita.templating.Templating; import com.arsdigita.util.Assert; import com.arsdigita.versioning.Versions; import com.arsdigita.web.Application; import com.arsdigita.web.BaseApplicationServlet; import com.arsdigita.web.Web; import java.io.IOException; import java.io.OutputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; /** * Application servlet for ccm-docmgr's Repository application, the main * package application, serves all request made for the application's UI. * * RepositporyServlet is called by BaseApplicationServlet which has determined * that RepositoryServlet is associated with a request URL. * * The servlet has to be included in servlet container's deployment descriptor, * see {@see com.arsdigita.cms.docmgr.Repository#getServletPath()} for details * about web.xml record. It is NOT directly referenced by any other class. * * It determines whether a Page has been registered to the URL and * if so passes the request to that page. Otherwise it hands the request * to the TemplateResolver to find an appropriate JSP file. * * @author Stefan Deusch * @author Peter Boy * @version $Id: RepositoryServlet.java 2161 2012-02-26 00:16:13Z pboy $ */ public class RepositoryServlet extends BaseApplicationServlet implements DMConstants { /** Private logger instance to faciliate debugging procedures */ private static final Logger s_log = Logger.getLogger(RepositoryServlet.class); /** URL (pathinfo) -> Page object mapping. Based on it (and the http * request url) the doService method selects a page to display */ private final Map m_pages = new HashMap(); /** * Use parent's class initialization extension point to perform additional * initialisation tasks. Here: build the UI pages. */ @Override public void doInit() { addPage( "/", buildRepositoryIndexPage() ); addPage( "/file", buildFileInfoPage()); // search is a tab, for now. //addPage("/search", buildSearchPage()); //addPage("/search/file", buildFileInfoPage()); } /** * Implements the (abstract) doService method of BaseApplicationServlet to * perform the services. * @see com.arsdigita.web.BaseApplicationServlet#doService * (HttpServletRequest, HttpServletResponse, Application) */ protected void doService( HttpServletRequest sreq, HttpServletResponse sresp, Application app) throws ServletException, IOException { if (s_log.isDebugEnabled()) { s_log.info("starting doService method"); } String url = sreq.getRequestURI(); int index = url.lastIndexOf("/download/"); if (index > 0) { /* Download requested, handle the download */ String str = sreq.getParameter(FILE_ID_PARAM_NAME); s_log.debug("Downloading"); if (str != null) { BigDecimal id = new BigDecimal(str); s_log.debug("requesting file for id: "+str); Document doc = new Document(id); sresp.setHeader("Content-Disposition", "attachment; filename=" + URLDecoder.decode(doc.getName())); doc.assertPrivilege(PrivilegeDescriptor.READ); // if the user has requested an earlier revision, get // that revision and serve it String param = sreq.getParameter("transID"); if (param != null) { Session ssn = SessionManager.getSession(); TransactionContext txn = ssn.getTransactionContext(); txn.addTransactionListener(new AbstractTransactionListener() { @Override public void beforeCommit(TransactionContext txn) { Assert.fail("uncommittable transaction"); } }); Kernel.getContext().getTransaction().setCommitRequested(false); BigInteger transID = new BigInteger(param); Versions.rollback(doc.getOID(), transID); } FileAsset file = doc.getFile(); sresp.setContentType( null != file.getMimeType() ? file.getMimeType().getMimeType() : "text/plain" ); OutputStream os = null; try { os = sresp.getOutputStream(); file.writeBytes(os); } catch (IOException iox) { iox.printStackTrace(); throw new RuntimeException(iox.getMessage()); } finally { try { //is.close(); os.close(); } catch(IOException iox2) { } } } } else { /* No download, show the repository index page */ s_log.debug("show repository page"); String pathInfo = sreq.getPathInfo(); Assert.exists(pathInfo, "String pathInfo"); if (pathInfo.length() > 1 && pathInfo.endsWith("/")) { /* NOTE: ServletAPI specifies, pathInfo may be empty or will * start with a '/' character. It currently carries a * trailing '/' if a "virtual" page, i.e. not a real jsp, but * result of a servlet mapping. But Application requires url * NOT to end with a trailing '/' for legacy free applications.*/ pathInfo = pathInfo.substring(0, pathInfo.length()-1); } final Page page = (Page) m_pages.get(pathInfo); if (page != null) { final com.arsdigita.xml.Document doc = page.buildDocument(sreq, sresp); PresentationManager pm = Templating.getPresentationManager(); pm.servePage(doc, sreq, sresp); } else { // TODO: Check JSP's first (cf. cms content-section servlet) sresp.sendError(404, "No such page for path " + pathInfo); } } if (s_log.isDebugEnabled()) s_log.info("completed doService method"); } /** * Adds one Url-Page mapping to the internal mapping table. * * @param pathInfo url stub for a page to display * @param page Page object to display */ protected void addPage(final String pathInfo, final Page page) { Assert.exists(pathInfo, String.class); Assert.exists(page, Page.class); // Current Implementation requires pathInfo to start with a leading '/' // SUN Servlet API specifies: "PathInfo *may be empty* or will start // with a '/' character." Assert.isTrue(pathInfo.startsWith("/"), "path starts not with '/'"); m_pages.put(pathInfo, page); } /** * Build index page for the document manager, */ private Page buildRepositoryIndexPage() { Page p = new DocmgrBasePage(); /* Create main administration tab. */ TabbedPane tb = new TabbedPane(); tb.setIdAttr("page-body"); //tb.addTab(WS_BROWSE_TITLE, new BrowsePane()); /* * Disable Repositories tab because * Still need to decide what to do with mounting * repository, since repository are now application. * tb.addTab(WS_REPOSITORIES_TITLE, new RepositoryPane()); */ p.add(new BrowsePane()); p.lock(); return p; } /** * Build page for the administration of one file. */ protected Page buildFileInfoPage() { final BigDecimalParameter fileIDParam = new BigDecimalParameter(FILE_ID_PARAM_NAME); DocmgrBasePage p = new DocmgrBasePage(fileIDParam) { // need to override this to show the File name @Override protected void buildTitle() { Label title = new Label(); title.addPrintListener(new com.arsdigita.bebop.event.PrintListener() { public void prepare(PrintEvent e) { PageState state = e.getPageState(); Label t = (Label) e.getTarget(); BigDecimal fid = (BigDecimal) state.getValue(fileIDParam); if (fid!=null) { t.setLabel(DMUtils.getFile(fid).getTitle()); } } }); setTitle(title); } @Override protected void buildContextBar() { FileDimensionalNavbar navbar = new FileDimensionalNavbar( new RequestLocal() { @Override protected Object initialValue(PageState state) { BigDecimal id = (BigDecimal) state.getValue(fileIDParam); return new Document(id); } }); navbar.setClassAttr("portalNavbar"); getHeader().add(navbar); } }; // need to add the file parameter to the page //BigDecimalParameter FILE_ID_PARAM = new BigDecimalParameter(FILE_ID_PARAM_NAME); //p.addGlobalStateParam(fileIDParam); /* Temporary fix to sdm #204233, NavBar of Application allows only one URL per application, so here we add a Link back to the parent folder */ Label backLinkLabel = new Label (new GlobalizedMessage("ui.fileinfo.goback.label", BUNDLE_NAME)); backLinkLabel.addPrintListener(new PrintListener() { public void prepare(PrintEvent e) { PageState state = e.getPageState(); Label t= (Label) e.getTarget(); String fixed = t.getLabel(e.getPageState()); String url = Web.getWebContext().getApplication().getTitle(); t.setLabel(fixed + " " + url); }}); ActionLink backLink = new ActionLink(backLinkLabel); backLink.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { PageState state = e.getPageState(); String url = Web.getWebContext().getApplication().getPath(); BigDecimal fid = (BigDecimal) state.getValue(fileIDParam); if (fid != null) { url = url + "?d_id="+fid; } /* BigDecimal pid = null; BigDecimal fid = (BigDecimal) state.getValue(FILE_ID_PARAM); if (fid!=null) { pid = DMUtils.getFile(fid).getParentResource().getID(); } */ try { DispatcherHelper.sendRedirect(state.getRequest(), state.getResponse(), url); } catch (IOException iox) { throw new RuntimeException("Redirect to Application failed" +iox); } }}); backLink.setClassAttr("actionLink"); p.add(backLink); // create main File-Info tabs TabbedPane tb = new TabbedPane(); tb.setIdAttr("page-body"); tb.addTab(FILE_INFO_PROPERTIES_TITLE, new FileInfoPropertiesPane(p)); // TODO - comment in tb.addTab(FILE_INFO_HISTORY_TITLE, new FileInfoHistoryPane(p)); /* * Disable Links tab because we have not * decided how to link other KnItems to a document. * 01/04/02 Stefan Deusch * tb.addTab(FILE_INFO_LINKS_TITLE, new FileInfoLinksPane()); */ p.add(tb); p.lock(); return p; } /** * Build search page for the document manager, */ protected Page buildSearchPage() { Page p = new DocmgrBasePage(); /** * Create main administration tab. */ TabbedPane tb = new TabbedPane(); tb.setIdAttr("page-body"); //tb.addTab(WS_BROWSE_TITLE, new BrowsePane()); /* * Disable Repositories tab because * Still need to decide what to do with mounting * repository, since repository are now application. * tb.addTab(WS_REPOSITORIES_TITLE, new RepositoryPane()); */ p.add(new SearchPane()); p.lock(); return p; } }