From 5df674a703a6d7168282a02c6b2836aad1f354b0 Mon Sep 17 00:00:00 2001 From: jensp Date: Fri, 23 Mar 2018 19:19:52 +0000 Subject: [PATCH] CCM NG: Form etc for editing FlexLayoutComponent and some other things git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5357 8810af33-2d31-482b-a856-94f89814c4df --- .../ui/pagemodel/ItemListComponentForm.java | 22 +- .../main/java/com/arsdigita/bebop/List.java | 436 ++++++++++-------- .../java/com/arsdigita/bebop/ListPanel.java | 51 +- .../layout/ui/FlexLayoutComponentForm.java | 71 --- .../AbstractComponentModelForm.java | 28 +- .../layout/FlexLayoutComponentForm.java | 411 +++++++++++++++++ .../core/AbstractEntityRepository.java | 2 +- .../main/java/org/libreccm/core/CcmCore.java | 2 +- .../pagemodel/ComponentModelRepository.java | 80 +++- .../libreccm/pagemodel/layout/FlexBox.java | 1 + .../libreccm/pagemodel/layout/FlexLayout.java | 3 +- .../pagemodel/layout/FlexLayoutRenderer.java | 2 +- .../java/org/libreccm/theming/ThemeFiles.java | 2 +- .../org/libreccm/theming/ThemeFilesDav.java | 106 +++++ .../org/libreccm/theming/ThemesService.java | 1 + .../java/org/libreccm/webdav/Headers.java | 179 +++++++ .../org/libreccm/webdav/ResponseStatus.java | 131 ++++++ .../org/libreccm/webdav/methods/COPY.java | 49 ++ .../org/libreccm/webdav/methods/LOCK.java | 49 ++ .../org/libreccm/webdav/methods/MKCOL.java | 47 ++ .../org/libreccm/webdav/methods/MOVE.java | 47 ++ .../org/libreccm/webdav/methods/PROPFIND.java | 47 ++ .../libreccm/webdav/methods/PROPPATCH.java | 47 ++ .../org/libreccm/webdav/methods/UNLOCK.java | 47 ++ .../libreccm/webdav/methods/package-info.java | 22 + .../org/libreccm/webdav/package-info.java | 29 ++ 26 files changed, 1610 insertions(+), 302 deletions(-) delete mode 100644 ccm-core/src/main/java/com/arsdigita/pagemodel/layout/ui/FlexLayoutComponentForm.java create mode 100644 ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/layout/FlexLayoutComponentForm.java create mode 100644 ccm-core/src/main/java/org/libreccm/theming/ThemeFilesDav.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/Headers.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/ResponseStatus.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/COPY.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/LOCK.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/MKCOL.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/MOVE.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/PROPFIND.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/PROPPATCH.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/UNLOCK.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/methods/package-info.java create mode 100644 ccm-core/src/main/java/org/libreccm/webdav/package-info.java diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/pagemodel/ItemListComponentForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/pagemodel/ItemListComponentForm.java index b02f12f2b..06f89bc05 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/pagemodel/ItemListComponentForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/pagemodel/ItemListComponentForm.java @@ -32,6 +32,8 @@ import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.ui.admin.pagemodels.AbstractComponentModelForm; import com.arsdigita.ui.admin.pagemodels.PageModelsTab; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.pagemodel.ComponentModelRepository; import org.librecms.CmsConstants; import org.librecms.pagemodel.ItemListComponent; @@ -133,8 +135,7 @@ public class ItemListComponentForm } @Override - public void init(final FormSectionEvent event) - throws FormProcessException { + public void init(final FormSectionEvent event) throws FormProcessException { super.init(event); @@ -144,7 +145,7 @@ public class ItemListComponentForm if (component == null) { pageSizeField.setValue(state, "30"); - }else { + } else { final Object[] descendingValue; if (component.isDescending()) { descendingValue = new Object[]{DESCENDING}; @@ -163,6 +164,21 @@ public class ItemListComponentForm } } + @Override + protected ItemListComponent loadSelectedComponent(final long componentId) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ComponentModelRepository componentModelRepo = cdiUtil + .findBean(ComponentModelRepository.class); + + return componentModelRepo.findById(componentId, + ItemListComponent.class, + new String[]{"listOrder"}) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No ComponentModel with ID %d in the database.", + componentId))); + } + @Override public void validate(final FormSectionEvent event) throws FormProcessException { diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/List.java b/ccm-core/src/main/java/com/arsdigita/bebop/List.java index 32e74865a..0047ec30f 100755 --- a/ccm-core/src/main/java/com/arsdigita/bebop/List.java +++ b/ccm-core/src/main/java/com/arsdigita/bebop/List.java @@ -39,24 +39,23 @@ import com.arsdigita.bebop.util.BebopConstants; import com.arsdigita.xml.Element; - /** - * A List, similar to a javax.swing.JList, that - * keeps track of a sequence of items and selections of one or more of - * these items. A separate model, {@link ListModel}, is used to represent - * the items in the list. + * A List, similar to a javax.swing.JList, that keeps + * track of a sequence of items and selections of one or more of these items. A + * separate model, {@link ListModel}, is used to represent the items in the + * list. * * @see ListModel * @see ListModelBuilder * @see com.arsdigita.bebop.list.ListCellRenderer - * @author David Lutterkort + * @author David Lutterkort * @version $Id: List.java 287 2005-02-22 00:29:02Z sskracic $ */ public class List extends SimpleComponent implements BebopConstants { /** - * The name of the StringParameter that the list uses to keep track of - * which item is selected. + * The name of the StringParameter that the list uses to keep track of which + * item is selected. */ public static final String SELECTED = "sel"; @@ -67,8 +66,9 @@ public class List extends SimpleComponent implements BebopConstants { public static final String SELECT_EVENT = "s"; /** - * The model builder for this list. Is used to produce a new model for - * each request served by this List. + * The model builder for this list. Is used to produce a new model for each + * request served by this List. + * * @see #setListModelBuilder * @see ArrayListModelBuilder * @see MapListModelBuilder @@ -79,6 +79,7 @@ public class List extends SimpleComponent implements BebopConstants { /** * The renderer used to format list items. + * * @see DefaultListCellRenderer */ private ListCellRenderer m_renderer; @@ -93,27 +94,28 @@ public class List extends SimpleComponent implements BebopConstants { private boolean m_stateParamsAreRegistered; - /** - *

Vertical List layout.

- **/ + *

+ * Vertical List layout.

+ * + */ public static final int VERTICAL = 0; - /** - *

Horizontal List layout.

- **/ + *

+ * Horizontal List layout.

+ * + */ public static final int HORIZONTAL = 1; - private int m_layout = VERTICAL; /** - * Creates a new List that uses the specified - * list model builder to generate - * per-request {@link ListModel ListModels}. + * Creates a new List that uses the specified list model + * builder to generate per-request {@link ListModel ListModels}. * * @param b the model builder used for this list + * * @pre b != null */ public List(ListModelBuilder b) { @@ -128,8 +130,8 @@ public class List extends SimpleComponent implements BebopConstants { public List() { // Force the use of the 'right' constructor this((SingleSelectionModel) null); - m_selection = - new ParameterSingleSelectionModel(new StringParameter(SELECTED)); + m_selection = new ParameterSingleSelectionModel(new StringParameter( + SELECTED)); } /** @@ -150,14 +152,14 @@ public class List extends SimpleComponent implements BebopConstants { /** * Creates a new List from an array of objects. Uses an - * internal {@link ListModelBuilder}. Each {@link ListModel} that is - * built will - * iterate through the entries of the object, returning the objects from - * calls to {@link ListModel#getElement} and the corresponding index, + * internal {@link ListModelBuilder}. Each {@link ListModel} that is built + * will iterate through the entries of the object, returning the objects + * from calls to {@link ListModel#getElement} and the corresponding index, * which is converted to a String from calls to {@link * ListModel#getKey}. * * @param values an array of items + * * @pre values != null * @see #setListData(Object[] v) */ @@ -173,10 +175,11 @@ public class List extends SimpleComponent implements BebopConstants { * returned by map.entrySet().iterator(). Calls to {@link * ListModel#getElement} return one value in map. Calls to * {@link ListModel#getElement} return the corresponding key, which is - * converted - * to a String by calling toString() on the key. + * converted to a String by calling toString() on + * the key. * * @param map a key-value mapping for the list items + * * @pre map != null */ public List(Map map) { @@ -189,12 +192,13 @@ public class List extends SimpleComponent implements BebopConstants { * specified page. * * @param p the page this list is contained in + * * @pre p != null * @pre ! isLocked() */ public void register(Page p) { Assert.isUnlocked(this); - if ( m_selection.getStateParameter() != null ) { + if (m_selection.getStateParameter() != null) { p.addComponentStateParam(this, m_selection.getStateParameter()); } } @@ -204,11 +208,13 @@ public class List extends SimpleComponent implements BebopConstants { * component. Calls to this method should only be made through links * generated by this list. * - *

Determines the new selected element and fires a {@link + *

+ * Determines the new selected element and fires a {@link * ChangeEvent} if it has changed. After that, fires an {@link * ActionEvent}. * * @param state the state of the current request + * * @throws ServletException if the control event is unknown. * @pre state != null * @see #fireStateChanged fireStateChanged @@ -217,7 +223,7 @@ public class List extends SimpleComponent implements BebopConstants { public void respond(PageState state) throws ServletException { String event = state.getControlEventName(); - if ( SELECT_EVENT.equals(event) ) { + if (SELECT_EVENT.equals(event)) { setSelectedKey(state, state.getControlEventValue()); } else { throw new ServletException("Unknown event '" + event + "'"); @@ -226,11 +232,33 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Generates XML representing the items in the list. The items are - * formatted using a {@link ListCellRenderer}. generateXML - * is called on each component returned by the renderer. + * Allow subclasses to override how the layout is determined. * - *

The XML that is generated has the following form: + * @param list + */ + protected void exportLayoutAttribute(final Element list) { + if (m_layout == VERTICAL) { + list.addAttribute("layout", "vertical"); + } else { + list.addAttribute("layout", "horizontal"); + } + } + + protected String getTagName() { + return BEBOP_LIST; + } + + protected String getTagXMLNS() { + return BEBOP_XML_NS; + } + + /** + * Generates XML representing the items in the list. The items are formatted + * using a {@link ListCellRenderer}. generateXML is called on + * each component returned by the renderer. + * + *

+ * The XML that is generated has the following form: *

      *   <bebop:list mode="single" %bebopAttr;>
      *     <bebop:cell [selected="selected"] key="itemKey">
@@ -239,43 +267,43 @@ public class List extends SimpleComponent implements BebopConstants {
      *     ... more <bebop:cell> elements, one for each list item ...
      *   </bebop:list>
* - * @param state the state of the current request + * @param state the state of the current request * @param parent the element into which XML is generated + * * @pre state != null * @pre parent != null * @see com.arsdigita.bebop.list.ListCellRenderer */ public void generateXML(PageState state, Element parent) { - if ( ! isVisible(state) ) { + if (!isVisible(state)) { return; } ListModel m = getModel(state); // Check if there are items in the list - if(m.next()) { + if (m.next()) { // The list has items - - Element list = parent.newChildElement(BEBOP_LIST, BEBOP_XML_NS); + Element list = parent.newChildElement(getTagName(), getTagXMLNS()); exportAttributes(list); - if (m_layout == VERTICAL) { - list.addAttribute("layout", "vertical"); - } else { - list.addAttribute("layout", "horizontal"); - } +// if (m_layout == VERTICAL) { +// list.addAttribute("layout", "vertical"); +// } else { +// list.addAttribute("layout", "horizontal"); +// } + exportLayoutAttribute(list); Component c; Object selKey; - if(getStateParamsAreRegistered()) - { - selKey = getSelectedKey(state); - } - else + if (getStateParamsAreRegistered()) { + selKey = getSelectedKey(state); + } else { selKey = null; + } int i = 0; do { @@ -286,24 +314,25 @@ public class List extends SimpleComponent implements BebopConstants { // Converting both keys to String for comparison // since ListModel.getKey returns a String - boolean selected = (selKey != null) && - key.equals(selKey.toString()); + boolean selected = (selKey != null) && key.equals(selKey + .toString()); item.addAttribute("key", key); - if ( selected ) { + if (selected) { item.addAttribute("selected", "selected"); } - if(getStateParamsAreRegistered()) + if (getStateParamsAreRegistered()) { state.setControlEvent(this, SELECT_EVENT, key); + } c = getCellRenderer().getComponent(this, state, m.getElement(), key, i, selected); c.generateXML(state, item); i += 1; - } while (m.next()); + } while (m.next()); } else { // The list has no items - if(m_emptyView != null) { + if (m_emptyView != null) { // Display the empty view m_emptyView.generateXML(state, parent); } else { @@ -317,42 +346,42 @@ public class List extends SimpleComponent implements BebopConstants { state.clearControlEvent(); } - /** - *

Retrieve the current List layout.

+ *

+ * Retrieve the current List layout.

* * @return List.VERTICAL or List.HORIZONTAL - **/ + * + */ public int getLayout() { return m_layout; } /** - *

Set the current List layout.

+ *

+ * Set the current List layout.

* * @param layout New layout value, must be List.VERTICAL or List.HORIZONTAL - **/ + * + */ public void setLayout(int layout) { Assert.isUnlocked(this); Assert.isTrue((layout == VERTICAL) || (layout == HORIZONTAL), - "Invalid layout code passed to setLayout"); + "Invalid layout code passed to setLayout"); m_layout = layout; } /** - * This method is part of a mechanism to freakishly allow - * List's to be used as parent classes for components - * that do not have their state params registered with the - * page. An example of a situation like this is Form ErrorDisplay - * being used in a Metaform + * This method is part of a mechanism to freakishly allow List's to be used + * as parent classes for components that do not have their state params + * registered with the page. An example of a situation like this is Form + * ErrorDisplay being used in a Metaform */ - public void setStateParamsAreRegistered(boolean val) - { + public void setStateParamsAreRegistered(boolean val) { m_stateParamsAreRegistered = val; } - public boolean getStateParamsAreRegistered() - { + public boolean getStateParamsAreRegistered() { return m_stateParamsAreRegistered; } @@ -360,6 +389,7 @@ public class List extends SimpleComponent implements BebopConstants { * Returns the renderer currently used for rendering list items. * * @return the current list cell renderer. + * * @see #setCellRenderer setCellRenderer * @see com.arsdigita.bebop.list.ListCellRenderer */ @@ -368,10 +398,11 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Sets the cell renderer to be used when generating output with - * or {@link #generateXML generateXML}. + * Sets the cell renderer to be used when generating output with or + * {@link #generateXML generateXML}. * * @param r a ListCellRenderer value + * * @pre r != null * @pre ! isLocked() * @see com.arsdigita.bebop.list.ListCellRenderer @@ -386,6 +417,7 @@ public class List extends SimpleComponent implements BebopConstants { * {@link ListModel}. * * @return a ListModelBuilder value. + * * @see #setModelBuilder setModelBuilder * @see ListModelBuilder */ @@ -398,6 +430,7 @@ public class List extends SimpleComponent implements BebopConstants { * {@link ListModel}. * * @param b a ListModelBuilder value + * * @pre ! isLocked() * @see ListModelBuilder */ @@ -407,9 +440,9 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Sets the empty view component, which is - * shown if there are no items in the list. This component must - * be stateless. For example, it could be an Image or a Label. + * Sets the empty view component, which is shown if there are no items in + * the list. This component must be stateless. For example, it could be an + * Image or a Label. * * @param c the new empty view component */ @@ -419,25 +452,27 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Gets the empty view component. The empty view component is - * shown if there are no items in the list. + * Gets the empty view component. The empty view component is shown if there + * are no items in the list. + * * @return the empty view component. */ public final Component getEmptyView() { return m_emptyView; } - /** - * Initialize the private m_model variable. The initial - * value is what the model builder returns for the state. + * Initialize the private m_model variable. The initial value + * is what the model builder returns for the state. */ private void initListModel() { m_model = new RequestLocal() { - protected Object initialValue(PageState s) { - return getModelBuilder().makeModel(List.this, s); - } - }; + + protected Object initialValue(PageState s) { + return getModelBuilder().makeModel(List.this, s); + } + + }; } /** @@ -445,8 +480,9 @@ public class List extends SimpleComponent implements BebopConstants { * state. * * @param state the state of the current request + * * @return the list model used in processing the request represented by - * state. + * state. */ public ListModel getModel(PageState state) { return (ListModel) m_model.get(state); @@ -455,11 +491,12 @@ public class List extends SimpleComponent implements BebopConstants { /** * Sets the list to use for the values in values. Each {@link * ListModel} that is built will iterate through the entries of the object, - * returning the objects from calls to {@link ListModel#getElement} and - * the corresponding index, which is converted to a String - * from calls to {@link ListModel#getKey}. + * returning the objects from calls to {@link ListModel#getElement} and the + * corresponding index, which is converted to a String from + * calls to {@link ListModel#getKey}. * * @param values an array of items + * * @pre values != null * @pre ! isLocked() */ @@ -475,9 +512,11 @@ public class List extends SimpleComponent implements BebopConstants { * map.entrySet().iterator(). Calls to {@link * ListModel#getElement} return one value in map. Calls to * {@link ListModel#getElement} return the corresponding key, which is - * converted to a String by calling toString() - * on the key. + * converted to a String by calling toString() on + * the key. + * * @param map a key-value mapping for the list items + * * @pre map != null * @pre ! isLocked() */ @@ -492,7 +531,7 @@ public class List extends SimpleComponent implements BebopConstants { * programmatically. * * @return the model used by the list to keep track of the selected list - * item. + * item. */ public final SingleSelectionModel getSelectionModel() { return m_selection; @@ -503,12 +542,13 @@ public class List extends SimpleComponent implements BebopConstants { * currently selected list item. * * @param m the new selection model + * * @pre m != null * @pre ! isLocked() */ public final void setSelectionModel(SingleSelectionModel m) { Assert.isUnlocked(this); - if ( m_changeListener != null ) { + if (m_changeListener != null) { // Transfer the change listener m_selection.removeChangeListener(m_changeListener); m.addChangeListener(m_changeListener); @@ -517,12 +557,13 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Gets the key for the selected list item. This will only - * be a valid key - * if {@link #isSelected isSelected} is true. + * Gets the key for the selected list item. This will only be a valid key if + * {@link #isSelected isSelected} is true. * * @param state the state of the current request + * * @return the key for the selected list item. + * * @pre isSelected(state) */ public Object getSelectedKey(PageState state) { @@ -530,12 +571,13 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Sets the selection to the one with the specified key. If - * key was not already selected, fires the {@link + * Sets the selection to the one with the specified key. If key + * was not already selected, fires the {@link * ChangeEvent}. * * @param state the state of the current request - * @param key the key for the selected list item + * @param key the key for the selected list item + * * @see #fireStateChanged fireStateChanged */ public void setSelectedKey(PageState state, String key) { @@ -546,8 +588,9 @@ public class List extends SimpleComponent implements BebopConstants { * Returns true if one of the list items is currently selected. * * @param state the state of the current request + * * @return true if one of the list items is selected - * false otherwise. + * false otherwise. */ public boolean isSelected(PageState state) { return m_selection.isSelected(state); @@ -557,6 +600,7 @@ public class List extends SimpleComponent implements BebopConstants { * Clears the selection in the request represented by state. * * @param state the state of the current request + * * @post ! isSelected(state) */ public void clearSelection(PageState state) { @@ -565,19 +609,20 @@ public class List extends SimpleComponent implements BebopConstants { /** * Creates the change listener that is used for forwarding change events - * fired by - * the selection model to change listeners registered with the list. The - * returned change listener refires the event with the list, + * fired by the selection model to change listeners registered with the + * list. The returned change listener refires the event with the list, * rather than the selection model, as source. * * @return the change listener used internally by the list. */ protected ChangeListener createChangeListener() { return new ChangeListener() { - public void stateChanged(ChangeEvent e) { - fireStateChanged(e.getPageState()); - } - }; + + public void stateChanged(ChangeEvent e) { + fireStateChanged(e.getPageState()); + } + + }; } /** @@ -585,13 +630,14 @@ public class List extends SimpleComponent implements BebopConstants { * list item changes during the processing of a request. The change event * that listeners receive names the list as the source. * - * @param l the change listener to run when the selected item changes in - * a request + * @param l the change listener to run when the selected item changes in a + * request + * * @pre ! isLocked() */ public void addChangeListener(ChangeListener l) { Assert.isUnlocked(this); - if ( m_changeListener == null ) { + if (m_changeListener == null) { m_changeListener = createChangeListener(); m_selection.addChangeListener(m_changeListener); } @@ -599,10 +645,9 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Removes a change listener. The listener should have been previously - * added with {@link #addChangeListener addChangeListener}, although no - * error is signalled if the change listener is not found among the - * list's listeners. + * Removes a change listener. The listener should have been previously added + * with {@link #addChangeListener addChangeListener}, although no error is + * signalled if the change listener is not found among the list's listeners. * * @param l the change listener to remove from the list */ @@ -612,19 +657,18 @@ public class List extends SimpleComponent implements BebopConstants { } /** - * Fires a change event to signal that the selected list item has changed - * in the request represented by state. The source of the - * event is the list. + * Fires a change event to signal that the selected list item has changed in + * the request represented by state. The source of the event is + * the list. * * @param state the state of the current request */ protected void fireStateChanged(PageState state) { - Iterator - i=m_listeners.getListenerIterator(ChangeListener.class); + Iterator i = m_listeners.getListenerIterator(ChangeListener.class); ChangeEvent e = null; while (i.hasNext()) { - if ( e == null ) { + if (e == null) { e = new ChangeEvent(this, state); } ((ChangeListener) i.next()).stateChanged(e); @@ -633,9 +677,10 @@ public class List extends SimpleComponent implements BebopConstants { // Action events /** - * Adds an action listener. This method is run whenever {@link #respond respond} is - * called on the list. This gives clients a way to track mouse clicks - * received by the list. + * Adds an action listener. This method is run whenever + * {@link #respond respond} is called on the list. This gives clients a way + * to track mouse clicks received by the list. + * * @param 1 the action listener to add * * @pre l != null @@ -649,6 +694,7 @@ public class List extends SimpleComponent implements BebopConstants { /** * Removes a previously added action listener. + * * @param 1 the action listener to remove * * @see #addActionListener addActionListener @@ -660,20 +706,20 @@ public class List extends SimpleComponent implements BebopConstants { /** * Fires an action event signalling that the list received the request - * submission. All registered action listeners are run. The source of - * the event is the list. + * submission. All registered action listeners are run. The source of the + * event is the list. + * * @param state the state of the current request * * @pre state != null * @see #respond respond */ protected void fireActionEvent(PageState state) { - Iterator - i=m_listeners.getListenerIterator(ActionListener.class); + Iterator i = m_listeners.getListenerIterator(ActionListener.class); ActionEvent e = null; while (i.hasNext()) { - if ( e == null ) { + if (e == null) { e = new ActionEvent(this, state); } ((ActionListener) i.next()).actionPerformed(e); @@ -681,7 +727,6 @@ public class List extends SimpleComponent implements BebopConstants { } // ListModelBuilder for maps - /** * Build list models from a map. The list models use the result of * toString() called on the key of the map entries as their @@ -689,6 +734,7 @@ public class List extends SimpleComponent implements BebopConstants { * the list model iterates over. */ private static class MapListModelBuilder implements ListModelBuilder { + private Map m_map; private boolean m_locked; @@ -702,36 +748,38 @@ public class List extends SimpleComponent implements BebopConstants { public ListModel makeModel(List l, PageState state) { return new ListModel() { - private Iterator i = m_map.entrySet().iterator(); - private Map.Entry e = null; - public boolean next() { - if ( ! i.hasNext() ) { - e = null; - return false; - } - e = (Map.Entry) i.next(); - return true; + private Iterator i = m_map.entrySet().iterator(); + private Map.Entry e = null; + + public boolean next() { + if (!i.hasNext()) { + e = null; + return false; } + e = (Map.Entry) i.next(); + return true; + } - public Object getElement() { - checkState(); - return e.getValue(); + public Object getElement() { + checkState(); + return e.getValue(); + } + + public String getKey() { + checkState(); + return e.getKey().toString(); + } + + private void checkState() { + if (e == null) { + throw new IllegalStateException( + "No valid current item. " + + "Model is either before first item or after last item"); } + } - public String getKey() { - checkState(); - return e.getKey().toString(); - } - - private void checkState() { - if ( e == null ) { - throw new IllegalStateException("No valid current item. " - + "Model is either before first item or after last item"); - } - } - - }; + }; } public void lock() { @@ -741,16 +789,17 @@ public class List extends SimpleComponent implements BebopConstants { public final boolean isLocked() { return m_locked; } + } // ListModelBuilder for arrays - /** - * Build list models from an array of values. The list models use the - * index of the array entries, converted to a String, as the - * key for the list items and the array values as their elements. + * Build list models from an array of values. The list models use the index + * of the array entries, converted to a String, as the key for + * the list items and the array values as their elements. */ private static class ArrayListModelBuilder implements ListModelBuilder { + private Object[] m_values; private boolean m_locked; @@ -764,33 +813,36 @@ public class List extends SimpleComponent implements BebopConstants { public ListModel makeModel(List l, PageState state) { return new ListModel() { - private int i = -1; - public boolean next() { - i += 1; - return ( i < m_values.length ); - } + private int i = -1; - public Object getElement() { - checkState(); - return m_values[i]; - } + public boolean next() { + i += 1; + return (i < m_values.length); + } - public String getKey() { - checkState(); - return String.valueOf(i); - } + public Object getElement() { + checkState(); + return m_values[i]; + } - private void checkState() { - if ( i < 0 ) { - throw new IllegalStateException - ("Before first item. Call next() first."); - } - if ( i >= m_values.length ) { - throw new IllegalStateException("After last item. Model exhausted."); - } + public String getKey() { + checkState(); + return String.valueOf(i); + } + + private void checkState() { + if (i < 0) { + throw new IllegalStateException( + "Before first item. Call next() first."); } - }; + if (i >= m_values.length) { + throw new IllegalStateException( + "After last item. Model exhausted."); + } + } + + }; } public void lock() { @@ -800,22 +852,26 @@ public class List extends SimpleComponent implements BebopConstants { public final boolean isLocked() { return m_locked; } + } /** * A {@link ListModel} that has no rows. */ public static final ListModel EMPTY_MODEL = new ListModel() { - public boolean next() { - return false; - } - public String getKey() { - throw new IllegalStateException("ListModel is empty"); - } + public boolean next() { + return false; + } + + public String getKey() { + throw new IllegalStateException("ListModel is empty"); + } + + public Object getElement() { + throw new IllegalStateException("ListModel is empty"); + } + + }; - public Object getElement() { - throw new IllegalStateException("ListModel is empty"); - } - }; } diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/ListPanel.java b/ccm-core/src/main/java/com/arsdigita/bebop/ListPanel.java index bca4357e6..d51f0d5ec 100644 --- a/ccm-core/src/main/java/com/arsdigita/bebop/ListPanel.java +++ b/ccm-core/src/main/java/com/arsdigita/bebop/ListPanel.java @@ -26,26 +26,29 @@ import com.arsdigita.xml.Element; /** * A container that outputs its components in a <list>. Each child is - * printed in its own list item. The components are put into the list - * in the order in which they were added to the - * ListPanel, progressing from top to bottom. + * printed in its own list item. The components are put into the list in the + * order in which they were added to the ListPanel, progressing + * from top to bottom. * - *

ListPanels can be ordered or unordered.

+ *

+ * ListPanels can be ordered or unordered.

* * @author Christian Brechbühler (christian@arsdigita.com) * * @version $Id$ - * */ -public class ListPanel extends SimpleContainer { + * + */ +public class ListPanel extends SimpleContainer { - public static final boolean ORDERED = true ; + public static final boolean ORDERED = true; public static final boolean UNORDERED = false; private boolean m_ordered; /** * Creates a simple list. + * * @param ordered true is an ordered (numbered) list; - * false is an unordered (bulleted) list + * false is an unordered (bulleted) list * */ public ListPanel(boolean ordered) { @@ -54,32 +57,36 @@ public class ListPanel extends SimpleContainer { /** * Adds child components as a subtree under list-item nodes. - *

Generates a DOM fragment: - *

+     * 

+ * Generates a DOM fragment: + *

+ *

      * <bebop:listPanel>
      *   <bebop:cell> ... cell contents </bebop:cell>
      *   <bebop:cell> ... cell contents </bebop:cell>
      *   ...
      * </bebop:list>

- * @param state the state of the current request + * + * @param state the state of the current request * @param parent the node under which this subtree will be added */ public void generateXML(PageState state, Element parent) { - if ( ! isVisible(state) ) { - return; - } + if (isVisible(state)) { - Element list = parent.newChildElement("bebop:listPanel", BEBOP_XML_NS); - list.addAttribute("ordered", String.valueOf(m_ordered)); - exportAttributes(list); + Element list = parent.newChildElement("bebop:listPanel", + BEBOP_XML_NS); + list.addAttribute("ordered", String.valueOf(m_ordered)); + exportAttributes(list); - // generate XML for children - for (Iterator i = children(); i.hasNext(); ) { - Component c = (Component) i.next(); + // generate XML for children + for (Iterator i = children(); i.hasNext();) { + Component c = (Component) i.next(); - Element item = list.newChildElement("bebop:cell", BEBOP_XML_NS); - c.generateXML(state, item); + Element item = list.newChildElement("bebop:cell", BEBOP_XML_NS); + c.generateXML(state, item); + } } } + } diff --git a/ccm-core/src/main/java/com/arsdigita/pagemodel/layout/ui/FlexLayoutComponentForm.java b/ccm-core/src/main/java/com/arsdigita/pagemodel/layout/ui/FlexLayoutComponentForm.java deleted file mode 100644 index f953ea6d1..000000000 --- a/ccm-core/src/main/java/com/arsdigita/pagemodel/layout/ui/FlexLayoutComponentForm.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2018 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.pagemodel.layout.ui; - -import com.arsdigita.bebop.BoxPanel; -import com.arsdigita.bebop.FormData; -import com.arsdigita.bebop.PageState; -import com.arsdigita.bebop.ParameterSingleSelectionModel; -import com.arsdigita.ui.admin.pagemodels.AbstractComponentModelForm; -import com.arsdigita.ui.admin.pagemodels.PageModelsTab; - -import org.libreccm.pagemodel.layout.FlexLayout; - -/** - * - * @author Jens Pelzetter - */ -public class FlexLayoutComponentForm - extends AbstractComponentModelForm { - - public FlexLayoutComponentForm( - final PageModelsTab pageModelsTab, - final ParameterSingleSelectionModel selectedModelId, - final ParameterSingleSelectionModel selectedComponentId) { - - - super("FlexLayoutComponentForm", - pageModelsTab, - selectedModelId, - selectedComponentId); - } - - @Override - protected void addWidgets() { - - final BoxPanel horizontalPanel = new BoxPanel(BoxPanel.HORIZONTAL); - - add(horizontalPanel); - } - - @Override - protected FlexLayout createComponentModel() { - return new FlexLayout(); - } - - @Override - protected void updateComponentModel(final FlexLayout componentModel, - final PageState state, - final FormData data) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - - -} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/AbstractComponentModelForm.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/AbstractComponentModelForm.java index 83c56ec7a..e8eb8b33b 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/AbstractComponentModelForm.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/AbstractComponentModelForm.java @@ -29,6 +29,7 @@ import com.arsdigita.bebop.event.FormProcessListener; import com.arsdigita.bebop.event.FormSectionEvent; import com.arsdigita.bebop.event.FormValidationListener; import com.arsdigita.bebop.form.TextField; +import com.arsdigita.bebop.parameters.LongParameter; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.ui.admin.AdminUiConstants; @@ -239,6 +240,7 @@ public abstract class AbstractComponentModelForm * @throws FormProcessException */ @Override + @SuppressWarnings("unchecked") public void init(final FormSectionEvent event) throws FormProcessException { final PageState state = event.getPageState(); @@ -248,18 +250,26 @@ public abstract class AbstractComponentModelForm if (selectedComponentIdStr != null && !selectedComponentIdStr.isEmpty()) { - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + + componentModel = loadSelectedComponent( + Long.parseLong(selectedComponentIdStr)); + + keyField.setValue(state, componentModel.getKey()); + } + } + + @SuppressWarnings("unchecked") + protected T loadSelectedComponent(final long componentId) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final ComponentModelRepository componentModelRepo = cdiUtil .findBean(ComponentModelRepository.class); - - final ComponentModel model = componentModelRepo - .findById(Long.parseLong(selectedComponentIdStr)) + + return (T) componentModelRepo + .findById(componentId) .orElseThrow(() -> new IllegalArgumentException(String - .format("No ComponentModel with ID %s in the database.", - selectedComponentIdStr))); - - keyField.setValue(state, model.getKey()); - } + .format("No ComponentModel with ID %d in the database.", + componentId))); } /** diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/layout/FlexLayoutComponentForm.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/layout/FlexLayoutComponentForm.java new file mode 100644 index 000000000..9f5ed9b7c --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/layout/FlexLayoutComponentForm.java @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2018 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.ui.admin.pagemodels.layout; + +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.List; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.PropertySheet; +import com.arsdigita.bebop.PropertySheetModel; +import com.arsdigita.bebop.PropertySheetModelBuilder; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.list.ListCellRenderer; +import com.arsdigita.bebop.list.ListModel; +import com.arsdigita.bebop.list.ListModelBuilder; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.ui.admin.AdminUiConstants; +import com.arsdigita.ui.admin.pagemodels.AbstractComponentModelForm; +import com.arsdigita.ui.admin.pagemodels.PageModelsTab; +import com.arsdigita.util.LockableImpl; +import com.arsdigita.xml.Element; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.core.UnexpectedErrorException; +import org.libreccm.pagemodel.ComponentModelRepository; +import org.libreccm.pagemodel.layout.FlexBox; +import org.libreccm.pagemodel.layout.FlexDirection; +import org.libreccm.pagemodel.layout.FlexLayout; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.Objects; + +/** + * + * @author Jens Pelzetter + */ +public class FlexLayoutComponentForm + extends AbstractComponentModelForm { + + private final ParameterSingleSelectionModel selectedComponentId; + + private SingleSelect directionSelect; +// private FlexBoxesPanel boxesPanel; + + private List boxesList; + + public FlexLayoutComponentForm( + final PageModelsTab pageModelsTab, + final ParameterSingleSelectionModel selectedModelId, + final ParameterSingleSelectionModel selectedComponentId) { + + super("FlexLayoutComponentForm", + pageModelsTab, + selectedModelId, + selectedComponentId); + + Objects.requireNonNull(pageModelsTab); + Objects.requireNonNull(selectedModelId); + Objects.requireNonNull(selectedComponentId); + + this.selectedComponentId = selectedComponentId; + } + + @Override + protected void addWidgets() { + + directionSelect = new SingleSelect("directionSelect"); + directionSelect.setLabel(new GlobalizedMessage( + AdminUiConstants.ADMIN_BUNDLE, + "ui.admin.pagelayout.flexlayout.direction.label")); + directionSelect + .addOption(new Option( + FlexDirection.HORIZONTAL.toString(), + new Label(new GlobalizedMessage( + AdminUiConstants.ADMIN_BUNDLE, + "ui.admin.pagelayout.flexlayout.direction" + + ".option.horizontal")))); + directionSelect + .addOption(new Option( + FlexDirection.VERTICAL.toString(), + new Label(new GlobalizedMessage( + AdminUiConstants.ADMIN_BUNDLE, + "ui.admin.pagelayout.flexlayout.direction" + + ".option.vertical")))); + add(directionSelect); + +// boxesPanel = new FlexBoxesPanel(); +// add(boxesPanel); + boxesList + = new BoxesList(new BoxesListModelBuilder(selectedComponentId)); + boxesList.setCellRenderer(new BoxesListCellRenderer()); + boxesList.setEmptyView(new Label(new GlobalizedMessage( + "ui.admin.pagelayout.flexlayout.no_boxes", + AdminUiConstants.ADMIN_BUNDLE))); + add(boxesList); + } + + @Override + protected FlexLayout createComponentModel() { + return new FlexLayout(); + } + + @Override + protected void updateComponentModel(final FlexLayout componentModel, + final PageState state, + final FormData data) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void init(final FormSectionEvent event) throws FormProcessException { + + super.init(event); + + final PageState state = event.getPageState(); + + final FlexLayout layout = getComponentModel(); + + if (layout == null) { + directionSelect.setValue(state, FlexDirection.VERTICAL.toString()); + } else { + directionSelect.setValue(state, layout.getDirection().toString()); + } + } + +// private class FlexBoxesPanel extends SimpleContainer { +// +// private FlexDirection direction; +// +// public FlexBoxesPanel() { +// super("flexLayout", "bebop"); +// +// direction = FlexDirection.VERTICAL; +// } +// +// public FlexDirection getDirection() { +// return direction; +// } +// +// public void setFlexDirection(final FlexDirection direction) { +// this.direction = direction; +// } +// +// @Override +// protected Element generateParent(final Element parent) { +// +// final Element element = super.generateParent(parent); +// element.addAttribute("direction", direction +// .toString() +// .toLowerCase()); +// return element; +// } +// +// } + private class FlexBoxPanel extends BoxPanel { + + private final FlexBox box; + + public FlexBoxPanel(final FlexBox box) { + + super(BoxPanel.VERTICAL); + + this.box = box; + + final PropertySheet propertySheet = new PropertySheet( + new FlexBoxPropertySheetModelBuilder(box)); + super.add(propertySheet); + } + + } + + private class FlexBoxPropertySheetModelBuilder + extends LockableImpl + implements PropertySheetModelBuilder { + + private final FlexBox box; + + public FlexBoxPropertySheetModelBuilder(final FlexBox box) { + this.box = box; + } + + @Override + public PropertySheetModel makeModel(final PropertySheet sheet, + final PageState state) { + + return new FlexBoxPropertySheetModel(box); + } + + } + + private class FlexBoxPropertySheetModel implements PropertySheetModel { + + private final FlexBox box; + private final Iterator propertyIterator; + private FlexBoxProperty currentProperty; + + public FlexBoxPropertySheetModel(final FlexBox box) { + this.box = box; + propertyIterator = Arrays + .asList(FlexBoxProperty.values()) + .iterator(); + } + + @Override + public boolean nextRow() { + + if (box == null) { + return false; + } + + if (propertyIterator.hasNext()) { + currentProperty = propertyIterator.next(); + return true; + } else { + return false; + } + } + + @Override + public String getLabel() { + return currentProperty.toString(); + } + + @Override + public GlobalizedMessage getGlobalizedLabel() { + + final String key = String + .format("ui.admin.pagemodels.flexlayout.box.properties.%s", + currentProperty.toString().toLowerCase()); + return new GlobalizedMessage(key, AdminUiConstants.ADMIN_BUNDLE); + } + + @Override + public String getValue() { + + switch (currentProperty) { + case ORDER: + return Integer.toString(box.getOrder()); + case SIZE: + return Integer.toString(box.getSize()); + case COMPONENT: + if (box.getComponent() == null) { + return ""; + } else { + return box.getComponent().getClass().getName(); + } + default: + throw new UnexpectedErrorException(String + .format("Invalid \"%s\" for property of FlexBox.", + currentProperty.toString())); + } + } + } + + private static enum FlexBoxProperty { + ORDER, + SIZE, + COMPONENT + } + + private class BoxesList extends List { + + private FlexLayout flexLayout; + + public BoxesList(final ListModelBuilder listModelBuilder) { + super(listModelBuilder); + } + + public FlexLayout getFlexLayout() { + return flexLayout; + } + + public void setFlexLayout(final FlexLayout flexLayout) { + this.flexLayout = flexLayout; + } + + @Override + protected String getTagName() { + return "flexLayoutBoxesList"; + } + + @Override + protected void exportLayoutAttribute(final Element list) { + + if (flexLayout.getDirection() == FlexDirection.HORIZONTAL) { + list.addAttribute("layout", "horizontal"); + } else { + list.addAttribute("layout", "vertical"); + } + } + + } + + private class BoxesListModelBuilder + extends LockableImpl + implements ListModelBuilder { + + private final ParameterSingleSelectionModel selectedComponentId; + + public BoxesListModelBuilder( + final ParameterSingleSelectionModel selectedComponentId) { + + super(); + + Objects.requireNonNull(selectedComponentId); + + this.selectedComponentId = selectedComponentId; + } + + @Override + public ListModel makeModel(final List list, + final PageState state) { + + if (selectedComponentId.isSelected(state)) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + + final ComponentModelRepository componentModelRepo = cdiUtil + .findBean(ComponentModelRepository.class); + + final String componentModelId = selectedComponentId + .getSelectedKey(state); + + final FlexLayout flexLayout = (FlexLayout) componentModelRepo + .findById(Long.parseLong(componentModelId)) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No ComponentModel with ID %s in the database", + componentModelId))); + + return new BoxesListModel(flexLayout.getBoxes()); + + } else { + return new BoxesListModel(Collections.emptyList()); + } + } + + } + + private class BoxesListModel implements ListModel { + + private final Iterator iterator; + private FlexBox currentBox; + + public BoxesListModel(final java.util.List boxes) { + this.iterator = boxes.iterator(); + } + + @Override + public boolean next() { + if (iterator.hasNext()) { + currentBox = iterator.next(); + return true; + } else { + return false; + } + } + + @Override + public Object getElement() { + return currentBox; + } + + @Override + public String getKey() { + return Long.toString(currentBox.getBoxId()); + } + + } + + private class BoxesListCellRenderer implements ListCellRenderer { + + @Override + public Component getComponent(final List list, + final PageState state, + final Object value, + final String key, + final int index, + final boolean isSelected) { + + final FlexBox box = (FlexBox) value; + + return new FlexBoxPanel(box); + } + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java b/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java index 148a86a97..e33c8b1ea 100644 --- a/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java +++ b/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java @@ -188,7 +188,7 @@ public abstract class AbstractEntityRepository implements Serializable { /** * Finds an entity by its ID and does fetch joins for the provided * attributes. Be careful with this method. Do not a too many attributes to - * the fetch joins, only does which you really need. Otherwise there can be + * the fetch joins, only those which you really need. Otherwise there can be * a serious performance impact. * * @param entityId The ID of the entity to retrieve. diff --git a/ccm-core/src/main/java/org/libreccm/core/CcmCore.java b/ccm-core/src/main/java/org/libreccm/core/CcmCore.java index 927c0b816..03eeee24f 100644 --- a/ccm-core/src/main/java/org/libreccm/core/CcmCore.java +++ b/ccm-core/src/main/java/org/libreccm/core/CcmCore.java @@ -18,7 +18,7 @@ */ package org.libreccm.core; -import com.arsdigita.pagemodel.layout.ui.FlexLayoutComponentForm; +import com.arsdigita.ui.admin.pagemodels.layout.FlexLayoutComponentForm; import com.arsdigita.ui.admin.AdminServlet; import com.arsdigita.ui.admin.AdminUiConstants; import com.arsdigita.ui.admin.applications.AdminApplicationCreator; diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentModelRepository.java b/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentModelRepository.java index 9217cd330..b35032174 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentModelRepository.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentModelRepository.java @@ -23,10 +23,23 @@ import org.libreccm.core.CoreConstants; import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.RequiresPrivilege; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + import javax.enterprise.context.RequestScoped; import javax.transaction.Transactional; + import java.util.UUID; +import javax.persistence.EntityGraph; +import javax.persistence.NoResultException; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + /** * Repository class for managing {@link ComponentModel} entities. * @@ -47,7 +60,7 @@ public class ComponentModelRepository public String getIdAttributeName() { return "componentModelId"; } - + @Override public Long getIdOfEntity(final ComponentModel entity) { return entity.getComponentModelId(); @@ -83,4 +96,69 @@ public class ComponentModelRepository } } + @Transactional(Transactional.TxType.REQUIRED) + public Optional findById(final long modelId, + final Class modelClass) { + + return Optional.ofNullable(getEntityManager().find(modelClass, + modelId)); + } + + @Transactional(Transactional.TxType.REQUIRED) + public Optional findById( + final long modelId, + final Class modelClass, + final String entityGraphName) { + + return Optional.ofNullable(getEntityManager().find(modelClass, + modelId)); + } + + @Transactional(Transactional.TxType.REQUIRED) + public Optional findById( + final long entityId, + final Class modelClass, + final EntityGraph entityGraph) { + + Objects.requireNonNull(entityId); + Objects.requireNonNull(entityGraph); + + final Map hints = new HashMap<>(); + hints.put(FETCH_GRAPH_HINT_KEY, entityGraph); + return Optional.ofNullable(getEntityManager().find(modelClass, + entityId, + hints)); + } + + @Transactional(Transactional.TxType.REQUIRED) + public Optional findById( + final long entityId, + final Class modelClass, + final String... fetchJoins) { + + Objects.requireNonNull(entityId); + + final CriteriaBuilder builder = getEntityManager() + .getCriteriaBuilder(); + final CriteriaQuery criteriaQuery = builder + .createQuery(modelClass); + final Root from = criteriaQuery.from(modelClass); + criteriaQuery.from(getEntityClass()); + criteriaQuery.select(from); + for (final String fetchJoin : fetchJoins) { + from.fetch(fetchJoin); + } + + criteriaQuery + .where(builder.equal(from.get(getIdAttributeName()), entityId)); + + final TypedQuery query = getEntityManager() + .createQuery(criteriaQuery); + try { + return Optional.of(query.getSingleResult()); + } catch (NoResultException ex) { + return Optional.empty(); + } + } + } diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBox.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBox.java index de0c17205..5f5e68a81 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBox.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexBox.java @@ -56,6 +56,7 @@ public class FlexBox implements Serializable { private long boxId; @ManyToOne + @JoinColumn(name = "LAYOUT_ID") private FlexLayout layout; @Column(name = "BOX_ORDER") diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayout.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayout.java index 5eecb3e56..f65e1a9ef 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayout.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayout.java @@ -46,7 +46,7 @@ import javax.persistence.Table; * @author Jens Pelzetter */ @Entity -@Table(name = "HORIZONTAL_LAYOUT_COMPONENTS", schema = CoreConstants.DB_SCHEMA) +@Table(name = "FLEX_LAYOUT_COMPONENTS", schema = CoreConstants.DB_SCHEMA) public class FlexLayout extends ComponentModel { private static final long serialVersionUID = 1977244351125227610L; @@ -65,7 +65,6 @@ public class FlexLayout extends ComponentModel { */ @OneToMany(mappedBy = "layout") @OrderBy(value = "order") - @JoinColumn(name = "LAYOUT_ID") private List boxes; public FlexLayout() { diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayoutRenderer.java b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayoutRenderer.java index 298e3520e..c7809640a 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayoutRenderer.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/layout/FlexLayoutRenderer.java @@ -59,7 +59,7 @@ public class FlexLayoutRenderer implements ComponentRenderer { componentModel .getBoxes() .stream() - .map(this::renderBox) + .map(box -> renderBox(box, parameters)) .collect(Collectors.toList())); return result; diff --git a/ccm-core/src/main/java/org/libreccm/theming/ThemeFiles.java b/ccm-core/src/main/java/org/libreccm/theming/ThemeFiles.java index a840aa5ff..7db5a9f52 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/ThemeFiles.java +++ b/ccm-core/src/main/java/org/libreccm/theming/ThemeFiles.java @@ -40,7 +40,7 @@ import javax.ws.rs.core.Response; * @author Jens Pelzetter */ @RequestScoped -@Path("/{theme}") +@Path("/files/{theme}") public class ThemeFiles { @Inject diff --git a/ccm-core/src/main/java/org/libreccm/theming/ThemeFilesDav.java b/ccm-core/src/main/java/org/libreccm/theming/ThemeFilesDav.java new file mode 100644 index 000000000..8a3f5f07d --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/theming/ThemeFilesDav.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 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 org.libreccm.theming; + +import org.libreccm.webdav.methods.PROPFIND; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path("/dav/{theme}") +public class ThemeFilesDav { + + @Inject + private Themes themes; + + @GET + @Path("/{path}") + public Response getFile(@PathParam("theme") final String theme, + @PathParam("path") final String path) { + + final ThemeInfo info = themes + .getTheme(theme, ThemeVersion.LIVE) + .orElseThrow(() -> new NotFoundException(String + .format("Theme \"%s\" does not exist.", theme))); + + final InputStream inputStream = themes + .getFileFromTheme(info, path) + .orElseThrow(() -> new NotFoundException(String + .format("The file \"%s\" does exist in the theme \"%s\".", + path, + theme))); + + final MediaType mediaType = getMediaTypeFromPath(path); + + final BufferedReader reader = new BufferedReader( + new InputStreamReader(inputStream)); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + int value = reader.read(); + while (value != -1) { + outputStream.write(value); + value = reader.read(); + } + } catch (IOException ex) { + throw new WebApplicationException(ex); + } + + final byte[] data = outputStream.toByteArray(); + return Response.ok(data, mediaType).build(); + + } + + @PROPFIND + @Path("/{path}") + public Response propfind(@PathParam("theme") final String theme, + @PathParam("path") final String path) { + + throw new UnsupportedOperationException(); + + } + + private MediaType getMediaTypeFromPath(final String path) { + + if (path.endsWith(".css")) { + return new MediaType("text", "css"); + } else { + return MediaType.WILDCARD_TYPE; + } + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/theming/ThemesService.java b/ccm-core/src/main/java/org/libreccm/theming/ThemesService.java index 20a178880..22587f0d3 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/ThemesService.java +++ b/ccm-core/src/main/java/org/libreccm/theming/ThemesService.java @@ -36,6 +36,7 @@ public class ThemesService extends Application { final Set> classes = new HashSet<>(); classes.add(ThemeFiles.class); + classes.add(ThemeFilesDav.class); return classes; } diff --git a/ccm-core/src/main/java/org/libreccm/webdav/Headers.java b/ccm-core/src/main/java/org/libreccm/webdav/Headers.java new file mode 100644 index 000000000..186401867 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/Headers.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2018 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 org.libreccm.webdav; + +/** + * WebDAV Headers. + * + * The class is based on a class/interface from java.net WebDAV Project: + * + * https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/Headers.java + * + * + * @author Markus KARG + * @author Jens Pelzetter + * + * @see + * + * Chapter 10 "HTTP Headers for Distributed Authoring" of RFC 4918 "HTTP + * Extensions for Web Distributed Authoring and Versioning (WebDAV)" + * + */ +public final class Headers { + + /** + * WebDAV DAV Header + * + * @see + * Chapter + * 10.1 "DAV Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String DAV = "DAV"; + + /** + * WebDAV Depth Header + * + * @see + * Chapter + * 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String DEPTH = "Depth"; + + /** + * WebDAV Depth Header Value "0" + * + * @see + * Chapter + * 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String DEPTH_0 = "0"; + + /** + * WebDAV Depth Header Value "1" + * + * @see + * Chapter + * 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String DEPTH_1 = "1"; + + /** + * WebDAV Depth Header Value "infinity" + * + * @see + * Chapter + * 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String DEPTH_INFINITY = "infinity"; + + /** + * WebDAV Destination Header + * + * @see + * Chapter + * 10.3 "Destination Header" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ + public static final String DESTINATION = "Destination"; + + /** + * WebDAV If Header + * + * @see Chapter + * 10.4 "If Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String IF = "If"; + + /** + * WebDAV Lock-Token Header + * + * @see + * Chapter + * 10.5 "Lock-Token Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String LOCK_TOKEN = "Lock-Token"; + + /** + * WebDAV Overwrite Header + * + * @see + * Chapter + * 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String OVERWRITE = "Overwrite"; + + /** + * WebDAV Overwrite Header Value "T" + * + * @see + * Chapter + * 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String OVERWRITE_TRUE = "T"; + + /** + * WebDAV Overwrite Header Value "F" + * + * @see + * Chapter + * 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + public static final String OVERWRITE_FALSE = "F"; + + /** + * WebDAV Timeout Header + * + * @see + * Chapter + * 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ + public static final String TIMEOUT = "Timeout"; + + /** + * WebDAV Timeout Header Value "Second-" + * + * @see + * Chapter + * 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ + public static final String TIMEOUT_SECOND = "Second-"; + + /** + * WebDAV Timeout Header Value "Infinite" + * + * @see + * Chapter + * 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ + public static final String TIMEOUT_INFINITE = "Infinite"; + +} diff --git a/ccm-core/src/main/java/org/libreccm/webdav/ResponseStatus.java b/ccm-core/src/main/java/org/libreccm/webdav/ResponseStatus.java new file mode 100644 index 000000000..2d60a824f --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/ResponseStatus.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2018 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 org.libreccm.webdav; + +import javax.ws.rs.core.Response; + +import static javax.ws.rs.core.Response.Status.Family.*; + +/** + * Commonly used status codes defined by WebDAV. + * + * The enum is based on an enum from the java.net WebDAV project: + * + * https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/ResponseStatus.java + * + * @author Markus KARG + * @author Jens Pelzetter + * + * @see + * Chapter + * 11 "Status Code Extensions to HTTP/1.1" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ +public enum ResponseStatus implements Response.StatusType { + + /** + * 207 Multi-Status + * + * @see + * Chapter + * 11.1 "207 Multi-Status" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + MULTI_STATUS(207, "Multi-Status"), + /** + * 422 Unprocessable Entity + * + * @see + * Chapter + * 11.2 "422 Unprocessable Entity" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ + UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"), + /** + * 423 Locked + * + * @see + * Chapter + * 11.3 "423 Locked" of RFC 4918 "HTTP Extensions for Web Distributed + * Authoring and Versioning (WebDAV)" + */ + LOCKED(423, "Locked"), + /** + * 424 Failed Dependency + * + * @see + * Chapter + * 11.4 "424 Failed Dependency" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ + FAILED_DEPENDENCY(424, "Failed Dependency"), + /** + * 507 Insufficient Storage + * + * @see + * Chapter + * 11.5 "507 Insufficient Storage" of RFC 4918 "HTTP Extensions for Web + * Distributed Authoring and Versioning (WebDAV)" + */ + INSUFFICIENT_STORAGE(507, "Insufficient Storage"); + + private final int statusCode; + + private final String reasonPhrase; + + private ResponseStatus(final int statusCode, final String reasonPhrase) { + this.statusCode = statusCode; + this.reasonPhrase = reasonPhrase; + } + + @Override + public int getStatusCode() { + return statusCode; + + } + + @Override + public Response.Status.Family getFamily() { + switch (this.statusCode / 100) { + case 1: + return INFORMATIONAL; + case 2: + return SUCCESSFUL; + case 3: + return REDIRECTION; + case 4: + return CLIENT_ERROR; + case 5: + return SERVER_ERROR; + default: + return OTHER; + } + } + + @Override + public String getReasonPhrase() { + return reasonPhrase; + } + + @Override + public String toString() { + return reasonPhrase; + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/COPY.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/COPY.java new file mode 100644 index 000000000..1b6085772 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/COPY.java @@ -0,0 +1,49 @@ +/* + * #%L + * WebDAV Support for JAX-RS + * %% + * Copyright (C) 2008 - 2018 The java.net WebDAV Project + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package org.libreccm.webdav.methods; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Indicates that the annotated method responds to WebDAV COPY requests. + * + * Adopted from + * https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/COPY.java + * + * @author Markus KARG (mkarg@java.net) + * + * @see Chapter + * 9.8 "COPY Method" of RFC 4918 "HTTP Extensions for Web Distributed Authoring + * and Versioning (WebDAV)" + */ +@Target(METHOD) +@Retention(RUNTIME) +@HttpMethod("COPY") +public @interface COPY { + // Has no members. +} diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/LOCK.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/LOCK.java new file mode 100644 index 000000000..eda697149 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/LOCK.java @@ -0,0 +1,49 @@ +/* + * #%L + * WebDAV Support for JAX-RS + * %% + * Copyright (C) 2008 - 2018 The java.net WebDAV Project + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package org.libreccm.webdav.methods; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Indicates that the annotated method responds to WebDAV LOCK requests. + * + * Adopted from + * https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/LOCK.java + * + * @author Markus KARG (mkarg@java.net) + * + * @see Chapter + * 9.10 "LOCK Method" of RFC 4918 "HTTP Extensions for Web Distributed Authoring + * and Versioning (WebDAV)" + */ +@Target(METHOD) +@Retention(RUNTIME) +@HttpMethod("LOCK") +public @interface LOCK { + // Has no members. +} diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/MKCOL.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/MKCOL.java new file mode 100644 index 000000000..c1f73e3ac --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/MKCOL.java @@ -0,0 +1,47 @@ +/* + * #%L + * WebDAV Support for JAX-RS + * %% + * Copyright (C) 2008 - 2018 The java.net WebDAV Project + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package org.libreccm.webdav.methods; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Indicates that the annotated method responds to WebDAV MKCOL requests. + * + * Adopted from https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MKCOL.java + * + * @author Markus KARG (mkarg@java.net) + * + * @see Chapter 9.3 "MKCOL Method" of RFC 4918 + * "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" + */ +@Target(METHOD) +@Retention(RUNTIME) +@HttpMethod("MKCOL") +public @interface MKCOL { + // Has no members. +} \ No newline at end of file diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/MOVE.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/MOVE.java new file mode 100644 index 000000000..e3159f134 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/MOVE.java @@ -0,0 +1,47 @@ +/* + * #%L + * WebDAV Support for JAX-RS + * %% + * Copyright (C) 2008 - 2018 The java.net WebDAV Project + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package org.libreccm.webdav.methods; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Indicates that the annotated method responds to WebDAV MOVE requests. + * + * Adopted from https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MOVE.java + * + * @author Markus KARG (mkarg@java.net) + * + * @see Chapter 9.9 "COPY Method" of RFC 4918 + * "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" + */ +@Target(METHOD) +@Retention(RUNTIME) +@HttpMethod("MOVE") +public @interface MOVE { + // Has no members. +} \ No newline at end of file diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/PROPFIND.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/PROPFIND.java new file mode 100644 index 000000000..f2a271b91 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/PROPFIND.java @@ -0,0 +1,47 @@ +/* + * #%L + * WebDAV Support for JAX-RS + * %% + * Copyright (C) 2008 - 2018 The java.net WebDAV Project + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package org.libreccm.webdav.methods; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Indicates that the annotated method responds to WebDAV PROPFIND requests. + * + * Adopted from https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPFIND.java + * + * @author Markus KARG (mkarg@java.net) + * + * @see Chapter 9.1 "PROPFIND Method" of RFC 4918 + * "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" + */ +@Target(METHOD) +@Retention(RUNTIME) +@HttpMethod("PROPFIND") +public @interface PROPFIND { + // Has no members. +} \ No newline at end of file diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/PROPPATCH.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/PROPPATCH.java new file mode 100644 index 000000000..5eefd7ff1 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/PROPPATCH.java @@ -0,0 +1,47 @@ +/* + * #%L + * WebDAV Support for JAX-RS + * %% + * Copyright (C) 2008 - 2018 The java.net WebDAV Project + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package org.libreccm.webdav.methods; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Indicates that the annotated method responds to WebDAV PROPPATCH requests. + * + * Adopted from https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPPATCH.java + * + * @author Markus KARG (mkarg@java.net) + * + * @see Chapter 9.2 "PROPPATCH Method" of RFC 4918 + * "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" + */ +@Target(METHOD) +@Retention(RUNTIME) +@HttpMethod("PROPPATCH") +public @interface PROPPATCH { + // Has no members. +} \ No newline at end of file diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/UNLOCK.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/UNLOCK.java new file mode 100644 index 000000000..252583fd1 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/UNLOCK.java @@ -0,0 +1,47 @@ +/* + * #%L + * WebDAV Support for JAX-RS + * %% + * Copyright (C) 2008 - 2018 The java.net WebDAV Project + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +package org.libreccm.webdav.methods; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.ws.rs.HttpMethod; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * Indicates that the annotated method responds to WebDAV UNLOCK requests. + * + * Adopted from https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/UNLOCK.java + * + * @author Markus KARG (mkarg@java.net) + * + * @see Chapter 9.11 "UNLOCK Method" of RFC 4918 + * "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" + */ +@Target(METHOD) +@Retention(RUNTIME) +@HttpMethod("UNLOCK") +public @interface UNLOCK { + // Has no members. +} \ No newline at end of file diff --git a/ccm-core/src/main/java/org/libreccm/webdav/methods/package-info.java b/ccm-core/src/main/java/org/libreccm/webdav/methods/package-info.java new file mode 100644 index 000000000..6db2e3567 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/methods/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2018 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 + */ +/** + * Annotations for the WebDAV HTTP methods. + */ +package org.libreccm.webdav.methods; diff --git a/ccm-core/src/main/java/org/libreccm/webdav/package-info.java b/ccm-core/src/main/java/org/libreccm/webdav/package-info.java new file mode 100644 index 000000000..22d886d3c --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/webdav/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 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 + */ +/** + * Annotations and classes for exposing resources via WebDAV using JAX-RS. + * The classes in these packages are based on classes originally created for + * JAX-RS. This project was hosted on the now defunct dev.java.net site. The + * sources now be found at {@link https://gitlab.com/headcrashing/webdav-jaxrs}. + * Unfortunately the project is not maintained anymore and has not been updated + * for JAX-RS 2. Therefore we used the classes only as foundation for our + * implementation. The classes have been edited to match our coding standards + * and to be compatible with new versions of JAX-RS and other libraries. + */ +package org.libreccm.webdav;