/*
* Copyright 2004, 2005, 2006 Odysseus Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.odysseus.calyxo.panels;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Locale;
import de.odysseus.calyxo.panels.conf.ItemConfig;
import de.odysseus.calyxo.panels.conf.ParamConfig;
import de.odysseus.calyxo.panels.conf.ListConfig;
import de.odysseus.calyxo.panels.conf.PanelConfig;
/**
* Panels Context.
* This class encapsulates a stack, which reflects the current forward/include
* hierarchy of panels and current list items.
* <p/>
* An instance of this class is created and installed in request scope, when
* forwarding to a panel element. Subsequent includes will push a
* panel entry before inclusion and pop it after inclusion. Each list iteration
* step will push an item entry at the beginning and pop it again at the end.
*
* This class implements methods to lookup panels, params and lists.
*
* @author Christoph Beck
*/
public class PanelsContext {
/**
* Basic stack entry class.
* A stack entry implements a namespace component
* and offers methods to lookup panels, params and lists.
*/
abstract class Entry {
Entry previous;
Entry(Entry previous) {
this.previous = previous;
}
abstract PanelConfig lookupPanelConfig(String name);
abstract ParamConfig lookupParamConfig(String name);
abstract ListConfig lookupListConfig(String name);
abstract void addParamConfig(ParamConfig param);
}
/**
* Panel stack entry.
* Searches components in the panel's inheritance hierarchy
*/
final class PanelEntry extends Entry {
HashMap map;
PanelConfig panel;
PanelEntry(PanelConfig panel, Entry previous) {
super(previous);
this.panel = panel;
}
PanelConfig lookupPanelConfig(String name) {
return panel.findPanelConfig(name, locale);
}
ParamConfig lookupParamConfig(String name) {
if (map != null && map.containsKey(name)) {
return (ParamConfig)map.get(name);
}
return panel.findParamConfig(name, locale);
}
ListConfig lookupListConfig(String name) {
return panel.findListConfig(name, locale);
}
void addParamConfig(ParamConfig param) {
if (map == null) {
map = new HashMap(8);
}
map.put(param.getName(), param);
}
}
/**
* Item stack entry.
* Searches components in the item's children first, then
* in the including panel's hierarchy.
*/
final class ItemEntry extends Entry {
ItemConfig item;
ItemEntry(ItemConfig item, Entry previous) {
super(previous);
this.item = item;
}
PanelConfig lookupPanelConfig(String name) {
PanelConfig result = item.getPanelConfig(name);
if (result == null && previous != null) {
result = previous.lookupPanelConfig(name);
}
return result;
}
ParamConfig lookupParamConfig(String name) {
ParamConfig result = item.getParamConfig(name);
if (result == null && previous != null) {
result = previous.lookupParamConfig(name);
}
return result;
}
ListConfig lookupListConfig(String name) {
ListConfig result = item.getListConfig(name);
if (result == null && previous != null) {
result = previous.lookupListConfig(name);
}
return result;
}
void addParamConfig(ParamConfig param) {
previous.addParamConfig(param);
}
}
/**
* Buttom stack entry, represents global scope.
* Searches toplevel panels, no params, no lists.
*/
final class BottomEntry extends Entry {
PanelsSupport support;
BottomEntry(PanelsSupport support) {
super(null);
this.support = support;
}
PanelConfig lookupPanelConfig(String name) {
return support.findPanelConfig(name, locale);
}
ParamConfig lookupParamConfig(String name) {
return null;
}
ListConfig lookupListConfig(String name) {
return null;
}
void addParamConfig(ParamConfig param) {
}
}
private Entry bottom, top;
private Locale locale;
/**
* Constructor
* @param support
*/
public PanelsContext(PanelsSupport support, Locale locale) {
this.locale = locale;
top = bottom = new BottomEntry(support);
}
/**
* Push panel element.
* Make the specified panel the current entry. This method is called
* before a forward or include is performed.
* @param panel current panel (to which is forwarded or which is included)
*/
public void push(PanelConfig panel) {
top = new PanelEntry(panel, top);
}
/**
* Push item element.
* Make the specified item the current entry. This method is called
* before each list iteration step.
* @param item current item (which is the next current item)
*/
public void push(ItemConfig item) {
top = new ItemEntry(item, top);
}
/**
* Pop panel or item element.
* Remove the current entry. This method is called
* after a forward or include is performed and after each list iteration step.
*/
public void pop() {
if (isEmpty()) {
throw new EmptyStackException();
}
top = top.previous;
}
/**
* Answer <code>true</code> if the stack is empty
*/
public boolean isEmpty() {
return top.previous == null;
}
/**
* Lookup panel within current scope.
* Delegates search to top stack entry.
* @param name panel name
*/
public PanelConfig lookupPanelConfig(String name) {
PanelConfig panel = top.lookupPanelConfig(name);
if (panel == null) {
panel = bottom.lookupPanelConfig(name);
}
return panel;
}
/**
* Lookup param within current scope.
* Delegates search to top stack entry.
* @param name param name
*/
public ParamConfig lookupParamConfig(String name) {
return top.lookupParamConfig(name);
}
/**
* Lookup list within current scope.
* Delegates search to top stack entry.
* @param name list name
*/
public ListConfig lookupListConfig(String name) {
return top.lookupListConfig(name);
}
/**
* Add a dynamic parameter to the current panel
*/
public void addParamConfig(ParamConfig param) {
top.addParamConfig(param);
}
/**
* Get locale
*/
public Locale getLocale() {
return locale;
}
}