CCM NG: Current progress of porting the ItemSearch forms to NG

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4495 8810af33-2d31-482b-a856-94f89814c4df

Former-commit-id: 31884ea9e3
pull/2/head
jensp 2016-12-20 18:37:35 +00:00
parent 2ce77fb924
commit ea1900d8dc
18 changed files with 2007 additions and 26 deletions

View File

@ -56,6 +56,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -56,6 +56,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -56,6 +56,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -56,6 +56,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -56,6 +56,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -56,6 +56,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -56,6 +56,12 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -22,27 +22,26 @@ import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Resettable;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.search.QuerySpecification;
import com.arsdigita.search.ui.QueryGenerator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* A wrapper around the {@link ItemSearchSection} which embedds
* the form section in a form.
* A wrapper around the {@link ItemSearchSection} which embeds the form section
* in a form.
*
* @author Stanislav Freidin (sfreidin@arsdigita.com)
* @version $Id: ItemSearch.java 1940 2009-05-29 07:15:05Z terry $
* @author <a href="jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ItemSearch extends Form implements Resettable, QueryGenerator {
public class ItemSearch extends Form implements Resettable {
private static final org.apache.log4j.Logger s_log =
org.apache.log4j.Logger.getLogger(ItemSearch.class);
private static final Logger LOGGER = LogManager.getLogger(ItemSearch.class);
public static final String SINGLE_TYPE_PARAM = ItemSearchSection.SINGLE_TYPE_PARAM;
private ItemSearchSection m_section;
private ItemSearchSection itemSearchSection;
/**
* Construct a new <code>ItemSearch</code> component
* Default to limit the search to current content section
* Construct a new <code>ItemSearch</code> component Default to limit the
* search to current content section
*
* @param context the context for the retrieved items. Should be
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
@ -56,31 +55,33 @@ public class ItemSearch extends Form implements Resettable, QueryGenerator {
*
* @param context the context for the retrieved items. Should be
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
* @param limitToContentSection limit the search to the current content section
* @param limitToContentSection limit the search to the current content
* section
*/
public ItemSearch(String context, boolean limitToContentSection) {
super("itemSearch", new SimpleContainer());
//setMethod("GET");
m_section = createSearchSection(context, limitToContentSection);
add(m_section);
itemSearchSection = createSearchSection(context, limitToContentSection);
add(itemSearchSection);
}
protected ItemSearchSection createSearchSection(String context, boolean limitToContentSection) {
protected ItemSearchSection createSearchSection(String context,
boolean limitToContentSection) {
return new ItemSearchSection(context, limitToContentSection);
}
@Override
public boolean hasQuery(PageState state) {
return m_section.hasQuery(state);
return itemSearchSection.hasQuery(state);
}
@Override
public QuerySpecification getQuerySpecification(PageState state) {
return m_section.getQuerySpecification(state);
return itemSearchSection.getQuerySpecification(state);
}
@Override
public void reset(PageState state) {
m_section.reset(state);
itemSearchSection.reset(state);
}
}

View File

@ -0,0 +1,395 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.ui;
import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.Resettable;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.SingleSelectionModel;
import com.arsdigita.bebop.Tree;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.ChangeEvent;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.bebop.event.TreeExpansionEvent;
import com.arsdigita.bebop.event.TreeExpansionListener;
import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.form.SingleSelect;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.cms.dispatcher.Utilities;
import com.arsdigita.cms.CMS;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder;
import com.arsdigita.cms.ui.authoring.NewItemForm;
import com.arsdigita.cms.ui.folder.FolderRequestLocal;
import com.arsdigita.cms.ui.folder.FolderSelectionModel;
import com.arsdigita.cms.ui.folder.FolderTreeModelBuilder;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.toolbox.ui.LayoutPanel;
import com.arsdigita.util.Assert;
import java.math.BigDecimal;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.arsdigita.cms.CMSConfig;
import org.librecms.CmsConstants;
import org.librecms.contentsection.ContentSectionConfig;
/**
* A pane that contains a folder tree on the left and a folder manipulator on
* the right.
*
* @author David LutterKort &lt;dlutter@redhat.com&gt;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ItemSearchBrowsePane extends SimpleContainer implements Resettable,
TreeExpansionListener,
ChangeListener,
FormProcessListener,
FormSubmissionListener {
private static final String CONTENT_TYPE_ID = "ct";
private static final Logger LOGGER = LogManager.getLogger(
ItemSearchBrowsePane.class);
private final FolderSelectionModel folderSelectionModel;
private final FolderRequestLocal folderRequestLocal;
private final Tree tree;
private ItemSearchFolderBrowser folderBrowser;
private SingleSelect sectionSelect;
private SingleSelectionModel typeSelectionModel;
public ItemSearchBrowsePane() {
final LayoutPanel mainPanel = new LayoutPanel();
setClassAttr("sidebarNavPanel");
setAttribute("navbar-title",
new GlobalizedMessage("cms.ui.folder_browser",
CmsConstants.CMS_BUNDLE)
.localize().toString());
final BoxPanel left = new BoxPanel(BoxPanel.VERTICAL);
final Label label = new Label(new GlobalizedMessage(
"cms.ui.folder_browser", CmsConstants.CMS_BUNDLE));
label.setClassAttr("heading");
left.add(label);
// As described in ticket 20540, some clients do not want the option to pick items from other
// subsites through the ItemSearchBrowsePane. A new parameter has been added to allow the
// administrator to pick between the old and new versions.
boolean linksOnlyInSameSubsite = CMSConfig.getConfig()
.isLinksOnlyInSameSubsite();
LOGGER.debug("linksOnlyInSameSubsite value is {}",
linksOnlyInSameSubsite);
tree = new Tree(new FolderTreeModelBuilder() {
@Override
protected Folder getRoot(PageState ps) {
Folder root = getRootFolder(ps);
if (null == root) {
return super.getRoot(ps);
}
return root;
}
});
folderSelectionModel = createFolderSelectionModel();
folderSelectionModel.addChangeListener(this);
folderRequestLocal = new FolderRequestLocal(folderSelectionModel);
if (!linksOnlyInSameSubsite) {
// The client should be able to pick between the subsites
Form sectionForm = getSectionForm();
add(sectionForm);
}
tree.setSelectionModel(folderSelectionModel);
tree.setClassAttr("navbar");
tree.addTreeExpansionListener(this);
left.add(tree);
// CMSContainer container = new CMSContainer();
left.setClassAttr("main");
final BoxPanel body = new BoxPanel(BoxPanel.VERTICAL);
folderBrowser = new ItemSearchFolderBrowser(folderSelectionModel);
body.add(folderBrowser);
body.add(folderBrowser.getPaginator());
// m_newItem = new SectionNewItemForm("newItem");
// m_typeSel = new ParameterSingleSelectionModel(new BigDecimalParameter(CONTENT_TYPE_ID));
// m_newItem.addProcessListener(this);
//
// container.add(m_newItem);
//add(container);
mainPanel.setLeft(left);
mainPanel.setBody(body);
add(mainPanel);
}
@Override
public boolean isVisible(PageState s) {
// Always expand root node
if (tree.isCollapsed(getRootFolder(s).getID().toString(), s)) {
tree.expand(getRootFolder(s).getID().toString(), s);
}
return super.isVisible(s);
}
private Form getSectionForm() {
Form sectionForm = new Form("isfbSectionForm",
new BoxPanel(BoxPanel.HORIZONTAL));
sectionForm.setClassAttr("navbar");
sectionSelect = new SingleSelect(new OIDParameter("isfbSection"));
ContentSectionCollection sections = ContentSection.getAllSections();
while (sections.next()) {
ContentSection section = sections.getContentSection();
sectionSelect.addOption(new Option(section.getOID().toString(),
section.getDisplayName()));
}
sectionForm.addInitListener(new FormInitListener() {
@Override
public void init(FormSectionEvent ev) {
PageState ps = ev.getPageState();
if (null == sectionSelect.getValue(ps)) {
ContentSection section = CMS.getContext().
getContentSection();
sectionSelect.setValue(ps, section.getOID());
}
}
});
sectionForm.add(sectionSelect);
sectionForm.add(new Submit("Change Section"));
return sectionForm;
}
private Folder getRootFolder(PageState ps) {
LOGGER.debug("Getting the root folder.");
if (sectionSelect != null) {
// We have more than one subsite to choose between
OID sectionOID = (OID) sectionSelect.getValue(ps);
if (LOGGER.isDebugEnabled()) {
if (null != sectionOID) {
LOGGER.debug("Using section " + sectionOID.toString());
} else {
LOGGER.debug("Using default section");
}
}
if (null == sectionOID) {
return null;
}
ContentSection section = (ContentSection) DomainObjectFactory.
newInstance(sectionOID);
return section.getRootFolder();
} else {
return null;
}
}
@Override
public void register(Page p) {
super.register(p);
p.addComponentStateParam(this, folderSelectionModel.getStateParameter());
// Only add the SingleSelect item if it exists
if (sectionSelect != null) {
p.addComponentStateParam(this, sectionSelect.getParameterModel());
}
// Save the state of the new item component
// p.addComponentStateParam(this, m_typeSel.getStateParameter());
p.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final PageState state = e.getPageState();
if (state.isVisibleOnPage(ItemSearchBrowsePane.this)) {
showHideSegments(state);
}
}
});
}
/**
* Show/hide segments based on access checks.
*
* @param state The page state
* @pre ( state != null )
*/
private void showHideSegments(PageState state) {
SecurityManager sm = Utilities.getSecurityManager(state);
Folder folder = folderRequestLocal.getFolder(state);
Assert.exists(folder);
// MP: This should be checked on the current folder instead of just
// the content section.
// boolean newItem =
// sm.canAccess(state.getRequest(), SecurityManager.NEW_ITEM, folder);
//
// if (!newItem) {
// browseMode(state);
// }
// m_newItem.setVisible(state, newItem);
}
@Override
public void reset(PageState s) {
//m_browser.reset(s);
}
public ItemSearchFolderBrowser getFolderBrowser() {
return folderBrowser;
}
public final FolderSelectionModel getFolderSelectionModel() {
return folderSelectionModel;
}
/**
* sets the current level of expansion of the folder tree and in the folder
* browser table
*/
protected void setSelectedFolder(PageState s, String key) {
//set the selected folder of the folder browser
folderBrowser.getFolderSelectionModel().setSelectedKey(s, key);
//set the selected folder of the folder tree
folderSelectionModel.setSelectedKey(s, key);
Folder current = (Folder) folderSelectionModel.getSelectedObject(s);
Folder parent = (Folder) current.getParent();
if (parent != null) {
BigDecimal id = parent.getID();
tree.expand(id.toString(), s);
}
}
// Implement TreeExpansionListener
@Override
public void treeCollapsed(TreeExpansionEvent e) {
PageState s = e.getPageState();
folderSelectionModel.setSelectedKey(s, e.getNodeKey());
}
@Override
public void treeExpanded(TreeExpansionEvent e) {
return;
}
@Override
public void stateChanged(ChangeEvent e) {
PageState s = e.getPageState();
Folder current = (Folder) folderSelectionModel.getSelectedObject(s);
Folder parent = (Folder) current.getParent();
folderBrowser.getPaginator().reset(s);
if (parent != null) {
BigDecimal id = parent.getID();
tree.expand(id.toString(), s);
}
//m_browser.getPermissionsPane().reset(s);
//m_browser.setPermissionLinkVis(s);
}
@Override
public void process(FormSectionEvent e) {
PageState s = e.getPageState();
final Object source = e.getSource();
// if (source == m_newItem) {
// BigDecimal typeID = m_newItem.getTypeID(s);
// m_typeSel.setSelectedKey(s, typeID);
// newItemMode(s);
// } else {
browseMode(s);
// }
}
@Override
public void submitted(FormSectionEvent e) {
PageState s = e.getPageState();
final Object source = e.getSource();
// if (source == m_newItem) {
// BigDecimal typeID = m_newItem.getTypeID(s);
// m_typeSel.setSelectedKey(s, typeID);
// //newItemMode(s);
// }
}
private void browseMode(PageState s) {
// m_browseSeg.setVisible(s, true);
typeSelectionModel.clearSelection(s);
}
private void newItemMode(PageState s) {
// m_newItemSeg.setVisible(s, true);
}
private FolderSelectionModel createFolderSelectionModel() {
return new FolderSelectionModel("folder") {
@Override
protected BigDecimal getRootFolderID(PageState ps) {
Folder root = getRootFolder(ps);
if (null == root) {
return super.getRootFolderID(ps);
}
return root.getID();
}
};
}
private static class SectionNewItemForm extends NewItemForm {
public SectionNewItemForm(String name) {
super(name);
}
@Override
public ContentSection getContentSection(PageState s) {
return CMS.getContext().getContentSection();
}
}
}

