diff --git a/ccm-cms/src/com/arsdigita/cms/ContentItem.java b/ccm-cms/src/com/arsdigita/cms/ContentItem.java index ed192181a..313e794c2 100755 --- a/ccm-cms/src/com/arsdigita/cms/ContentItem.java +++ b/ccm-cms/src/com/arsdigita/cms/ContentItem.java @@ -1320,6 +1320,11 @@ public class ContentItem extends VersionedACSObject implements CustomCopy { Assert.isTrue(isLive(), "Attempt to republish non live item " + getOID()); + //ToDo Remove item from cache + if (CMSConfig.getInstance().getEnableXmlCache()) { + XMLDeliveryCache.getInstance().removeFromCache(getOID()); + } + Lifecycle cycle = getLifecycle(); Assert.exists(cycle, Lifecycle.class); //resets lifecycle if opted diff --git a/ccm-cms/src/com/arsdigita/cms/DomainCopier.java b/ccm-cms/src/com/arsdigita/cms/DomainCopier.java index 44ea76a78..bd43d541d 100755 --- a/ccm-cms/src/com/arsdigita/cms/DomainCopier.java +++ b/ccm-cms/src/com/arsdigita/cms/DomainCopier.java @@ -46,11 +46,11 @@ import java.util.Iterator; */ class DomainCopier extends DomainService { - private static Logger s_log = Logger.getLogger(DomainCopier.class); + private static final Logger s_log = Logger.getLogger(DomainCopier.class); // A map of OID => DomainObject private final HashMap m_copied; protected final TraversedSet m_traversed; - final Tracer m_trace; + protected final Tracer m_trace; /** * Constructs a new DomainCopier @@ -127,7 +127,7 @@ class DomainCopier extends DomainService { } } - protected void copyData(final DomainObject source, DomainObject target) { + protected void copyData(final DomainObject source, final DomainObject target) { final ObjectType type = source.getObjectType(); if (s_log.isDebugEnabled()) { @@ -295,11 +295,12 @@ class DomainCopier extends DomainService { } else if (prop.isRequired()) { s_log.debug("The property is a 1..1 association"); - final DataObject data = (DataObject) get(source, name); + final DataObject data = (DataObject) get(source, name); Assert.exists(data, DataObject.class); final DomainObject domain = domain(data); + checkXmlCache(domain); m_traversed.add(domain, prop.getAssociatedProperty()); @@ -307,12 +308,13 @@ class DomainCopier extends DomainService { } else if (prop.isNullable()) { s_log.debug("The property is a 0..1 association"); - final DataObject data = (DataObject) get(source, name); + final DataObject data = (DataObject) get(source, name); if (data == null) { set(target, name, null); } else { final DomainObject domain = domain(data); + checkXmlCache(domain); m_traversed.add(domain, prop.getAssociatedProperty()); @@ -362,6 +364,7 @@ class DomainCopier extends DomainService { m_traversed.add(selem, reverse); final DomainObject telem = copy(source, target, selem, prop); + checkXmlCache(telem); DataObject tgtLink = null; @@ -469,16 +472,31 @@ class DomainCopier extends DomainService { return contains(object.getOID() + "." + prop.getName()); } + } protected final class WrapperDomainObject extends DomainObject { - public WrapperDomainObject(DataObject dobj) { + public WrapperDomainObject(final DataObject dobj) { super(dobj); } - public WrapperDomainObject(OID oid) { + public WrapperDomainObject(final OID oid) { super(oid); } + } + + /** + * Helper method for invalidating the cached XML of associated objects when an item is (re-)published. + * + * @param dobj + */ + private void checkXmlCache(final DomainObject dobj) { + if ((dobj instanceof ContentItem) && CMSConfig.getInstance().getEnableXmlCache()) { + final ContentItem item = (ContentItem) dobj; + XMLDeliveryCache.getInstance().removeFromCache(item.getOID()); + } + } + } diff --git a/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleXMLGenerator.java b/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleXMLGenerator.java index 2c163fdc7..bfb133ae4 100755 --- a/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleXMLGenerator.java +++ b/ccm-cms/src/com/arsdigita/cms/dispatcher/SimpleXMLGenerator.java @@ -19,7 +19,6 @@ package com.arsdigita.cms.dispatcher; import com.arsdigita.bebop.PageState; -import com.arsdigita.caching.CacheTable; import com.arsdigita.cms.CMS; import com.arsdigita.cms.CMSConfig; import com.arsdigita.cms.ContentItem; @@ -27,6 +26,7 @@ import com.arsdigita.cms.ContentItemXMLRenderer; import com.arsdigita.cms.ExtraXMLGenerator; import com.arsdigita.cms.SecurityManager; import com.arsdigita.cms.UserDefinedContentItem; +import com.arsdigita.cms.XMLDeliveryCache; import com.arsdigita.cms.util.GlobalizationUtil; import com.arsdigita.domain.DataObjectNotFoundException; import com.arsdigita.domain.DomainObjectFactory; @@ -42,7 +42,6 @@ import com.arsdigita.persistence.OID; import com.arsdigita.persistence.metadata.Property; import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.xml.Element; -import java.util.HashMap; import org.apache.log4j.Logger; import java.util.Iterator; import java.util.LinkedHashMap; @@ -84,17 +83,6 @@ public class SimpleXMLGenerator implements XMLGenerator { */ private String itemElemName = "cms:item"; private String itemElemNs = CMS.CMS_XML_NS; - //Cache for generated XML - private static final CacheTable CACHE = new CacheTable( - SimpleXMLGenerator.class.getName() + "Cache", - CMSConfig.getInstance().getXmlCacheSize(), - CMSConfig.getInstance().getXmlCacheAge(), - true); - //Stores the master ID of the cached items and the ID of cached version. Used to delete obsolete entries in the - //cash after republishing - private static final Map CACHED_ITEMS = new HashMap(); - //private static final Map cache = new HashMap(); - //private static final boolean USE_CACHE = false; // Register general purpose adaptor for all content items static { @@ -201,29 +189,14 @@ public class SimpleXMLGenerator implements XMLGenerator { // This is the preferred method //final Element content = startElement(useContext, parent); - final Element content; - if (CMSConfig.getInstance().getEnableXmlCache() && (CACHE.get(item.getOID().toString()) != null)) { - s_log.debug("Item found in cache, using cached XML"); - final Element cached = (Element) CACHE.get(item.getOID().toString()); - //parent.importElement(content); - cached.syncDocs(); + final Element content = startElement(useContext); + s_log.debug("Item is not in cache, generating item."); - content = startElement(useContext); - final Iterator entries = cached.getAttributes().entrySet().iterator(); - Map.Entry entry; - while (entries.hasNext()) { - entry = (Map.Entry) entries.next(); - content.addAttribute((String) entry.getKey(), (String) entry.getValue()); - } - final Iterator childs = cached.getChildren().iterator(); - while (childs.hasNext()) { - copyElement(content, (Element) childs.next()); - } + final XMLDeliveryCache xmlCache = XMLDeliveryCache.getInstance(); + + if (CMSConfig.getInstance().getEnableXmlCache() && xmlCache.isCached(item.getOID(), useContext, listMode)) { + xmlCache.retrieveFromCache(content, item.getOID(), useContext, listMode); } else { - s_log.debug("Item is not in cache, generating item."); - - content = startElement(useContext); - final ContentItemXMLRenderer renderer = new ContentItemXMLRenderer(content); renderer.setWrapAttributes(true); @@ -241,72 +214,35 @@ public class SimpleXMLGenerator implements XMLGenerator { //parent.addContent(content); - if (CMSConfig.getInstance().getEnableXmlCache()) { - validateCache(item); - } - - //Only published items - //Only the XML of the item itself, no extra XML - if (CMSConfig.getInstance().getEnableXmlCache() && item.isLiveVersion()) { - s_log.debug("Putting item item into the cache."); - final Element cachedElem = startCachedElement(useContext); - final Iterator entries = content.getAttributes().entrySet().iterator(); - Map.Entry entry; - while (entries.hasNext()) { - entry = (Map.Entry) entries.next(); - cachedElem.addAttribute((String) entry.getKey(), (String) entry.getValue()); - } - final Iterator childs = content.getChildren().iterator(); - while (childs.hasNext()) { - //cachedElem.newChildElement((Element) childs.next()); - copyElement(cachedElem, (Element) childs.next()); - } - CACHE.put(item.getOID().toString(), cachedElem); - } - } - //Only item XML Cache End + //Only item XML Cache End // s_log.debug("Content elem content: "); // logElementTree(content); // s_log.debug("Content elem content end -- "); - /* - * 2011-08-27 jensp: Introduced to remove the annoying special templates - * for MultiPartArticle, SiteProxy and others. The method called - * here was already definied but not used. - * - * 2011-10-23 jensp: It is now possible to disable the use of - * extra XML. - */ - //final long extraXMLStart = System.nanoTime(); - if (useExtraXml) { - for (ExtraXMLGenerator generator : item.getExtraXMLGenerators()) { - generator.setListMode(listMode); - generator.generateXML(item, content, state); + /* + * 2011-08-27 jensp: Introduced to remove the annoying special templates + * for MultiPartArticle, SiteProxy and others. The method called + * here was already definied but not used. + * + * 2011-10-23 jensp: It is now possible to disable the use of + * extra XML. + */ + //final long extraXMLStart = System.nanoTime(); + if (useExtraXml) { + for (ExtraXMLGenerator generator : item.getExtraXMLGenerators()) { + generator.setListMode(listMode); + generator.generateXML(item, content, state); + } + } + + //Only published items + //Only the XML of the item itself, no extra XML + if (CMSConfig.getInstance().getEnableXmlCache() && item.isLiveVersion()) { + xmlCache.cache(item.getOID(), item, content, useContext, listMode); } } -// System.out. -// printf("Rendered ExtraXML in %d ms\n", (System.nanoTime() - extraXMLStart) / 1000000); -// System.out.printf(" -----\n"); - - //Complete cache begin -// if (CMSConfig.getInstance().getEnableXmlCache() && item.isLiveVersion()) { -// final Element cachedElem = startElement(useContext); -// final Iterator entries = content.getAttributes().entrySet().iterator(); -// Map.Entry entry; -// while (entries.hasNext()) { -// entry = (Map.Entry) entries.next(); -// cachedElem.addAttribute((String) entry.getKey(), (String) entry.getValue()); -// } -// final Iterator childs = content.getChildren().iterator(); -// while (childs.hasNext()) { -// cachedElem.newChildElement((Element) childs.next()); -// } -// CACHE.put(item.getOID().toString(), cachedElem); -// } -// } - //complete cache end if (PermissionService.checkPermission(edit)) { final ItemResolver resolver = item.getContentSection().getItemResolver(); @@ -506,20 +442,4 @@ public class SimpleXMLGenerator implements XMLGenerator { return builder.toString(); } - private void validateCache(final ContentItem item) { - if (item.isDraftVersion()) { - //Draft version are not cached - return; - } - final String itemId = item.getOID().toString(); - final String masterId = item.getDraftVersion().getOID().toString(); - - final String cachedId = CACHED_ITEMS.get(masterId); - if ((cachedId != null) - && !cachedId.equals(itemId)) { - CACHE.remove(cachedId); - } - - } - } diff --git a/ccm-core/src/com/arsdigita/ui/admin/AdminServlet.java b/ccm-core/src/com/arsdigita/ui/admin/AdminServlet.java index 945ea958d..1b3957e8b 100644 --- a/ccm-core/src/com/arsdigita/ui/admin/AdminServlet.java +++ b/ccm-core/src/com/arsdigita/ui/admin/AdminServlet.java @@ -16,7 +16,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - package com.arsdigita.ui.admin; import com.arsdigita.bebop.Page; @@ -47,55 +46,55 @@ import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; - /** - * Web Developer Support Application Servlet class, central entry point to - * create and process the applications UI. - * - * We should have subclassed BebopApplicationServlet but couldn't overwrite - * doService() method to add permission checking. So we use our own page - * mapping. The general logic is the same as for BebopApplicationServlet. - * {@see com.arsdigita.bebop.page.BebopApplicationServlet} - * + * Web Developer Support Application Servlet class, central entry point to create and process the applications UI. + * + * We should have subclassed BebopApplicationServlet but couldn't overwrite doService() method to add permission + * checking. So we use our own page mapping. The general logic is the same as for BebopApplicationServlet. + * { + * + * @see com.arsdigita.bebop.page.BebopApplicationServlet} + * * @author pb */ -public class AdminServlet extends BaseApplicationServlet - implements AdminConstants{ +public class AdminServlet extends BaseApplicationServlet + implements AdminConstants { - /** Logger instance for debugging */ + /** + * Logger instance for debugging + */ private static final Logger s_log = Logger.getLogger( - AdminServlet.class.getName()); - - /** URL (pathinfo) -> Page object mapping. Based on it (and the http - * request url) the doService method to selects a page to display */ + AdminServlet.class.getName()); + /** + * URL (pathinfo) -> Page object mapping. Based on it (and the http request url) the doService method to selects a + * page to display + */ private final Map m_pages = new HashMap(); - /** * User extension point, overwrite this method to setup a URL - page mapping - * - * @throws ServletException + * + * @throws ServletException */ @Override public void doInit() throws ServletException { addPage("/", buildAdminIndexPage()); // index page at address ~/ds - // addPage("/index.jsp", buildIndexPage()); // index page at address ~/ds + // addPage("/index.jsp", buildIndexPage()); // index page at address ~/ds } - /** - * Central service method, checks for required permission, determines the - * requested page and passes the page object to PresentationManager. + * Central service method, checks for required permission, determines the requested page and passes the page object + * to PresentationManager. */ public final void doService(HttpServletRequest sreq, HttpServletResponse sresp, Application app) - throws ServletException, IOException { + throws ServletException, IOException { + + - - // /////// Some preparational steps /////////////// /* Determine access privilege: only logged in users may access DS */ @@ -104,8 +103,7 @@ public class AdminServlet extends BaseApplicationServlet throw new LoginSignal(sreq); } /* Determine access privilege: Admin privileges must be granted */ - PermissionDescriptor admin = new PermissionDescriptor - (PrivilegeDescriptor.ADMIN, app, party); + PermissionDescriptor admin = new PermissionDescriptor(PrivilegeDescriptor.ADMIN, app, party); if (!PermissionService.checkPermission(admin)) { throw new AccessDeniedException("User is not an administrator"); } @@ -123,7 +121,7 @@ public class AdminServlet extends BaseApplicationServlet * 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); + pathInfo = pathInfo.substring(0, pathInfo.length() - 1); } final Page page = (Page) m_pages.get(pathInfo); @@ -140,13 +138,12 @@ public class AdminServlet extends BaseApplicationServlet sresp.sendError(404, "No such page for path " + pathInfo); } - - } + } /** * Adds one pair of Url - Page to the internal hash map, used as a cache. - * + * * @param pathInfo url stub for a page to display * @param page Page object to display */ @@ -171,11 +168,11 @@ public class AdminServlet extends BaseApplicationServlet p.addGlobalStateParam(USER_ID_PARAM); p.addGlobalStateParam(GROUP_ID_PARAM); - // p.addGlobalStateParam(APPLICATIONS_ID_PARAM); + p.addGlobalStateParam(APPLICATIONS_ID_PARAM); /* Create User split panel. */ AdminSplitPanel userSplitPanel = - new AdminSplitPanel(USER_NAVBAR_TITLE); + new AdminSplitPanel(USER_NAVBAR_TITLE); UserBrowsePane browsePane = new UserBrowsePane(); @@ -187,19 +184,19 @@ public class AdminServlet extends BaseApplicationServlet new UserSearchPane(userSplitPanel, browsePane)); userSplitPanel.addTab(USER_TAB_CREATE_USER, new CreateUserPane(userSplitPanel)); - - + + /* * Create group administration panel */ - GroupAdministrationTab groupAdministrationTab = + GroupAdministrationTab groupAdministrationTab = new GroupAdministrationTab(); - + /* * Create group administration panel */ - // ApplicationsAdministrationTab appsAdministrationTab = - // new ApplicationsAdministrationTab(); + ApplicationsAdministrationTab appsAdministrationTab = + new ApplicationsAdministrationTab(); // Create the Admin's page tab bar, currently 2 elements: user & groups TabbedPane tb = new TabbedPane(); @@ -207,19 +204,15 @@ public class AdminServlet extends BaseApplicationServlet tb.addTab(USER_TAB_TITLE, userSplitPanel); tb.addTab(GROUP_TAB_TITLE, groupAdministrationTab); - // tb.addTab(APPLICATIONS_TAB_TITLE, appsAdministrationTab); + tb.addTab(APPLICATIONS_TAB_TITLE, appsAdministrationTab); browsePane.setTabbedPane(tb); browsePane.setGroupAdministrationTab(groupAdministrationTab); - // browsePane.setAppsAdministrationTab(appsAdministrationTab); + //browsePane.setAppsAdministrationTab(appsAdministrationTab); p.add(tb); p.lock(); return p; } - - - } - diff --git a/ccm-core/src/com/arsdigita/ui/admin/ApplicationsAdministrationTab.java b/ccm-core/src/com/arsdigita/ui/admin/ApplicationsAdministrationTab.java index 0f420fc5e..107ed8394 100644 --- a/ccm-core/src/com/arsdigita/ui/admin/ApplicationsAdministrationTab.java +++ b/ccm-core/src/com/arsdigita/ui/admin/ApplicationsAdministrationTab.java @@ -5,22 +5,36 @@ package com.arsdigita.ui.admin; import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.SplitPanel; +import com.arsdigita.bebop.Table; import com.arsdigita.bebop.event.ChangeEvent; import com.arsdigita.bebop.event.ChangeListener; +import com.arsdigita.bebop.event.TableActionEvent; +import com.arsdigita.bebop.event.TableActionListener; +import com.arsdigita.bebop.table.TableCellRenderer; +import com.arsdigita.bebop.table.TableColumn; +import com.arsdigita.bebop.table.TableColumnModel; +import com.arsdigita.bebop.table.TableModel; +import com.arsdigita.bebop.table.TableModelBuilder; import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.util.LockableImpl; +import com.arsdigita.web.Application; +import com.arsdigita.web.ApplicationCollection; /** * * @author pb + * @author Jens Pelzetter */ public class ApplicationsAdministrationTab extends BoxPanel - implements AdminConstants, ChangeListener { + implements AdminConstants, ChangeListener { private GlobalizedMessage m_title; - /** * Constructor */ @@ -29,35 +43,214 @@ public class ApplicationsAdministrationTab extends BoxPanel // m_title = "TEST für ein neues Pannel"; setClassAttr("sidebarNavPanel"); setAttribute("navbar-title", "Sitemap"); - // m_componentList = new ArrayList(); - // m_keys = new ArrayList(); + // m_componentList = new ArrayList(); + // m_keys = new ArrayList(); - BoxPanel box = new BoxPanel(); + final BoxPanel box = new BoxPanel(); box.setClassAttr("main"); - SplitPanel panel = new SplitPanel(); + final SplitPanel panel = new SplitPanel(); panel.setClassAttr("sidebarNavPanel"); panel.setRightComponent(box); - + box.add(new ApplicationsTable()); + + add(panel); } - - /** - * - * @param e + + /** + * + * @param e */ + @Override public void stateChanged(ChangeEvent e) { PageState ps = e.getPageState(); - // String key = (String) m_tree.getSelectedKey(ps); + // String key = (String) m_tree.getSelectedKey(ps); // added cg - reset existing group add panel to the search screen // when a new group is selected from the tree - // ps.setValue(GROUP_ID_PARAM, new BigDecimal(key)); - // int selectedIndex = Integer.parseInt((String) m_list.getSelectedKey(ps)); - // setTab(selectedIndex, ps); + // ps.setValue(GROUP_ID_PARAM, new BigDecimal(key)); + // int selectedIndex = Integer.parseInt((String) m_list.getSelectedKey(ps)); + // setTab(selectedIndex, ps); } + private class ApplicationsTable extends Table implements TableActionListener { + + private static final String COL_APP_CLASS = "col_app_class"; + private static final String COL_APP_TYPE = "col_app_type"; + private static final String COL_APP_VIEW_URL = "col_app_view_url"; + private static final String COL_APP_ADMIN_URL = "col_app_admin_url"; + private static final String COL_APP_SINGLETON = "col_app_singleton"; + + public ApplicationsTable() { + super(); + + setEmptyView(new Label("No applications installed.")); + + final TableColumnModel colModel = getColumnModel(); + colModel.add(new TableColumn( + 0, + "App Class", + COL_APP_CLASS)); + colModel.add(new TableColumn( + 1, + "App Type", + COL_APP_TYPE)); + colModel.add(new TableColumn( + 2, + "App View URL", + COL_APP_VIEW_URL)); + colModel.add(new TableColumn( + 3, + "Is Singleton?", + COL_APP_SINGLETON)); + + setModelBuilder(new ApplicationsTableModelBuilder()); + + colModel.get(0).setCellRenderer(new TableCellRenderer() { + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + return new Label(value.toString()); + } + + }); + + colModel.get(1).setCellRenderer(new TableCellRenderer() { + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + return new Label(value.toString()); + } + + }); + + colModel.get(2).setCellRenderer(new TableCellRenderer() { + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + return new Link(value.toString(), value.toString()); + } + + }); + + colModel.get(3).setCellRenderer(new TableCellRenderer() { + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + return new Label(value.toString()); + } + + }); + + addTableActionListener(this); + + } + + private class ApplicationsTableModelBuilder extends LockableImpl implements TableModelBuilder { + + @Override + public TableModel makeModel(final Table table, final PageState state) { + return new ApplicationsTableModel(table); + } + + } + + private class ApplicationsTableModel implements TableModel { + + private final Table table; + private final ApplicationCollection apps; + private Application app; + + public ApplicationsTableModel(final Table table) { + this.table = table; + + apps = Application.retrieveAllApplications(); + apps.addOrder("objectType"); + } + + @Override + public int getColumnCount() { + return table.getColumnModel().size(); + } + + @Override + public boolean nextRow() { + boolean ret; + + if ((apps != null) && apps.next()) { + app = apps.getApplication(); + ret = true; + } else { + ret = false; + } + + return ret; + } + + @Override + public Object getElementAt(final int columnIndex) { + switch (columnIndex) { + case 0: + return String.format("%s (%s)", app.getObjectType().getName(), app.getClass().getName()); + case 1: + return app.getApplicationType().getTitle(); + case 2: + return app.getPath(); + case 3: + return Boolean.toString(app.getApplicationType().isSingleton()); + default: + return null; + } + } + + @Override + public Object getKeyAt(final int columnIndex) { + return app.getID(); + } + + private String constructAppPath(final Application app) { + if (app.getParentApplication() == null) { + return app.getPath(); + } else { + return String.format("%s/%s", constructAppPath(app.getParentApplication()), app.getPath()); + } + } + + } + + @Override + public void cellSelected(final TableActionEvent event) { + //Nothing for now + } + + @Override + public void headSelected(final TableActionEvent event) { + //Nothing for now + } + + } } diff --git a/ccm-core/src/com/arsdigita/web/Application.java b/ccm-core/src/com/arsdigita/web/Application.java index 11621abbd..5a42f4147 100755 --- a/ccm-core/src/com/arsdigita/web/Application.java +++ b/ccm-core/src/com/arsdigita/web/Application.java @@ -68,17 +68,14 @@ public class Application extends Resource { /** Logger instance for debugging. */ private static final Logger s_log = Logger.getLogger(Application.class); - /** PDL property, basic object type for all applications of this type */ public static final String BASE_DATA_OBJECT_TYPE = "com.arsdigita.web.Application"; /** PDL property, the applications base URL. */ public static final String PRIMARY_URL = "primaryURL"; - /** Internal String to denote a Path delimiter. */ private static final String SLASH = "/"; - /** * Provides the base object type. */ @@ -124,13 +121,13 @@ public class Application extends Resource { * without parent and without an explicit URL fragment */ public static Application createRootApplication( - final ApplicationType type, - final String title, - final boolean createContainerGroup) { + final ApplicationType type, + final String title, + final boolean createContainerGroup) { if (Assert.isEnabled()) { Assert.exists(type, ApplicationType.class); Assert.exists(title, String.class); - // Assert.isTrue(type.m_legacyFree); + // Assert.isTrue(type.m_legacyFree); } return Application.make(type, null, title, null, createContainerGroup); @@ -151,7 +148,7 @@ public class Application extends Resource { final String title, final Application parent) { s_log.debug("Create Application"); - return Application.createApplication(type,fragment,title,parent,false); + return Application.createApplication(type, fragment, title, parent, false); } // For convenience. @@ -168,7 +165,7 @@ public class Application extends Resource { final String title, final Application parent) { - return Application.createApplication(typeName,fragment,title,parent,false); + return Application.createApplication(typeName, fragment, title, parent, false); } /** @@ -181,20 +178,20 @@ public class Application extends Resource { * @return */ public static Application createApplication( - final String typeName, - final String fragment, - final String title, - final Application parent, - final boolean createContainerGroup) { + final String typeName, + final String fragment, + final String title, + final Application parent, + final boolean createContainerGroup) { final ApplicationType type = ApplicationType - .retrieveApplicationTypeForApplication( - typeName); + .retrieveApplicationTypeForApplication( + typeName); if (type == null) { throw new IllegalArgumentException( - "No ApplicationType found for type name " + typeName); + "No ApplicationType found for type name " + typeName); } - return Application.createApplication(type,fragment, - title,parent,createContainerGroup); + return Application.createApplication(type, fragment, + title, parent, createContainerGroup); } /** @@ -211,20 +208,20 @@ public class Application extends Resource { * @return */ public static Application createApplication( - final ApplicationType type, - final String fragment, - final String title, - final Application parent, - final boolean createContainerGroup) { + final ApplicationType type, + final String fragment, + final String title, + final Application parent, + final boolean createContainerGroup) { if (Assert.isEnabled()) { Assert.exists(type, ApplicationType.class); Assert.exists(fragment, String.class); Assert.exists(title, String.class); Assert.isTrue(!fragment.equals(""), - "The URL fragment must not be the empty string"); + "The URL fragment must not be the empty string"); } - return Application.make(type,fragment,title,parent, + return Application.make(type, fragment, title, parent, createContainerGroup); } @@ -243,17 +240,16 @@ public class Application extends Resource { final String title, final Application parent, final boolean createContainerGroup) { - - final Application app = (Application) Resource.createResource(type, - title, - parent); + + final Application app = (Application) Resource.createResource(type, + title, + parent); if (createContainerGroup) { app.createGroup(); } if (Assert.isEnabled() && fragment != null) { Assert.isTrue(fragment.indexOf('/') == -1, - "The URL fragment must not contain " + - "slashes; I got '" + fragment + "'"); + "The URL fragment must not contain " + "slashes; I got '" + fragment + "'"); } /* Problem with "slash or not slash" @@ -285,7 +281,6 @@ public class Application extends Resource { return app; } - /** * * @param id @@ -338,8 +333,7 @@ public class Application extends Resource { Assert.exists(obj, ACSObject.class); ACSObject result = obj.gimmeContainer(); - while (result != null && - !(result instanceof Application)) { + while (result != null && !(result instanceof Application)) { result = result.gimmeContainer(); } @@ -355,7 +349,7 @@ public class Application extends Resource { s_log.debug("retrieveApplicationForPath: " + path); DataCollection dataCollection = - SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE); + SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE); dataCollection.addEqualsFilter(PRIMARY_URL, path); @@ -364,7 +358,7 @@ public class Application extends Resource { dataCollection.close(); return Application.retrieveApplication(dataObject); } else { - s_log.debug("retrieveApplicationForPath: No application found on " + path); + s_log.debug("retrieveApplicationForPath: No application found on " + path); return null; } } @@ -372,7 +366,6 @@ public class Application extends Resource { // /////////////////////// // Association properties // /////////////////////// - /** * * @return (Cannot return null.) @@ -445,14 +438,12 @@ public class Application extends Resource { * @param applicationType * @return */ - public ApplicationCollection getChildApplicationsForType - (String applicationType) { + public ApplicationCollection getChildApplicationsForType(String applicationType) { ApplicationCollection children = getChildApplications(); children.addEqualsFilter("objectType", applicationType); return children; } - // Can return null. /** * @deprecated Use {@link @@ -471,7 +462,6 @@ public class Application extends Resource { // ////////////////// // Member properties // ////////////////// - /** * Returns the path to this application through the dispatcher. * This path ends in a slash. Returns null if the @@ -526,26 +516,26 @@ public class Application extends Resource { public final void setPath(String path) { if (Assert.isEnabled()) { Assert.exists(path, String.class); -/* Modified by pboy April 2011 - * This Assert statement prevents a trailing slash. setPath is currently called - * only by Applicatiom#make which creates a LEGACY FREE application. - * Legacy compatible applications are currently created WITH a trailing slash - * (see e.g. SiteNode#setURL oder SiteNode#getURLFromParent.) Therefore for the - * time beeing if we must support legacy free and legacy compatible applications - * in parallel we have to use a trailing slash for legacy free applications, - * otherwise they will not be found by methods like retrieveApplicationForPath() - * which is called by legacy compatible apps including a trailing slash. If - * legacy free apps are stored without trailing slash the search will never match. - * The same is true as long as we mix old style dispatcher code with new style - * servlet code. - */ + /* Modified by pboy April 2011 + * This Assert statement prevents a trailing slash. setPath is currently called + * only by Applicatiom#make which creates a LEGACY FREE application. + * Legacy compatible applications are currently created WITH a trailing slash + * (see e.g. SiteNode#setURL oder SiteNode#getURLFromParent.) Therefore for the + * time beeing if we must support legacy free and legacy compatible applications + * in parallel we have to use a trailing slash for legacy free applications, + * otherwise they will not be found by methods like retrieveApplicationForPath() + * which is called by legacy compatible apps including a trailing slash. If + * legacy free apps are stored without trailing slash the search will never match. + * The same is true as long as we mix old style dispatcher code with new style + * servlet code. + */ // Assert.isTrue // (path.equals("") || (path.startsWith(SLASH) // && !path.endsWith(SLASH)), // "The path must either be the empty string (for the " + // "default application) or it must start with '/' and *not* " + // "end in '/'; I got '" + path + "'"); - } + } set(PRIMARY_URL, path); } @@ -560,33 +550,30 @@ public class Application extends Resource { */ public static ApplicationCollection retrieveAllApplications() { DataCollection dataCollection = - SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE); + SessionManager.getSession().retrieve(BASE_DATA_OBJECT_TYPE); // exclude all portlets (no application at all) and portal panes // (no application but sort of "sub-application"). - dataCollection.addEqualsFilter - ("resourceType.hasFullPageView", Boolean.TRUE); - - ApplicationCollection apps = new ApplicationCollection - (dataCollection); + dataCollection.addEqualsFilter("resourceType.hasFullPageView", Boolean.TRUE); + + ApplicationCollection apps = new ApplicationCollection(dataCollection); return apps; } + /** * Retrieve all installed applications (portlets excluded). * @return a collection of installed */ - public static ApplicationCollection retrieveAllApplications(String - applicationType) { + public static ApplicationCollection retrieveAllApplications(String applicationType) { DataCollection dataCollection = SessionManager.getSession() - .retrieve(BASE_DATA_OBJECT_TYPE); + .retrieve(BASE_DATA_OBJECT_TYPE); // exclude all portlets (no application at all) and portal panes // (no application but sort of "sub-application"). - dataCollection.addEqualsFilter - ("resourceType.hasFullPageView", Boolean.TRUE); + dataCollection.addEqualsFilter("resourceType.hasFullPageView", Boolean.TRUE); dataCollection.addEqualsFilter("objectType", applicationType); - + ApplicationCollection apps = new ApplicationCollection(dataCollection); return apps; @@ -598,10 +585,10 @@ public class Application extends Resource { * @param path * @return */ - public static boolean isInstalled (String applicationObjectType, - String path) { + public static boolean isInstalled(String applicationObjectType, + String path) { DataCollection dataCollection = - SessionManager.getSession().retrieve(applicationObjectType); + SessionManager.getSession().retrieve(applicationObjectType); dataCollection.addEqualsFilter(PRIMARY_URL, path); @@ -621,7 +608,7 @@ public class Application extends Resource { * */ public static String getCanonicalURL(String url) { - + String canonicalURL; url = url.trim(); // Remove whitespace @@ -629,7 +616,7 @@ public class Application extends Resource { canonicalURL = url.startsWith(SLASH) ? url : (SLASH + url); canonicalURL = url.endsWith(SLASH) ? canonicalURL : (canonicalURL + SLASH); - return canonicalURL ; + return canonicalURL; } /** @@ -697,15 +684,15 @@ public class Application extends Resource { @Override public void beforeDelete() { super.beforeDelete(); - // SiteNode node = getSiteNode(); - // if (node != null) { - // node.delete(); - // } + // SiteNode node = getSiteNode(); + // if (node != null) { + // node.delete(); + // } } /** * - */ + */ @Override public void afterDelete() { BaseDispatcher.scheduleRefresh(); @@ -737,7 +724,7 @@ public class Application extends Resource { */ public void createGroup() { Assert.isEqual(getGroup(), null, - "Group has already been created for Application " + getTitle()); + "Group has already been created for Application " + getTitle()); Group group = new Group(); group.setName(getTitle() + " Groups"); @@ -756,7 +743,6 @@ public class Application extends Resource { } - /** * . * @@ -765,7 +751,7 @@ public class Application extends Resource { * @param title */ @Override - public void setTitle (String title) { + public void setTitle(String title) { super.setTitle(title); Group containerGroup = getGroup(); if (containerGroup != null) { @@ -781,7 +767,7 @@ public class Application extends Resource { */ public Group getGroup() { return (Group) DomainObjectFactory.newInstance( - (DataObject) get("containerGroup")); + (DataObject) get("containerGroup")); } } diff --git a/ccm-navigation/src/com/arsdigita/navigation/DataCollectionRenderer.java b/ccm-navigation/src/com/arsdigita/navigation/DataCollectionRenderer.java index 0f2e861f0..3860525d4 100755 --- a/ccm-navigation/src/com/arsdigita/navigation/DataCollectionRenderer.java +++ b/ccm-navigation/src/com/arsdigita/navigation/DataCollectionRenderer.java @@ -152,11 +152,14 @@ public class DataCollectionRenderer extends LockableImpl { Assert.isLocked(this); int pageNumber = pageNum; + + final long objectCount = objects.size(); // Quasimodo: Begin // If objects is null or empty, do not insert objectList-element // but do insert noContent-element and return immediately - if (objects == null || objects.isEmpty()) { + //if (objects == null || objects.isEmpty()) { + if (objects == null || (objectCount == 0)) { return Navigation.newElement("noContent"); } // Quasimodo: End @@ -171,7 +174,7 @@ public class DataCollectionRenderer extends LockableImpl { return content; } - final long objectCount = objects.size(); + final int pageCount = (int) Math.ceil((double) objectCount / (double) m_pageSize); if (pageNumber < 1) { diff --git a/ccm-navigation/src/com/arsdigita/navigation/cms/CMSDataCollectionRenderer.java b/ccm-navigation/src/com/arsdigita/navigation/cms/CMSDataCollectionRenderer.java index 8726fe987..42926f3c7 100755 --- a/ccm-navigation/src/com/arsdigita/navigation/cms/CMSDataCollectionRenderer.java +++ b/ccm-navigation/src/com/arsdigita/navigation/cms/CMSDataCollectionRenderer.java @@ -18,9 +18,11 @@ package com.arsdigita.navigation.cms; import com.arsdigita.bebop.PageState; +import com.arsdigita.cms.CMSConfig; import com.arsdigita.cms.ContentItem; import com.arsdigita.cms.ContentItemXMLRenderer; import com.arsdigita.cms.ExtraXMLGenerator; +import com.arsdigita.cms.XMLDeliveryCache; import com.arsdigita.cms.dispatcher.ItemResolver; import com.arsdigita.domain.DomainObjectFactory; import com.arsdigita.kernel.ACSObject; @@ -69,45 +71,79 @@ public class CMSDataCollectionRenderer extends DataCollectionRenderer { ACSObject obj, int index) { if (obj != null) { - ContentItemXMLRenderer renderer = new ContentItemXMLRenderer(item); - renderer.setRevisitFullObject(false); - renderer.setWrapAttributes(true); - renderer.setWrapRoot(false); - renderer.setWrapObjects(false); - //renderer.walk(obj, SimpleXMLGenerator.ADAPTER_CONTEXT); + if (CMSConfig.getInstance().getEnableXmlCache() + && (obj instanceof ContentItem) + && XMLDeliveryCache.getInstance().isCached(obj.getOID())) { + + XMLDeliveryCache.getInstance().retrieveFromCache(item, obj.getOID()); + + createEditLink(item, (ContentItem) obj); + + } else { + + ContentItemXMLRenderer renderer = new ContentItemXMLRenderer(item); + renderer.setRevisitFullObject(false); + renderer.setWrapAttributes(true); + renderer.setWrapRoot(false); + renderer.setWrapObjects(false); + //renderer.walk(obj, SimpleXMLGenerator.ADAPTER_CONTEXT); /* jensp 2011-01-03: - * I needed the option to use different traversal adapters for - * the object in the detail view and the list view. It is now - * possible to set the adapter context used from a JSP template, - * using DataCollectionRenderer#setSpecializeObjectsContext(String). - */ - renderer.walk(obj, getSpecializeObjectsContext()); + * I needed the option to use different traversal adapters for + * the object in the detail view and the list view. It is now + * possible to set the adapter context used from a JSP template, + * using DataCollectionRenderer#setSpecializeObjectsContext(String). + */ + renderer.walk(obj, getSpecializeObjectsContext()); - if ((obj instanceof ContentItem) && useExtraXml) { - final ContentItem contentItem = (ContentItem) obj; + if ((obj instanceof ContentItem) && useExtraXml) { + final ContentItem contentItem = (ContentItem) obj; - for (ExtraXMLGenerator generator : contentItem.getExtraListXMLGenerators()) { - generator.setListMode(true); - generator.generateXML(contentItem, item, null); - } + for (ExtraXMLGenerator generator : contentItem.getExtraListXMLGenerators()) { + generator.setListMode(true); + generator.generateXML(contentItem, item, null); + } + + XMLDeliveryCache.getInstance().cache(contentItem.getOID(), contentItem, item, "", false); - Party currentParty = Kernel.getContext().getParty(); - if (currentParty == null) { - currentParty = Kernel.getPublicUser(); - } - final PermissionDescriptor edit = new PermissionDescriptor(PrivilegeDescriptor.get( - com.arsdigita.cms.SecurityManager.CMS_EDIT_ITEM), contentItem, currentParty); - if (PermissionService.checkPermission(edit)) { - final ItemResolver resolver = contentItem.getContentSection().getItemResolver(); - final Element editLinkElem = item.newChildElement("editLink"); - final ContentItem draftItem = contentItem.getDraftVersion(); - editLinkElem.setText(resolver.generateItemURL(PageState.getPageState(), - draftItem, - contentItem.getContentSection(), - draftItem.getVersion())); + createEditLink(item, contentItem); + +// Party currentParty = Kernel.getContext().getParty(); +// if (currentParty == null) { +// currentParty = Kernel.getPublicUser(); +// } +// +// final PermissionDescriptor edit = new PermissionDescriptor(PrivilegeDescriptor.get( +// com.arsdigita.cms.SecurityManager.CMS_EDIT_ITEM), contentItem, currentParty); +// if (PermissionService.checkPermission(edit)) { +// final ItemResolver resolver = contentItem.getContentSection().getItemResolver(); +// final Element editLinkElem = item.newChildElement("editLink"); +// final ContentItem draftItem = contentItem.getDraftVersion(); +// editLinkElem.setText(resolver.generateItemURL(PageState.getPageState(), +// draftItem, +// contentItem.getContentSection(), +// draftItem.getVersion())); +// } } } } } + private void createEditLink(final Element item, final ContentItem contentItem) { + Party currentParty = Kernel.getContext().getParty(); + if (currentParty == null) { + currentParty = Kernel.getPublicUser(); + } + + final PermissionDescriptor edit = new PermissionDescriptor(PrivilegeDescriptor.get( + com.arsdigita.cms.SecurityManager.CMS_EDIT_ITEM), contentItem, currentParty); + if (PermissionService.checkPermission(edit)) { + final ItemResolver resolver = contentItem.getContentSection().getItemResolver(); + final Element editLinkElem = item.newChildElement("editLink"); + final ContentItem draftItem = contentItem.getDraftVersion(); + editLinkElem.setText(resolver.generateItemURL(PageState.getPageState(), + draftItem, + contentItem.getContentSection(), + draftItem.getVersion())); + } + } } diff --git a/ccm-navigation/src/com/arsdigita/navigation/ui/AbstractObjectList.java b/ccm-navigation/src/com/arsdigita/navigation/ui/AbstractObjectList.java index adaa6f2e9..9b13f8af5 100755 --- a/ccm-navigation/src/com/arsdigita/navigation/ui/AbstractObjectList.java +++ b/ccm-navigation/src/com/arsdigita/navigation/ui/AbstractObjectList.java @@ -93,6 +93,7 @@ public abstract class AbstractObjectList public Element generateObjectListXML(HttpServletRequest request, HttpServletResponse response) { + final long start = System.nanoTime(); Assert.isLocked(this); String pageNumberValue = request.getParameter("pageNumber"); @@ -107,9 +108,13 @@ public abstract class AbstractObjectList throw new UncheckedWrapperException( "cannot parse page number " + pageNumber, ex); } - + + final long loadObjectsStart = System.nanoTime(); DataCollection objects = getObjects(request, response); + ////System.out.printf("Got objects for list in %d ms\n", (System.nanoTime() - loadObjectsStart) / 1000000); + ////System.out.printf("(100) Needed %d ms until here...\n", (System.nanoTime() - start) / 1000000); + // Quasimodo: Begin // Limit list to objects in the negotiated language and language invariant items if (objects != null && objects.size() > 0) { @@ -130,8 +135,15 @@ public abstract class AbstractObjectList } } // Quasimodo: End + ////System.out.printf("(200) Needed %d ms until here...\n", (System.nanoTime() - start) / 1000000); - return m_renderer.generateXML(objects, pageNumber.intValue()); + //final long renderStart = System.nanoTime(); + final Element listXML = m_renderer.generateXML(objects, pageNumber.intValue()); + //System.out.printf("Rendered items of list in %d ms\n", (System.nanoTime() - renderStart) / 1000000); + + //System.out.printf("Generated object list in %d ms\n", (System.nanoTime() - start) / 1000000); + + return listXML; } } diff --git a/ccm-sci-personalpublications/src/com/arsdigita/cms/publicpersonalprofile/PersonalPublications.java b/ccm-sci-personalpublications/src/com/arsdigita/cms/publicpersonalprofile/PersonalPublications.java index ce955a5e3..2ed30e4c9 100644 --- a/ccm-sci-personalpublications/src/com/arsdigita/cms/publicpersonalprofile/PersonalPublications.java +++ b/ccm-sci-personalpublications/src/com/arsdigita/cms/publicpersonalprofile/PersonalPublications.java @@ -211,6 +211,7 @@ public class PersonalPublications implements ContentGenerator { List publicationList = publications; Collections.sort(publicationList, new Comparator() { + @Override public int compare(final PublicationBundle bundle1, final PublicationBundle bundle2) { final Publication publication1 = bundle1.getPublication(GlobalizationHelper.getNegotiatedLocale(). getLanguage()); diff --git a/ccm-sci-publications/src/com/arsdigita/cms/contenttypes/ui/PublicationExtraXmlGenerator.java b/ccm-sci-publications/src/com/arsdigita/cms/contenttypes/ui/PublicationExtraXmlGenerator.java index 2383e2fab..c4ce178e8 100644 --- a/ccm-sci-publications/src/com/arsdigita/cms/contenttypes/ui/PublicationExtraXmlGenerator.java +++ b/ccm-sci-publications/src/com/arsdigita/cms/contenttypes/ui/PublicationExtraXmlGenerator.java @@ -31,6 +31,7 @@ public class PublicationExtraXmlGenerator implements ExtraXMLGenerator { public void generateXML(final ContentItem item, final Element element, final PageState state) { + final long start = System.nanoTime(); if (!(item instanceof Publication)) { throw new IllegalArgumentException(String.format( "ExtraXMLGenerator '%s' only supports items of type '%s'.", @@ -40,7 +41,13 @@ public class PublicationExtraXmlGenerator implements ExtraXMLGenerator { final Publication publication = (Publication) item; createAuthorsXml(publication, element, state); + System.out.printf("[%s] Created authors XML in %d ms\n", + PublicationExtraXmlGenerator.class.getName(), + (System.nanoTime() - start) / 1000000); createSeriesXml(publication, element, state); + System.out.printf("[%s] Created series XML in %d ms\n", + PublicationExtraXmlGenerator.class.getName(), + (System.nanoTime() - start) / 1000000); if (!listMode) { createOrgaUnitsXml(publication, element, state); @@ -50,15 +57,22 @@ public class PublicationExtraXmlGenerator implements ExtraXMLGenerator { createExportLink(format, element, (Publication) item, state); } } + System.out.printf("[%s] Created extra XML in %d ms\n", + PublicationExtraXmlGenerator.class.getName(), + (System.nanoTime() - start) / 1000000); } private void createAuthorsXml(final Publication publication, final Element parent, final PageState state) { + final long start = System.nanoTime(); final AuthorshipCollection authors = publication.getAuthors(); if ((authors == null) || authors.isEmpty()) { return; } + System.out.printf("[%s#createAuthorsXML] Got authors in %d ms\n", + PublicationExtraXmlGenerator.class.getName(), + (System.nanoTime() - start) / 1000000); final Element authorsElem = parent.newChildElement("authors"); while (authors.next()) { @@ -68,6 +82,9 @@ public class PublicationExtraXmlGenerator implements ExtraXMLGenerator { authorsElem, state); } + System.out.printf("[%s#createAuthorsXML] Created XML for authors in %d ms\n", + PublicationExtraXmlGenerator.class.getName(), + (System.nanoTime() - start) / 1000000); } private void createAuthorXml(final GenericPerson author, @@ -75,12 +92,17 @@ public class PublicationExtraXmlGenerator implements ExtraXMLGenerator { final Integer order, final Element authorsElem, final PageState state) { + final long start = System.nanoTime(); final XmlGenerator generator = new XmlGenerator(author); generator.setItemElemName("author", ""); generator.addItemAttribute("isEditor", isAuthor.toString()); generator.addItemAttribute("order", order.toString()); generator.setListMode(listMode); generator.generateXML(state, authorsElem, ""); + System.out.printf("[%s] Created XML for author %s in %d ms\n", + PublicationExtraXmlGenerator.class.getName(), + author.getTitle(), + (System.nanoTime() - start) / 1000000); } private void createOrgaUnitsXml(final Publication publication,