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
pull/2/head
jensp 2018-03-23 19:19:52 +00:00
parent 3abbb740a1
commit 5df674a703
26 changed files with 1610 additions and 302 deletions

View File

@ -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 {

View File

@ -39,12 +39,11 @@ import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.xml.Element;
/**
* A <code>List</code>, similar to a <code>javax.swing.JList</code>, 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 <code>List</code>, similar to a <code>javax.swing.JList</code>, 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
@ -55,8 +54,8 @@ import com.arsdigita.xml.Element;
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 <code>List</code>.
* The model builder for this list. Is used to produce a new model for each
* request served by this <code>List</code>.
*
* @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;
/**
* <p>Vertical List layout.</p>
**/
* <p>
* Vertical List layout.</p>
*
*/
public static final int VERTICAL = 0;
/**
* <p>Horizontal List layout.</p>
**/
* <p>
* Horizontal List layout.</p>
*
*/
public static final int HORIZONTAL = 1;
private int m_layout = VERTICAL;
/**
* Creates a new <code>List</code> that uses the specified
* list model builder to generate
* per-request {@link ListModel ListModels}.
* Creates a new <code>List</code> 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 <code>List</code> 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 <code>String</code> 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 <code>map.entrySet().iterator()</code>. Calls to {@link
* ListModel#getElement} return one value in <code>map</code>. Calls to
* {@link ListModel#getElement} return the corresponding key, which is
* converted
* to a <code>String</code> by calling <code>toString()</code> on the key.
* converted to a <code>String</code> by calling <code>toString()</code> 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.
*
* <p>Determines the new selected element and fires a {@link
* <p>
* 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}. <code>generateXML</code>
* is called on each component returned by the renderer.
* Allow subclasses to override how the layout is determined.
*
* <p> 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}. <code>generateXML</code> is called on
* each component returned by the renderer.
*
* <p>
* The XML that is generated has the following form:
* <pre>
* &lt;bebop:list mode="single" %bebopAttr;>
* &lt;bebop:cell [selected="selected"] key="itemKey">
@ -239,43 +267,43 @@ public class List extends SimpleComponent implements BebopConstants {
* ... more &lt;bebop:cell> elements, one for each list item ...
* &lt;/bebop:list></pre>
*
* @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();
}
/**
* <p>Retrieve the current List layout.</p>
* <p>
* Retrieve the current List layout.</p>
*
* @return List.VERTICAL or List.HORIZONTAL
**/
*
*/
public int getLayout() {
return m_layout;
}
/**
* <p>Set the current List layout.</p>
* <p>
* Set the current List layout.</p>
*
* @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 <code>ListCellRenderer</code> 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 <code>ListModelBuilder</code> value.
*
* @see #setModelBuilder setModelBuilder
* @see ListModelBuilder
*/
@ -398,6 +430,7 @@ public class List extends SimpleComponent implements BebopConstants {
* {@link ListModel}.
*
* @param b a <code>ListModelBuilder</code> 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 <code>m_model</code> variable. The initial
* value is what the model builder returns for the state.
* Initialize the private <code>m_model</code> 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 {
* <code>state</code>.
*
* @param state the state of the current request
*
* @return the list model used in processing the request represented by
* <code>state</code>.
* <code>state</code>.
*/
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 <code>values</code>. 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 <code>String</code>
* from calls to {@link ListModel#getKey}.
* returning the objects from calls to {@link ListModel#getElement} and the
* corresponding index, which is converted to a <code>String</code> 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 {
* <code>map.entrySet().iterator()</code>. Calls to {@link
* ListModel#getElement} return one value in <code>map</code>. Calls to
* {@link ListModel#getElement} return the corresponding key, which is
* converted to a <code>String</code> by calling <code>toString()</code>
* on the key.
* converted to a <code>String</code> by calling <code>toString()</code> 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 <code>true</code>.
* Gets the key for the selected list item. This will only be a valid key if
* {@link #isSelected isSelected} is <code>true</code>.
*
* @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
* <code>key</code> was not already selected, fires the {@link
* Sets the selection to the one with the specified key. If <code>key</code>
* 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 <code>true</code> if one of the list items is currently selected.
*
* @param state the state of the current request
*
* @return <code>true</code> if one of the list items is selected
* <code>false</code> otherwise.
* <code>false</code> 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 <code>state</code>.
*
* @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 <code>state</code>. 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 <code>state</code>. 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
* <code>toString()</code> 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 <code>String</code>, 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 <code>String</code>, 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");
}
};
}

View File

@ -26,26 +26,29 @@ import com.arsdigita.xml.Element;
/**
* A container that outputs its components in a &lt;list&gt;. 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
* <code>ListPanel</code>, 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 <code>ListPanel</code>, progressing
* from top to bottom.
*
* <p> ListPanels can be ordered or unordered.</p>
* <p>
* ListPanels can be ordered or unordered.</p>
*
* @author Christian Brechb&uuml;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 <code>true</code> is an ordered (numbered) list;
* <code>false</code> is an unordered (bulleted) list
* <code>false</code> 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.
* <p>Generates a DOM fragment:
* <p><pre>
* <p>
* Generates a DOM fragment:
* <p>
* <pre>
* &lt;bebop:listPanel>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* &lt;bebop:cell> ... cell contents &lt;/bebop:cell>
* ...
* &lt;/bebop:list></pre></p>
* @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);
}
}
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class FlexLayoutComponentForm
extends AbstractComponentModelForm<FlexLayout> {
public FlexLayoutComponentForm(
final PageModelsTab pageModelsTab,
final ParameterSingleSelectionModel<String> selectedModelId,
final ParameterSingleSelectionModel<String> 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.
}
}

View File

@ -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<T extends ComponentModel>
* @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<T extends ComponentModel>
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)));
}
/**

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class FlexLayoutComponentForm
extends AbstractComponentModelForm<FlexLayout> {
private final ParameterSingleSelectionModel<String> selectedComponentId;
private SingleSelect directionSelect;
// private FlexBoxesPanel boxesPanel;
private List boxesList;
public FlexLayoutComponentForm(
final PageModelsTab pageModelsTab,
final ParameterSingleSelectionModel<String> selectedModelId,
final ParameterSingleSelectionModel<String> 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<FlexBoxProperty> 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<String> selectedComponentId;
public BoxesListModelBuilder(
final ParameterSingleSelectionModel<String> 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<FlexBox> iterator;
private FlexBox currentBox;
public BoxesListModel(final java.util.List<FlexBox> 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);
}
}
}

View File

@ -188,7 +188,7 @@ public abstract class AbstractEntityRepository<K, E> 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.

View File

@ -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;

View File

@ -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.
*
@ -83,4 +96,69 @@ public class ComponentModelRepository
}
}
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(final long modelId,
final Class<M> modelClass) {
return Optional.ofNullable(getEntityManager().find(modelClass,
modelId));
}
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(
final long modelId,
final Class<M> modelClass,
final String entityGraphName) {
return Optional.ofNullable(getEntityManager().find(modelClass,
modelId));
}
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(
final long entityId,
final Class<M> modelClass,
final EntityGraph<M> entityGraph) {
Objects.requireNonNull(entityId);
Objects.requireNonNull(entityGraph);
final Map<String, Object> hints = new HashMap<>();
hints.put(FETCH_GRAPH_HINT_KEY, entityGraph);
return Optional.ofNullable(getEntityManager().find(modelClass,
entityId,
hints));
}
@Transactional(Transactional.TxType.REQUIRED)
public <M extends ComponentModel> Optional<M> findById(
final long entityId,
final Class<M> modelClass,
final String... fetchJoins) {
Objects.requireNonNull(entityId);
final CriteriaBuilder builder = getEntityManager()
.getCriteriaBuilder();
final CriteriaQuery<M> criteriaQuery = builder
.createQuery(modelClass);
final Root<M> 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<M> query = getEntityManager()
.createQuery(criteriaQuery);
try {
return Optional.of(query.getSingleResult());
} catch (NoResultException ex) {
return Optional.empty();
}
}
}

View File

@ -56,6 +56,7 @@ public class FlexBox implements Serializable {
private long boxId;
@ManyToOne
@JoinColumn(name = "LAYOUT_ID")
private FlexLayout layout;
@Column(name = "BOX_ORDER")

View File

@ -46,7 +46,7 @@ import javax.persistence.Table;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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<FlexBox> boxes;
public FlexLayout() {

View File

@ -59,7 +59,7 @@ public class FlexLayoutRenderer implements ComponentRenderer<FlexLayout> {
componentModel
.getBoxes()
.stream()
.map(this::renderBox)
.map(box -> renderBox(box, parameters))
.collect(Collectors.toList()));
return result;

View File

@ -40,7 +40,7 @@ import javax.ws.rs.core.Response;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Path("/{theme}")
@Path("/files/{theme}")
public class ThemeFiles {
@Inject

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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;
}
}
}

View File

@ -36,6 +36,7 @@ public class ThemesService extends Application {
final Set<Class<?>> classes = new HashSet<>();
classes.add(ThemeFiles.class);
classes.add(ThemeFilesDav.class);
return classes;
}

View File

@ -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:
*
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/Headers.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/Headers.java</a>
*
*
* @author <a href="mailto:karg@java.net">Markus KARG</a>
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#http.headers.for.distributed.authoring">
* Chapter 10 "HTTP Headers for Distributed Authoring" of RFC 4918 "HTTP
* Extensions for Web Distributed Authoring and Versioning (WebDAV)"
* </a>
*/
public final class Headers {
/**
* WebDAV DAV Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_DAV">Chapter
* 10.1 "DAV Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DAV = "DAV";
/**
* WebDAV Depth Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH = "Depth";
/**
* WebDAV Depth Header Value "0"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH_0 = "0";
/**
* WebDAV Depth Header Value "1"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH_1 = "1";
/**
* WebDAV Depth Header Value "infinity"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Depth">Chapter
* 10.2 "Depth Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String DEPTH_INFINITY = "infinity";
/**
* WebDAV Destination Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Destination">Chapter
* 10.3 "Destination Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String DESTINATION = "Destination";
/**
* WebDAV If Header
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_If">Chapter
* 10.4 "If Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String IF = "If";
/**
* WebDAV Lock-Token Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token">Chapter
* 10.5 "Lock-Token Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String LOCK_TOKEN = "Lock-Token";
/**
* WebDAV Overwrite Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Overwrite">Chapter
* 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String OVERWRITE = "Overwrite";
/**
* WebDAV Overwrite Header Value "T"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Overwrite">Chapter
* 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String OVERWRITE_TRUE = "T";
/**
* WebDAV Overwrite Header Value "F"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Overwrite">Chapter
* 10.6 "Overwrite Header" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
public static final String OVERWRITE_FALSE = "F";
/**
* WebDAV Timeout Header
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Timeout">Chapter
* 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String TIMEOUT = "Timeout";
/**
* WebDAV Timeout Header Value "Second-"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Timeout">Chapter
* 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String TIMEOUT_SECOND = "Second-";
/**
* WebDAV Timeout Header Value "Infinite"
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#HEADER_Timeout">Chapter
* 10.7 "Timeout Request Header" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public static final String TIMEOUT_INFINITE = "Infinite";
}

View File

@ -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:
*
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/ResponseStatus.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/ResponseStatus.java</a>
*
* @author <a href="mailto:mkarg@java.net">Markus KARG</a>
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11">Chapter
* 11 "Status Code Extensions to HTTP/1.1" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
public enum ResponseStatus implements Response.StatusType {
/**
* 207 Multi-Status
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_207">Chapter
* 11.1 "207 Multi-Status" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
MULTI_STATUS(207, "Multi-Status"),
/**
* 422 Unprocessable Entity
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_422">Chapter
* 11.2 "422 Unprocessable Entity" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"),
/**
* 423 Locked
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_423">Chapter
* 11.3 "423 Locked" of RFC 4918 "HTTP Extensions for Web Distributed
* Authoring and Versioning (WebDAV)"</a>
*/
LOCKED(423, "Locked"),
/**
* 424 Failed Dependency
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_424">Chapter
* 11.4 "424 Failed Dependency" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
FAILED_DEPENDENCY(424, "Failed Dependency"),
/**
* 507 Insufficient Storage
*
* @see
* <a href="http://www.webdav.org/specs/rfc4918.html#STATUS_507">Chapter
* 11.5 "507 Insufficient Storage" of RFC 4918 "HTTP Extensions for Web
* Distributed Authoring and Versioning (WebDAV)"</a>
*/
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;
}
}

View File

@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/COPY.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/COPY.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_COPY">Chapter
* 9.8 "COPY Method" of RFC 4918 "HTTP Extensions for Web Distributed Authoring
* and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("COPY")
public @interface COPY {
// Has no members.
}

View File

@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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
* <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/LOCK.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/LOCK.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_LOCK">Chapter
* 9.10 "LOCK Method" of RFC 4918 "HTTP Extensions for Web Distributed Authoring
* and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("LOCK")
public @interface LOCK {
// Has no members.
}

View File

@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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 <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MKCOL.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MKCOL.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_MKCOL">Chapter 9.3 "MKCOL Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("MKCOL")
public @interface MKCOL {
// Has no members.
}

View File

@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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 <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MOVE.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/MOVE.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_MOVE">Chapter 9.9 "COPY Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("MOVE")
public @interface MOVE {
// Has no members.
}

View File

@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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 <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPFIND.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPFIND.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND">Chapter 9.1 "PROPFIND Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("PROPFIND")
public @interface PROPFIND {
// Has no members.
}

View File

@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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 <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPPATCH.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/PROPPATCH.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_PROPPATCH">Chapter 9.2 "PROPPATCH Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("PROPPATCH")
public @interface PROPPATCH {
// Has no members.
}

View File

@ -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
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #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 <a href="https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/UNLOCK.java">https://gitlab.com/headcrashing/webdav-jaxrs/blob/master/src/main/java/net/java/dev/webdav/jaxrs/methods/UNLOCK.java</a>
*
* @author Markus KARG (mkarg@java.net)
*
* @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_UNLOCK">Chapter 9.11 "UNLOCK Method" of RFC 4918
* "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)"</a>
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("UNLOCK")
public @interface UNLOCK {
// Has no members.
}

View File

@ -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;

View File

@ -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;