View File

@ -0,0 +1,494 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.ui;
import com.arsdigita.bebop.Bebop;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Link;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.RequestLocal;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.PaginationModelBuilder;
import com.arsdigita.bebop.Paginator;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.TableActionAdapter;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.table.AbstractTableModelBuilder;
import com.arsdigita.bebop.table.DefaultTableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentPage;
import com.arsdigita.cms.ContentSection;
import com.arsdigita.cms.ContentType;
import com.arsdigita.cms.Folder;
import com.arsdigita.cms.SecurityManager;
import com.arsdigita.cms.dispatcher.Utilities;
import com.arsdigita.cms.ui.folder.FolderSelectionModel;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.persistence.CompoundFilter;
import com.arsdigita.persistence.FilterFactory;
import com.arsdigita.toolbox.GlobalisationUtil;
import com.arsdigita.util.Assert;
import java.math.BigDecimal;
/**
* Browse folders and items. If the user clicks on a folder, the folder selection model is updated.
* If the user clicks on any other item, an separate item selection model is updated.
*
* @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
* @version $Revision: #9 $ $DateTime: 2004/08/17 23:15:09 $
*/
public class ItemSearchFolderBrowser extends Table {
private static final org.apache.log4j.Logger s_log = org.apache.log4j.Logger.getLogger(
ItemSearchFolderBrowser.class);
private static GlobalizedMessage[] s_headers = {
globalize("cms.ui.folder.name"),
globalize("cms.ui.folder.title"),
globalize("cms.ui.folder.type")};
private FolderSelectionModel m_currentFolder;
private TableActionListener m_folderChanger;
private TableActionListener m_deleter;
private TableActionListener m_indexChanger;
private TableColumn m_nameColumn;
private Paginator m_paginator;
public ItemSearchFolderBrowser(FolderSelectionModel currentFolder) {
super((FolderTableModelBuilder) null, s_headers);
FolderTableModelBuilder builder = new FolderTableModelBuilder();
setModelBuilder(builder);
m_paginator = new Paginator(builder, ContentSection.getConfig().
getFolderBrowseListSize());
m_currentFolder = currentFolder;
setClassAttr("dataTable");
getHeader().setDefaultRenderer(
new com.arsdigita.cms.ui.util.DefaultTableCellRenderer());
m_nameColumn = getColumn(0);
m_nameColumn.setCellRenderer(new NameCellRenderer());
m_folderChanger = new FolderChanger();
addTableActionListener(m_folderChanger);
setEmptyView(new Label(globalize("cms.ui.folder.no_items")));
Assert.exists(m_currentFolder.getStateParameter());
}
public Paginator getPaginator() {
return m_paginator;
}
@Override
public void register(Page p) {
super.register(p);
p.addComponentStateParam(this, m_currentFolder.getStateParameter());
p.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
// MP: This action listener should only be called when the
// folder browser is visible.
showHideFolderActions(event.getPageState());
}
});
}
private Folder getCurrentFolder(PageState state) {
return (Folder) m_currentFolder.getSelectedObject(state);
}
private void showHideFolderActions(PageState state) {
SecurityManager sm = Utilities.getSecurityManager(state);
Folder folder = getCurrentFolder(state);
Assert.exists(folder);
}
public FolderSelectionModel getFolderSelectionModel() {
return m_currentFolder;
}
private class FolderTableModelBuilder
extends AbstractTableModelBuilder implements PaginationModelBuilder {
private RequestLocal m_size = new RequestLocal() {
@Override
protected Object initialValue(PageState state) {
Folder.ItemCollection itemColl = getItemCollection(state);
if (null == itemColl) {
return new Integer(0);
}
return new Integer((int) itemColl.size());
}
};
private RequestLocal m_itemColl = new RequestLocal() {
@Override
protected Object initialValue(PageState state) {
Folder.ItemCollection itemColl = getItemCollection(state);
itemColl.addOrder("item.name");
itemColl.setRange(new Integer(m_paginator.getFirst(state)),
new Integer(m_paginator.getLast(state) + 1));
return itemColl;
}
};
public TableModel makeModel(Table t, PageState s) {
FolderSelectionModel sel = ((ItemSearchFolderBrowser) t).
getFolderSelectionModel();
Folder f = getCurrentFolder(s);
if (s_log.isDebugEnabled()) {
if (null == f) {
s_log.debug("Selected folder is null");
} else {
s_log.debug("Selected folder: " + f.getLabel() + " " + f.
getOID().toString());
}
}
if (f == null) {
return Table.EMPTY_MODEL;
} else {
t.getRowSelectionModel().clearSelection(s);
return new FolderTableModel((Folder.ItemCollection) m_itemColl.
get(s));
}
}
private Folder.ItemCollection getItemCollection(PageState state) {
Folder f = getCurrentFolder(state);
Folder.ItemCollection itemColl = f.getPrimaryInstances();
if (null == itemColl) {
return null;
}
BigDecimal singleTypeID = (BigDecimal) state.getValue(new BigDecimalParameter(
ItemSearch.SINGLE_TYPE_PARAM));
if (singleTypeID != null) {
// The Filter Factory
FilterFactory ff = itemColl.getFilterFactory();
// Create an or-filter
CompoundFilter or = ff.or();
// The content type must be either of the requested type
or.addFilter(ff.equals(ContentItem.CONTENT_TYPE + "."
+ ContentType.ID, singleTypeID));
// Or must be a sibling of the requested type
/*
* jensp 2011-11-14: The orginal code here was only traversing
* one level, but ContentType hierarchies may have several
* levels. Therefore, this code was replaced by method which is
* called recursivly until the type with no descendents is
* reached.
*/
createSiblingFilter(or, ff, singleTypeID);
/*try {
ContentType ct = new ContentType(singleTypeID);
StringTokenizer strTok = new StringTokenizer(ct.
getDescendants(), "/");
while (strTok.hasMoreElements()) {
or.addFilter(ff.equals(ContentItem.CONTENT_TYPE + "."
+ ContentType.ID,
(String) strTok.nextElement()));
}
} catch (Exception ex) {
// WTF? The selected content type does not exist in the table???
s_log.error(String.format(
"Something is very wrong here, the ContentType '%s' "
+ "seems not to exist. Ignoring for now, but please "
+ "make your checks.",
singleTypeID.toString()),
ex);
}*/
itemColl.addFilter(or);
}
itemColl.addOrder("isFolder desc");
itemColl.addOrder("lower(item." + ContentItem.NAME + ") ");
return itemColl;
}
private void createSiblingFilter(final CompoundFilter filter,
final FilterFactory filterFactory,
final BigDecimal typeId) {
final ContentType type = new ContentType(typeId);
if ((type.getDescendants() == null)
|| type.getDescendants().trim().isEmpty()) {
return;
} else {
final String[] descendantsIds = type.getDescendants().split("/");
for (String descendantId : descendantsIds) {
filter.addFilter(filterFactory.equals(String.format(
ContentItem.CONTENT_TYPE + "." + ContentType.ID),
descendantId));
createSiblingFilter(filter, filterFactory, descendantId);
}
}
}
private void createSiblingFilter(final CompoundFilter filter,
final FilterFactory filterFactory,
final String typeId) {
try {
final BigDecimal _typeId = new BigDecimal(typeId);
createSiblingFilter(filter, filterFactory, _typeId);
} catch (NumberFormatException ex) {
s_log.error(String.format("Failed to parse typeId '%s'.",
typeId),
ex);
}
}
public int getTotalSize(Paginator paginator, PageState state) {
Integer size = (Integer) m_size.get(state);
return size.intValue();
}
/**
* Indicates whether the paginator should be visible, based on the visibility of the folder
* browser itself and how many items are displayed
*
* @return true if folder browser is visible and there is more than 1 page of items, false
* otherwise
*/
public boolean isVisible(PageState state) {
int size = ((Integer) m_size.get(state)).intValue();
return ItemSearchFolderBrowser.this.isVisible(state)
&& (size
> ContentSection.getConfig().getFolderBrowseListSize());
}
}
/**
* Produce links to view an item or control links for folders to change into the folder.
*/
private class NameCellRenderer extends DefaultTableCellRenderer {
public NameCellRenderer() {
super(true);
}
@Override
public Component getComponent(Table table, PageState state,
Object value, boolean isSelected,
Object key, int row, int column) {
Folder.ItemCollection coll = (Folder.ItemCollection) value;
String name = coll.getName();
if (coll.isFolder()) {
return super.getComponent(table, state, name, isSelected, key,
row, column);
} else {
ContentSection section = CMS.getContext().getContentSection();
BigDecimal id = (BigDecimal) key;
if (section == null) {
return new Label(name);
} else {
//ItemResolver resolver = section.getItemResolver();
//String url =
//resolver.generateItemURL
//(state, id, name, section, coll.getVersion()));
SimpleContainer container = new SimpleContainer();
String widget = (String) state.getValue(new StringParameter(
ItemSearchPopup.WIDGET_PARAM));
String searchWidget = (String) state.getValue(
new StringParameter("searchWidget"));
boolean useURL = "true".equals(state.getValue(new StringParameter(
ItemSearchPopup.URL_PARAM)));
String fillString;
if (useURL) {
fillString = ItemSearchPopup.getItemURL(state.getRequest(),
coll.getDomainObject().getOID());
} else {
fillString = id.toString();// + " (" + name + ")";
}
String title = ((ContentPage) coll.getDomainObject()).getTitle();
Label js = new Label(
generateJSLabel(id, widget, searchWidget, fillString, title),
false);
container.add(js);
String url = "#";
Link link = new Link(name, url);
link.setClassAttr("title");
link.setOnClick("return fillItem" + id + "()");
container.add(link);
return container;
}
}
}
private String generateJSLabel(BigDecimal id, String widget, String searchWidget,
String fill, String title) {
StringBuilder buffer = new StringBuilder();
buffer.append(" <script language=javascript> ");
buffer.append(" <!-- \n");
buffer.append(" function fillItem").append(id).append("() { \n");
buffer.append(" window.opener.document.").append(widget).append(".value=\"").
append(fill).append("\";\n");
if (searchWidget != null) {
buffer.append(" window.opener.document.").append(searchWidget).append(".value=\"").
append(title.
replace("\"", "\\\"")).append("\";\n");
}
// set protocol to 'other' in FCKEditor, else relative url prepended by http://
if (Bebop.getConfig().getDHTMLEditor().equals(
BebopConstants.BEBOP_FCKEDITOR)) {
buffer.append(
" if(window.opener.document.getElementById('cmbLinkProtocol')) {\n");
buffer.append(
" window.opener.document.getElementById('cmbLinkProtocol').value=\"\";\n");
buffer.append(" }\n");
}
buffer.append(" self.close(); \n"
+ " return false; \n"
+ " } \n"
+ " --> \n"
+ " </script> ");
return buffer.toString();
}
}
/**
* Table model around ItemCollection
*/
private static class FolderTableModel implements TableModel {
private static final int NAME = 0;
private static final int TITLE = 1;
private static final int TYPE = 2;
private Folder.ItemCollection m_itemColl;
public FolderTableModel(Folder.ItemCollection itemColl) {
m_itemColl = itemColl;
}
public int getColumnCount() {
return 3;
}
public boolean nextRow() {
return m_itemColl != null ? m_itemColl.next() : false;
}
public Object getElementAt(int columnIndex) {
switch (columnIndex) {
case NAME:
return m_itemColl;
case TITLE:
return m_itemColl.getDisplayName();
case TYPE:
return m_itemColl.getTypeLabel();
default:
throw new IndexOutOfBoundsException("Column index "
+ columnIndex
+ " not in table model.");
}
}
public Object getKeyAt(int columnIndex) {
// Mark folders by using their negative ID (dirty, dirty)
return (m_itemColl.isFolder()) ? m_itemColl.getID().negate()
: m_itemColl.getID();
}
}
private class FolderChanger extends TableActionAdapter {
@Override
public void cellSelected(TableActionEvent e) {
PageState s = e.getPageState();
int col = e.getColumn().intValue();
if (m_nameColumn != getColumn(col)) {
return;
}
String key = (String) e.getRowKey();
if (key.startsWith("-")) {
clearSelection(s);
getFolderSelectionModel().setSelectedKey(s, key.substring(1));
m_paginator.reset(s);
}
}
}
/**
* Getting the GlobalizedMessage using a CMS Class targetBundle.
*
* @param key The resource key
*
* @pre ( key != null )
*/
private static GlobalizedMessage globalize(String key) {
//return FolderManipulator.globalize(key);
final GlobalisationUtil util = new GlobalisationUtil(
"com.arsdigita.cms."
+ "ui.folder.CMSFolderResources");
return util.globalize(key);
}
}

View File

@ -28,15 +28,12 @@ import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.BooleanParameter;
import com.arsdigita.bebop.parameters.IntegerParameter;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.cms.*;
import com.arsdigita.cms.dispatcher.CMSPage;
import com.arsdigita.cms.util.GlobalizationUtil;
import com.arsdigita.dispatcher.RequestContext;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.templating.PresentationManager;
import com.arsdigita.templating.Templating;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.web.Application;
import org.libreccm.web.CcmApplication;
import com.arsdigita.web.Web;
import com.arsdigita.xml.Document;

View File

@ -0,0 +1,202 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.ui;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.Container;
import com.arsdigita.bebop.Resettable;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.FormSection;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentType;
import com.arsdigita.cms.ui.search.ItemQueryComponent;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.search.ui.ResultsPane;
import com.arsdigita.search.ui.QueryGenerator;
import com.arsdigita.toolbox.ui.LayoutPanel;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.lucene.search.Query;
import org.librecms.CmsConstants;
/**
* Contains a form for specifying search parameters, as well as a
* {@link com.arsdigita.search.ui.ResultsPane} which will perform the search and
* display the results
*
* @author Stanislav Freidin (sfreidin@arsdigita.com)
* @version $Id: ItemSearchSection.java 1940 2009-05-29 07:15:05Z terry $
*/
public class ItemSearchSection extends FormSection implements Resettable,
QueryGenerator {
private static final Logger LOGGER = LogManager.getLogger(
ItemSearchSection.class);
public static final String SINGLE_TYPE_PARAM = "single_type";
private ItemQueryComponent itemQueryComponent;
private Component resultsComponent;
/**
* Construct a new <code>ItemSearchSection</code> component
*
* @param context the context for the retrieved items. Should be
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
* @param limitToContentSection limit the search to the current content
* section
*/
public ItemSearchSection(final String context,
final boolean limitToContentSection) {
this(null, context, limitToContentSection);
}
/**
* Construct a new <code>ItemSearchSection</code> component
*
* @param context the context for the retrieved items. Should be
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
* @param name The name of the search parameter for the particular
* FormSection
* @param limitToContentSection limit the search to the current content
* section
*/
public ItemSearchSection(final String name,
final String context,
final boolean limitToContentSection) {
this(name, context, limitToContentSection, null);
}
public ItemSearchSection(final String name,
final String context,
final boolean limitToContentSection,
final ContentType type) {
super(new SimpleContainer());
final String thisName;
if (name == null) {
thisName = "itemSearch";
} else {
thisName = name;
}
if (type == null) {
itemQueryComponent = createQueryGenerator(context,
limitToContentSection);
} else {
itemQueryComponent = createQueryGenerator(context,
limitToContentSection,
type);
}
resultsComponent = createResultsPane(itemQueryComponent);
LayoutPanel searchPanel = new LayoutPanel();
searchPanel.setLeft(itemQueryComponent);
searchPanel.setBody(resultsComponent);
this.add(searchPanel);
// addQueryGenerator(this);
// addResultsPane(this);
addFormListener();
setClassAttr("itemSearch");
}
@Override
public boolean hasQuery(final PageState state) {
return itemQueryComponent.hasQuery(state);
}
@Override
public Query getQuerySpecification(final PageState state) {
return itemQueryComponent.getQuerySpecification(state);
}
@Override
public void reset(final PageState state) {
resultsComponent.setVisible(state, false);
}
protected ItemQueryComponent createQueryGenerator(
final String context, final boolean limitToContentSection) {
return new ItemQueryComponent(context, limitToContentSection);
}
protected ItemQueryComponent createQueryGenerator(
final String context,
final boolean limitToContentSection,
final ContentType type) {
return new ItemQueryComponent(context, limitToContentSection, type);
}
protected Component createResultsPane(QueryGenerator generator) {
ResultsPane pane = new ResultsPane(generator);
pane.setRelativeURLs(true);
pane.setSearchHelpMsg(new GlobalizedMessage("cms.ui.search.help",
CmsConstants.CMS_BUNDLE));
pane.setNoResultsMsg(new GlobalizedMessage("cms.ui.search.no_results",
CmsConstants.CMS_BUNDLE));
return pane;
}
protected void addResultsPane(final Container container) {
container.add(resultsComponent);
}
protected void addQueryGenerator(final Container container) {
container.add(itemQueryComponent);
}
protected void processQuery(final PageState state) {
resultsComponent.setVisible(state, itemQueryComponent.hasQuery(state));
}
protected void addFormListener() {
addProcessListener(new SearchFormProcessListener());
}
// Hide results by default
@Override
public void register(final Page page) {
super.register(page);
page.setVisibleDefault(resultsComponent, false);
page.addGlobalStateParam(new BigDecimalParameter(SINGLE_TYPE_PARAM));
}
/**
* Displays the "keywords" and "content types" widgets
*/
private class SearchFormProcessListener implements FormProcessListener {
@Override
public void process(final FormSectionEvent event)
throws FormProcessException {
PageState s = event.getPageState();
processQuery(s);
}
}
}

View File

@ -0,0 +1,145 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.ui.search;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.form.Submit;
import org.libreccm.categorization.Category;
import com.arsdigita.cms.CMS;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentType;
import com.arsdigita.cms.ui.ContentSectionPage;
import com.arsdigita.search.ui.BaseQueryComponent;
import java.util.ArrayList;
import java.util.List;
/**
* This class provides a basic query form for CMS admin pages that automatically
* adds components for the maximal set of filters supported by the current
* search query engine.
*
* @author unknown
* @author Sören Bernstein <quasi@quasiweb.de>
* @author Jens Pelzetter (jens@jp-digital.de)
*/
public class ItemQueryComponent extends BaseQueryComponent {
private String context;
public ItemQueryComponent(final String context,
final boolean limitToContentSection) {
this(context, limitToContentSection, null);
}
public ItemQueryComponent(final String context,
final boolean limitToContentSection,
final ContentType type) {
this.context = context;
// add(new PermissionFilterComponent(
// SecurityManager.CMS_PREVIEW_ITEM));
//
// add(new SimpleCategoryFilterWidget() {
//
// @Override
// protected Category[] getRoots(PageState state) {
// Category[] roots;
// if (limitToContentSection == true && CMS.getContext().
// hasContentSection()) {
// ContentSection section = CMS.getContext().
// getContentSection();
// roots = new Category[]{section.getRootCategory()};
// } else {
// ContentSectionCollection sections =
// ContentSection.getAllSections();
// List cats = new ArrayList();
// while (sections.next()) {
// ContentSection section =
// sections.getContentSection();
// cats.add(section.getRootCategory());
// }
// roots =
// (Category[]) cats.toArray(new Category[cats.size()]);
// }
// return roots;
// }
// });
//
// if (type == null) {
// add(new ContentTypeFilterWidget() {
//
// @Override
// protected ContentSection getContentSection() {
// if (limitToContentSection == true && CMS.getContext().
// hasContentSection()) {
// return CMS.getContext().getContentSection();
// } else {
// return super.getContentSection();
// }
// }
// });
// } else {
// add(new ContentTypeFilterWidget(type) {
//
// @Override
// protected ContentSection getContentSection() {
// if (limitToContentSection == true && CMS.getContext().
// hasContentSection()) {
// return CMS.getContext().getContentSection();
// } else {
// return super.getContentSection();
// }
// }
// });
// }
//
// add(new VersionFilterComponent(context));
// if (limitToContentSection == true) {
// add(new ContentSectionFilterComponent());
// }
// add(new DateRangeFilterWidget(new LastModifiedDateFilterType(),
// LastModifiedDateFilterType.KEY));
// add(new DateRangeFilterWidget(new CreationDateFilterType(),
// CreationDateFilterType.KEY));
// add(new PartyFilterWidget(new CreationUserFilterType(),
// CreationUserFilterType.KEY));
// add(new PartyFilterWidget(new LastModifiedUserFilterType(),
// LastModifiedUserFilterType.KEY));
Submit submit =
new Submit(context + "_search",
ContentSectionPage.globalize("cms.ui.search"));
add(submit);
}
// private class LaunchDateFilterWidget extends DateRangeFilterWidget {
//
// public LaunchDateFilterWidget(FilterType type, String name) {
// super(type, name);
//
// }
//
// @Override
// public boolean isVisible(PageState state) {
// return !ContentSection.getConfig().getHideLaunchDate()
// && super.isVisible(state);
// }
// }
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.search;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public final class SearchConstants {
private SearchConstants() {
//Nothing
}
/**
* Constant for search XML namespace prefix
*/
public static final String XML_PREFIX = "search:";
/**
* Constant for search XML namespace URL
*/
public static final String XML_NS = "http://rhea.redhat.com/search/1.0";
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.search.ui;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormModel;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.globalization.Globalization;
import com.arsdigita.xml.Element;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.search.SearchConstants;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* This is a simple extension of the QueryComponent that provides management of
* the 'terms' parameter and uses FilterGenerators to populate a query
* specification
* <p>
* Typical use would be as follows:
* <pre>
* Form f = new Form("search");
* BaseQueryComponent q = new BaseQueryComponent();
* q.add(new ObjectTypeFilterComponent("com.arsdigita.kernel.User");
* q.add(new PermissionGenerator(PrivilegeDescriptor.READ));
* q.add(new Submit("Go"));
* f.add(q);
* </pre>
*/
public class BaseQueryComponent extends QueryComponent {
private static final Logger LOGGER = LogManager.getLogger(
BaseQueryComponent.class);
private Set filters;
private Form form;
private StringParameter termsParameter = new StringParameter("terms");
/**
* Creates a new query component
*/
public BaseQueryComponent() {
super("query");
filters = new HashSet();
}
@Override
public void register(final Page page) {
super.register(page);
}
@Override
public void register(final Form form, final FormModel formModel) {
LOGGER.debug("Adding {} to form model...", termsParameter.getName());
termsParameter.setPassIn(true);
formModel.addFormParam(termsParameter);
this.form = form;
}
/**
* Gets the current search terms
*
* @return
*/
@Override
protected String getTerms(final PageState state) {
final FormData formData = form.getFormData(state);
if (formData != null) {
final ParameterData data = formData.getParameter(termsParameter.
getName());
LOGGER.debug("Search terms were: {}", (String) data.getValue());
return (String) data.getValue();
} else {
return null;
}
}
/**
*
* @param state
* @param parent
*/
@Override
public void generateXML(final PageState state, final Element parent) {
final Element content = generateParent(parent);
final Element terms = new Element(SearchConstants.XML_PREFIX + "terms",
SearchConstants.XML_NS);
terms.addAttribute("param", termsParameter.getName());
terms.addAttribute("value",
Globalization.decodeParameter(
state.getRequest(),
termsParameter.getName()));
generateErrorXML(state, terms);
content.addContent(terms);
generateChildrenXML(state, content);
}
protected void generateErrorXML(final PageState state,
final Element parent) {
final FormData formData = form.getFormData(state);
if (formData == null) {
return;
}
final Iterator iterator = formData.getErrors(termsParameter.getName());
while (iterator.hasNext()) {
final Element error = new Element(
SearchConstants.XML_PREFIX + "error",
SearchConstants.XML_NS);
error.setText((String) ((GlobalizedMessage) iterator.next()).
localize(state.getRequest())
);
parent.addContent(error);
}
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.search.ui;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.search.SearchConstants;
import com.arsdigita.util.Assert;
import org.apache.lucene.search.Query;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.CcmObject;
import org.libreccm.search.SearchManager;
/**
* A base class for generating a query specification from the state. Subclasses
* must implement two methods, one for getting the query terms, the other for
* getting a set of filter specs.
*/
public abstract class QueryComponent extends SimpleContainer
implements QueryGenerator {
public QueryComponent(final String name) {
setTag(SearchConstants.XML_PREFIX + name);
setNamespace(SearchConstants.XML_NS);
}
/**
* Determine if a query specification is available
*
* @return true if the user has entered some search terms
*/
@Override
public boolean hasQuery(final PageState state) {
String terms = getTerms(state);
return (terms != null && !"".equals(terms));
}
/**
* Returns the current query specification
*/
@Override
public Query getQuerySpecification(final PageState state) {
final String terms = getTerms(state);
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final SearchManager searchManager = cdiUtil.
findBean(SearchManager.class);
final QueryBuilder queryBuilder = searchManager.createQueryBuilder(CcmObject.class);
return queryBuilder
.keyword().onFields("displayName", "summary", "description", "title")
.matching(terms)
.createQuery();
}
/**
* Returns the current query terms
*
* @param state
* @return the query terms, or null
*/
protected abstract String getTerms(PageState state);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.search.ui;
import com.arsdigita.bebop.PageState;
import org.apache.lucene.search.Query;
/**
* This interface provides the API for retrieving a query specification based on
* the current state. The ResultsPane component uses an instance of this class
* to retrieve the query spec and display a list of results
*
* @see com.arsdigita.search.ui.QueryComponent
* @see com.arsdigita.search.ui.ResultsPane
*/
public interface QueryGenerator {
/**
* Determines whether a query spec currently exists.
*
* @param state The current page state.
* @return true if a query spec is available.
*/
boolean hasQuery(PageState state);
/**
* Retrieves the current query spec. This method can only be called if
* hasQuery(state) returns true.
*
* @param state The current page.
* @return The query
*/
Query getQuerySpecification(PageState state);
}

View File

@ -0,0 +1,381 @@
/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* 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.search.ui;
import com.arsdigita.bebop.SimpleComponent;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.IntegerParameter;
import com.arsdigita.globalization.Globalization;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.search.SearchConstants;
import com.arsdigita.util.UncheckedWrapperException;
import org.libreccm.security.Party;
import com.arsdigita.xml.Element;
import com.arsdigita.xml.XML;
import com.arsdigita.web.URL;
import com.arsdigita.web.ParameterMap;
import com.arsdigita.web.Web;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.search.Query;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.CcmObject;
import org.libreccm.search.SearchManager;
public class ResultsPane extends SimpleComponent {
private static final Logger LOGGER = LogManager.getLogger(ResultsPane.class);
public static final int PAGE_SIZE = 10;
private final int pageSize = PAGE_SIZE;
private final QueryGenerator queryGenerator;
private IntegerParameter pageNumber;
private boolean relative;
//jensp 2014-03-04 Allow using classes to set a suitable info messages.
private GlobalizedMessage searchHelpMsg;
private GlobalizedMessage noResultsMsg;
public ResultsPane(final QueryGenerator query) {
pageNumber = new IntegerParameter("page");
relative = false;
this.queryGenerator = query;
}
/**
* Determines whether the links to the search results will be relative or
* absolute. The default is absolute.
*
* @param relative
*/
public void setRelativeURLs(final boolean relative) {
this.relative = relative;
}
public void setSearchHelpMsg(final GlobalizedMessage msg) {
searchHelpMsg = msg;
}
public void setNoResultsMsg(final GlobalizedMessage msg) {
noResultsMsg = msg;
}
@Override
public void generateXML(final PageState state, final Element parent) {
if (!queryGenerator.hasQuery(state)) {
LOGGER.debug("No query available, skipping XML generation");
final Element content = new Element(
SearchConstants.XML_PREFIX + "results",
SearchConstants.XML_NS);
final Element info = content.newChildElement("info");
if (searchHelpMsg == null) {
info.setText(
"To search for content items, please enter at least 3 letters into the search field. You can narrow the result by using additional parameters.");
} else {
//info.setText(GlobalizationUtil.globalize("cms.ui.search_help").localize().toString());
info.setText(searchHelpMsg.localize().toString());
}
parent.addContent(content);
return;
}
final Query spec = queryGenerator.getQuerySpecification(state);
final SearchManager searchManager = CdiUtil.createCdiUtil().findBean(
SearchManager.class);
final List<CcmObject> results = (List<CcmObject>) searchManager.
executeQuery(spec);
LOGGER.debug("Got result list with {} items.", results.size());
if (results.isEmpty()) {
final long objectCount = results.size();
final int pageCount = (int) Math.ceil((double) objectCount
/ (double) pageSize);
final Integer page = (Integer) pageNumber.transformValue(state.
getRequest());
int pageNum;
if (page == null) {
pageNum = 1;
} else if (page < 1) {
pageNum = 1;
} else if (page > pageCount) {
if (pageCount == 0) {
pageNum = 1;
} else {
pageNum = page;
}
} else {
pageNum = page;
}
final long begin = ((pageNum - 1) * pageSize);
final long count = Math.min(pageSize, (objectCount - begin));
final long end = begin + count;
final Iterator iterator = results
.subList((int) begin, (int) begin + (int) count)
.iterator();
final Element content = new Element(
SearchConstants.XML_PREFIX + "results",
SearchConstants.XML_NS);
exportAttributes(content);
LOGGER.debug("Paginator stats\n"
+ " page number: {}\n"
+ " page count.: {}\n"
+ " page size..: {}\n"
+ " begin......: {}\n"
+ " end........: {}\n"
+ " count : {}",
pageNum,
pageCount,
pageSize,
begin,
end,
objectCount);
content.addContent(generatePaginatorXML(state,
pageNumber.getName(),
pageNum,
pageCount,
pageSize,
begin,
end,
objectCount));
content.addContent(generateDocumentsXML(state, iterator));
parent.addContent(content);
} else {
// No search result, so we don't need a paginator, but we want
// to inform the user, that there are no results for this search
final Element content = new Element(
SearchConstants.XML_PREFIX + "results",
SearchConstants.XML_NS);
final Element info = content.newChildElement("info");
// info.setText(GlobalizationUtil.globalize("cms.ui.search_no_results").localize().toString());
if (noResultsMsg == null) {
info.setText("Sorry. Your search returned 0 results.");
} else {
info.setText(noResultsMsg.localize().toString());
}
parent.addContent(content);
}
}
protected Element generatePaginatorXML(final PageState state,
final String pageParam,
final int pageNumber,
final int pageCount,
final int pageSize,
final long begin,
final long end,
final long objectCount) {
final Element paginator = new Element(
SearchConstants.XML_PREFIX + "paginator",
SearchConstants.XML_NS);
final URL url = Web.getWebContext().getRequestURL();
final ParameterMap parameterMap = new ParameterMap();
final Iterator current = url.getParameterMap().keySet().iterator();
while (current.hasNext()) {
final String key = (String) current.next();
if (key.equals(pageParam)) {
continue;
}
parameterMap.setParameterValues(
key, decodeParameters(url.getParameterValues(key), state));
}
paginator.addAttribute("pageParam", this.pageNumber.getName());
paginator.addAttribute("baseURL", URL.there(url.getPathInfo(),
parameterMap).toString());
paginator.addAttribute("pageNumber", XML.format(pageNumber));
paginator.addAttribute("pageCount", XML.format(pageCount));
paginator.addAttribute("pageSize", XML.format(pageSize));
paginator.addAttribute("objectBegin", XML.format(begin + 1));
paginator.addAttribute("objectEnd", XML.format(end));
paginator.addAttribute("objectCount", XML.format(objectCount));
return paginator;
}
private String[] decodeParameters(final String[] parameters,
final PageState state) {
final String[] decoded = new String[parameters.length];
for (int i = 0; i < parameters.length; i++) {
decoded[i] = decodeParameter(parameters[i], state);
}
return decoded;
}
private String decodeParameter(final String parameter,
final PageState state) {
String re = state.getRequest().getParameter(
Globalization.ENCODING_PARAM_NAME);
if ((re == null) || (re.isEmpty())) {
re = Globalization.getDefaultCharset();
}
if ((parameter == null) || (parameter.isEmpty())) {
return parameter;
} else if (Globalization.getDefaultCharset(state.getRequest()).
equals(re)) {
return parameter;
} else {
try {
return new String(parameter.getBytes(Globalization.
getDefaultCharset(
state.getRequest())), re);
} catch (UnsupportedEncodingException ex) {
LOGGER.warn("Unsupported encoding.", ex);
return parameter;
}
}
}
protected Element generateDocumentsXML(final PageState state,
final Iterator<CcmObject> results) {
final Element documents = new Element(
SearchConstants.XML_PREFIX + "documents",
SearchConstants.XML_NS);
LOGGER.debug("Outputting documents");
while (results.hasNext()) {
final CcmObject doc = results.next();
LOGGER.debug("Current document {} {}",
doc.getObjectId(),
doc.getDisplayName());
documents.addContent(generateDocumentXML(state, doc));
}
return documents;
}
private Optional<String> getSummary(final CcmObject doc) {
final BeanInfo beanInfo;
try {
beanInfo = Introspector.getBeanInfo(doc.getClass());
} catch (IntrospectionException ex) {
throw new UncheckedWrapperException(ex);
}
final Optional<PropertyDescriptor> propertyDesc
= Arrays.stream(beanInfo.
getPropertyDescriptors())
.filter(descriptor -> {
return "description".equals(descriptor.getName())
|| "summary".equals(descriptor.
getName());
})
.findFirst();
if (propertyDesc.isPresent()) {
final Method readMethod = propertyDesc.get().getReadMethod();
final String summary;
try {
summary = (String) readMethod.invoke(doc);
} catch (IllegalAccessException
| IllegalArgumentException
| InvocationTargetException ex) {
throw new UncheckedWrapperException(ex);
}
return Optional.of(summary);
} else {
return Optional.empty();
}
}
protected Element generateDocumentXML(final PageState state,
final CcmObject doc) {
final Element entry = new Element(SearchConstants.XML_PREFIX + "object",
SearchConstants.XML_NS);
final Optional<String> summary = getSummary(doc);
entry.addAttribute("id", XML.format(doc.getObjectId()));
entry.addAttribute("uuid", XML.format(doc.getUuid()));
// entry.addAttribute("url", XML.format(relative ? url.getPath() + "?"
// + url.getQuery()
// : url.toString()));
entry.addAttribute("title", XML.format(doc.getDisplayName()));
if (summary.isPresent()) {
entry.addAttribute("summary", XML.format(summary));
}
// entry.addAttribute("locale", XML.format(doc.getLocale()));
// Date creationDate = doc.getCreationDate();
// if (creationDate != null) {
// entry.addAttribute("creationDate", XML.format(
// creationDate.toString()));
// }
// Party creationParty = doc.getCreationParty();
// if (creationParty != null) {
// entry.addAttribute("creationParty",
// XML.format(creationParty.getDisplayName()));
// }
//
// Date lastModifiedDate = doc.getLastModifiedDate();
// if (lastModifiedDate != null) {
// entry.addAttribute("lastModifiedDate",
// XML.format(lastModifiedDate));
// }
// Party lastModifiedParty = doc.getLastModifiedParty();
// if (lastModifiedParty != null) {
// entry.addAttribute("lastModifiedParty",
// XML.format(lastModifiedParty.getDisplayName()));
// }
// LOGGER.debug(
// "about to add the contentSectionName from search index Doc to search result xml");
// entry.addAttribute("contentSectionName", XML.format(doc.
// getContentSection()));
return entry;
}
}