at.spardat.xma.component.ComponentClient Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* s IT Solutions AT Spardat GmbH - initial API and implementation
*******************************************************************************/
package at.spardat.xma.component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import at.spardat.enterprise.exc.INotification;
import at.spardat.enterprise.exc.SysException;
import at.spardat.xma.appshell.ITask;
import at.spardat.xma.boot.component.IComponentListener;
import at.spardat.xma.boot.component.IRtXMASessionClient;
import at.spardat.xma.boot.component.NamedEvent;
import at.spardat.xma.page.NotificationBox;
import at.spardat.xma.page.PageClient;
import at.spardat.xma.rpc.RemoteCallClient;
import at.spardat.xma.rpc.RemoteReply;
import at.spardat.xma.security.XMAContext;
import at.spardat.xma.serializer.XmaInput;
import at.spardat.xma.serializer.XmaOutput;
import at.spardat.xma.session.XMASessionClient;
/**
* Implents the clients specific aspects of a Component.
* This includes the management of SWT-Resources like the Display and Images.
*
* @author s2877
*/
public abstract class ComponentClient extends Component implements IComponentClient {
/** color used to mark input fields containing errors */
public static RGB errorBackground = new RGB(255,255,200);
/** color used to mark uneditable fields containing errors */
public static RGB errorBackgroundUneditable = new RGB(245, 240, 205);
/** The Display for all Pages in the Component */
Display display;
/** true if this Component had to create a new Display */
boolean displayIsNew;
/** contains all active Images in the Component
* used to dispose them when the Component is finished */
private HashMap images = new HashMap();
/** contains all active Colors in the Component
* used to dispose them when the Component is finished */
private HashMap colors = new HashMap();
/**
* Contains Fonts that are owned by this component and
* freed in dispose.
*/
private HashMap fFonts;
/** contains all event-listeners for this Component
* all elements implement IComponentListener */
private List listeners;
/** contains the input and output values of this component */
private Properties properties;
/**
* the page of which the pageComposite was passed to method {@link #invoke(Composite)}
* this page is used to display exceptions thrown in component {@link #enter()}
* or {@link #leave()} methods
*/
private PageClient invokingPage;
/**
* Indicates that the state of the components page models may be out
* of sync with respect to the servers state. This necessitates
* that not deltas but the full state is transmitted in the
* next server side event.
*/
private boolean outOfSyncWithServer_;
/** Id for Info-Icon */
public static final short resInfoGif = 1;
/** Id for Warning-Icon */
public static final short resWarnGif = 2;
/** Id for Error-Icon */
public static final short resErrorGif = 3;
/**
* maximum Id reserved by the runtime. currently 100.
* please use only ids greater than this for your own images.
*/
public static final short lastResGif = 100;
/** mapping of Icon-Ids to Rescource-URIs */
HashMap imageResources = new HashMap();
{
imageResources.put(new Short(resInfoGif),"at/spardat/xma/page/message_info.gif");
imageResources.put(new Short(resWarnGif),"at/spardat/xma/page/message_warning.gif");
imageResources.put(new Short(resErrorGif),"at/spardat/xma/page/message_error.gif");
}
/**
* Constructor just for test-purpose. This constructor is not intended to be called
* from outside JUnit-Tests.
*/
public ComponentClient () {
}
/**
* Constructor of the Component. Creates the Display if necessary.
* Registers this component with the session.
*
* @param session the XMASession this component belongs to
* @param isStateless defines whether this component is stateless or not.
*/
public ComponentClient (XMASessionClient session, boolean isStateless) {
super (session, isStateless, false);
display = Display.getCurrent();
if(display==null) {
displayIsNew=true;
display = Display.getDefault();
}
// register at session
getSession().registerComponent (this);
// In the case that just 256 colors are available, set the errorBackground to yellow.
// (Otherwise the errorBackground would be white.)
int colorDepth = display.getDepth();
if (colorDepth <= 8) {
errorBackground = display.getSystemColor(SWT.COLOR_YELLOW).getRGB();
}
}
/**
* Adds a ComponentListner to the listeners of the component. All listeners
* are notified of all property-changes and component-events.
*
* @param listener the new listener to register
*/
public void addEventListener(IComponentListener listener) {
if(listeners==null) listeners = new ArrayList(1);
if(!listeners.contains(listener)) listeners.add(listener);
}
/**
* Remove a ComponentListener form the listners of the component. This
* ComponentListner will not be notified of propertiy-changes and component-events
* any more.
* @param listener the ComponentListener to remove
*/
public void removeEventListener(IComponentListener listener) {
if(listeners!=null) {
listeners.remove(listener);
if(listeners.size()==0) listeners=null;
}
}
/**
* Adds a PropertyChangeListener to the listeners of the component. All listeners
* are notified of all property-changes.
*
* @param listener the new listener to register
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
if(listeners==null) listeners = new ArrayList(1);
if(!listeners.contains(listener)) listeners.add(listener);
}
/**
* Remove a PropertyChangeListener form the listners of the component. This
* PropertyChangeListener will not be notified of propertiy-changes
* any more.
* @param listener the PropertyChangeListener to remove
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
if(listeners!=null) {
listeners.remove(listener);
if(listeners.size()==0) listeners=null;
}
}
/**
* Sets all properties of the component. This method completly
* resets the set of properties of the component to the set given
* as input.
* If there are registered ComponentListeners, all ComponentListeners
* are notifyed of each property-change.
*
* @param input the new set of properties
*/
public void setProperties(Properties input) {
ComponentProperty[] props = getPropDes();
if(props!=null) {
for(Iterator it = input.keySet().iterator();it.hasNext();) {
String key = (String)it.next();
ComponentProperty prop = getPropDes(key);
if(prop!=null && prop.isIn()) {
prop.setValue(input.getProperty(key));
} else { // property not input or not defined
//silently ignore
}
}
// // clear missing properties
// for(int i=0;i use old implementation
if(listeners==null) {
properties = input;
} else {
Properties oldprops = properties;
properties = input;
for(Iterator it=properties.keySet().iterator();it.hasNext();) {
String key = (String)it.next();
String value = properties.getProperty(key);
String oldValue = oldprops.getProperty(key);
if(value==null&& oldValue!=null || !value.equals(oldValue)) {
for(Iterator itt=listeners.iterator();itt.hasNext();) {
((PropertyChangeListener)itt.next()).propertyChange(new PropertyChangeEvent(this,key,oldValue,value));
}
}
}
// notify deletes
for(Iterator it=oldprops.keySet().iterator();it.hasNext();) {
String key = (String)it.next();
String value = properties.getProperty(key);
String oldValue = oldprops.getProperty(key);
if(value==null && oldValue!=null) {
for(Iterator itt=listeners.iterator();itt.hasNext();) {
((PropertyChangeListener)itt.next()).propertyChange(new PropertyChangeEvent(this,key,oldValue,value));
}
}
}
}
}
}
/**
* Sets one property of the component.
* If there are registered ComponentListeners and the value of the
* property is differend from its old value, all ComponentListeners
* are notifyed of the property-change.
*
* @param name the name of the property to change
* @param value the new value of the property
*/
public void setProperty(String name, String value) {
ComponentProperty prop = getPropDes(name);
if(prop!=null) {
if(prop.isIn()) {
prop.setValue(value);
} else { // property is not an input property
// silently ignore
}
} else {
if(getPropDes()==null) { // no properties defined in guidesigner -> use old implementation
if(properties==null) {
properties = new Properties();
}
String oldValue = properties.getProperty(name);
properties.setProperty(name,value);
notifyPropertyChange(name,oldValue,value);
} else { // properties defined in guidesigner, but this property is missing
// silently ignore
}
}
}
/**
* Notifies all registerd PropertyChangeListeners of a property change.
* The event is only fired if oldValue and value differ.
* @param name The name of the property which changed
* @param oldValue The old value of the property
* @param value The new value of the property
*/
protected void notifyPropertyChange(String name,Object oldValue,Object value) {
if(listeners!=null && value!=oldValue) {
if(value==null&&oldValue!=null || !value.equals(oldValue)) {
for(Iterator it=listeners.iterator();it.hasNext();) {
((PropertyChangeListener)it.next()).propertyChange(new PropertyChangeEvent(this,name,oldValue,value));
}
}
}
}
/**
* Gives the value of a property. If the property is not defined
* null is returned.
*
* @param name the name of the property
* @return the value of the named property
*/
public String getProperty(String name) {
ComponentProperty prop = getPropDes(name);
if(prop!=null) {
if(prop.isOut()) {
return prop.getValue();
} else { // property is not an output property
// silently ignore
return null;
}
} else {
if(getPropDes()==null) { // no properties defined in guidesigner -> use old implementation
if(properties!=null) {
return properties.getProperty(name);
} else {
return null;
}
} else { // properties defined in guidesigner, but this property is missing
// silently ignore
return null;
}
}
}
/**
* Gives all properties of the component.
* @return the properties of the component.
*/
public Properties getProperties() {
ComponentProperty[] props = getPropDes();
if(props!=null) {
Properties out = new Properties();
for(int i=0;i use old implementation
if(properties!=null) {
return properties;
} else {
return new Properties();
}
}
}
/**
* Notifies all listeners of the named event.
*
* @param name the name of the event
* @param value an optional value passed with the event
*/
public void notifyEvent(String name, String value) {
if(listeners!=null) {
for(Iterator it=listeners.iterator();it.hasNext();) {
Object listener = it.next();
if(listener instanceof IComponentListener) {
((IComponentListener)listener).event(new NamedEvent(this,name,value));
}
}
}
}
/**
* Notifies all listener that this component was closed.
*/
public void notifyClosed() {
if(listeners!=null) {
for(Iterator it=listeners.iterator();it.hasNext();) {
Object listener = it.next();
if(listener instanceof IComponentListener) {
((IComponentListener)listener).componentClosed(new EventObject(this));
}
}
}
}
/**
* Gets the Display used by all Pages in the Component. This Display allways
* exists and is never null.
*
* @return the Display for all Pages in the Component.
*/
public Display getDisplay() {
return display;
}
/**
* Registers an image under the given id. This image-id can be used
* in tables and trees.
* @param id the new id of the image.
* @param resource a resource-string naming the image file.
*/
public void registerImage(short id, String resource) {
imageResources.put(new Short(id),resource);
}
/**
* Get an Image by its ID.
* The resource is loaded via the classloader which downloads the jar-file
* containing the resource if necessary. If the Image is allready loaded,
* the loaded Image will be returned.
* The Images are stored internally in the Component and will be disposed
* automatically when the Component is finished. Do not dispose the Image!
*
* @param id one of the static final int ids defined in this class.
* @return the Image or null if the resource can not be found.
*/
public Image getImage(short id) {
String resource = (String)imageResources.get(new Short(id));
if(resource!=null) {
return getImage(resource);
} else {
return null;
}
}
/**
* Get an Image by naming its resource-file.
* The resource is loaded via the classloader which downloads the jar-file
* containing the resource if necessary. If the Image is allready loaded,
* the loaded Image will be returned.
* The Images are stored internally in the Component and will be disposed
* automatically when the Component is finished. Do not dispose the Image!
*
* @param resource a resource-string naming the image file.
* @return the Image or null if the resource can not be found.
*/
public Image getImage(String resource) {
Image image = (Image) images.get(resource);
if (image == null) {
InputStream in = this.getClass().getClassLoader().getResourceAsStream(resource);
if(in!=null) {
image = new Image(display, in);
images.put(resource, image);
}
}
return image;
}
/**
* Get a Color by naming its red, green and blue values.
* The Colors are stored internally in the Component and will be disposed
* automatically when the Component is finished. Do not dispose the Color!
*
* @param red the red value of the color.
* @param green the green value of the color.
* @param blue the blue value of the color.
* @return the Color corresponding to this values
*/
public Color getColor(int red, int green, int blue) {
return getColor(new RGB(red,green,blue));
}
/**
* Get a Color by naming its red-green-blue value.
* The Colors are stored internally in the Component and will be disposed
* automatically when the Component is finished. Do not dispose the Color!
*
* @param rgb the red, green, blue values defining the color.
* @return the Color corresponding to this values
*/
public Color getColor(RGB rgb) {
Color color = (Color) colors.get(rgb);
if(color==null) {
color = new Color(display,rgb);
colors.put(rgb,color);
}
return color;
}
/**
* Returns a font for the specified data that is owned by this component
* and automatically disposed if this component is disposed. Do not
* dispose the returned Font!
*
* @param name the name of the font (must not be null)
* @param height the font height in points
* @param style a bit or combination of SWT.NORMAL, SWT.BOLD, SWT.ITALIC
* @return a font-object. Must not be disposed by the caller.
*/
public Font getFont (String name, int height, int style) {
FontDescriptor fd = new FontDescriptor (name, height, style);
if (fFonts == null) fFonts = new HashMap();
Font f = (Font) fFonts.get(fd);
if (f == null) {
f = new Font (display, name, height, style);
fFonts.put(fd, f);
}
return f;
}
/**
* Returns a font whose name and style is taken from template
* and whose height is provided. Do not dispose the returned font.
*
* @param template the reference font. Must not be null.
* @param height the height in points of the return Font.
* @return a font-object. Must not be disposed by the caller.
*/
public Font getFontByHeight (Font template, int height) {
if (template == null) throw new IllegalArgumentException();
FontData fData = template.getFontData()[0];
return getFont (fData.getName(), height, fData.getStyle());
}
/**
* Returns a font whose name and height is taken from template
* and whose style is provided. Do not dispose the returned font.
*
* @param template the reference font. Must not be null.
* @param style the style of the font.
* @return a font object. Must not be disposed by the caller.
*/
public Font getFontByStyle (Font template, int style) {
if (template == null) throw new IllegalArgumentException();
FontData fData = template.getFontData()[0];
return getFont (fData.getName(), fData.getHeight(), style);
}
/**
* Gets the URI to the help page explaining this component. The help page must be
* showable inside a web browser.
* This method is implemented in the generated Class for each ComponentClient.
*
* @return the uri of the help page.
*/
public String getHelpUri() { return null; }
/**
* Frees all allocated recources of the Component.
* This includes freeing all still living statefull PageModels at the server
* and disposing all SWT-resources like Images.
*/
public void dispose() {
Collection models=new ArrayList(pageModels.values());
for(Iterator it=models.iterator();it.hasNext();) {
((PageClient)it.next()).removeModel();
}
pageModels.clear();
for (Iterator it = images.values().iterator(); it.hasNext();) {
((Image) it.next()).dispose();
}
images.clear();
for (Iterator it = colors.values().iterator(); it.hasNext();) {
((Color) it.next()).dispose();
}
colors.clear();
// dispose fonts
if (fFonts != null) {
for (Iterator it = fFonts.values().iterator(); it.hasNext();) {
((Font)it.next()).dispose();
}
fFonts.clear();
}
// if(displayIsNew) {
// display.dispose();
// display=null;
// }
/**
* deregister at session
*/
getSession().removeComponent(this);
getSession().getAppContainer().getAppManager().endComponent(this);
}
/**
* Frees the Page with the given ID.
* The Page will also be freed on the server bevor the next
* serverEvent is executed. If the Page does not exist or
* is allredy freed, nothing happens.
*
* @param idPageModel the ID of the Page to destroy.
*/
public void freePageModel(short idPageModel) {
pageModels.remove(new Integer(idPageModel));
}
/**
* This Method is called by the Launcher to start the Component on the
* client side. Before guidesigner 3.4.1.1, there was a first cut generation
* of this method in the derived component class. Since guidesigner 3.4.1.1,
* this method is generated into the generated base class of the component and
* contains calls to modeled init functions of component and page. Since guidesigner 3.5.3,
* it additionally contains calls of the life cycle methods {@link #enter()} and
* {@link #leave()}, if the property doUseComponentLifeCycleMethods=true
* is set in guidesign.properties
.
* This Method can be overwritten by the application programmer. Do not forget
* to call super
if you want to use modeled initialization or life cycle
* methods of the component.
*/
abstract public void invoke(Composite parent);
/**
* This method calculates the data stream necessary to update the server side
* component so that its state equals this client side component.
*
* @param forceFull the meaning here is as follows: If forceFull, we do
* not trust the delta mechanism. That implies that all alive
* pages are transmitted with all their widget models. So the
* server side state of the component may be deliberately inconsistent
* before. If forceFull is false, only changed pages or stateless pages
* are transmitted.
*
* @see at.spardat.xma.mdl.Synchronization#externalize(at.spardat.xma.serializer.XmaOutput, boolean)
*/
public void externalize (XmaOutput xo, boolean forceFull) throws IOException {
// write properties
externalizeProperties (xo, forceFull);
// write boolean to indicate if stream is full or delta
xo.writeBoolean("full", forceFull);
if (forceFull) externalizeFull (xo);
else externalizeDeltas (xo);
}
/**
* Assumes that the server side components state is correct with respect to the
* intention that accumulated changes in all models may be safely applied to it.
* Then this method writes the delta information neccessary to update the
* server side component state in order to make it equal to this.
*/
private void externalizeDeltas (XmaOutput xo) throws IOException {
// we build three sets; the first is the set of alive models at the client
// that are not new and stateless
HashSet pOldStateless = new HashSet();
// client alive models that are not new and stateful
HashSet pOldStateful = new HashSet();
// the third set covers the new models
HashSet pNew = new HashSet();
// the union of the these sets represents the programmer visible alive page models
// at the client before the server side event
Iterator iter = getPageModels();
while (iter.hasNext()) {
PageClient p = (PageClient) iter.next();
if (p.hasModels()) {
if (p.isNew()) pNew.add(p);
else {
if (p.isStateless()) pOldStateless.add(p);
else pOldStateful.add(p);
}
}
}
/**
* Write header information; this information is necessary for the server to
* adjust the set of alive pages.
*/
// old stateless pages must be created at the server --> long header
xo.writeShort("numOldStateless", pOldStateless.size());
iter = pOldStateless.iterator();
while (iter.hasNext()) {
writeLongHeader((PageClient) iter.next(), xo);
}
// old stateful pages must already exist at the server --> short header
xo.writeShort("numOldStateful", pOldStateful.size());
iter = pOldStateful.iterator();
while (iter.hasNext()) {
writeShortHeader((PageClient) iter.next(), xo);
}
// new pages must be created at the server --> long header
xo.writeShort("numNew", pNew.size());
iter = pNew.iterator();
while (iter.hasNext()) {
writeLongHeader((PageClient) iter.next(), xo);
}
// out of the set (pOldStateful union pOldStateless union pNew), write the page data
// that really changed
HashSet all = new HashSet();
all.addAll(pNew);
all.addAll(pOldStateful);
all.addAll(pOldStateless);
externalizePageSet (all, xo, false);
}
// writes only the id of the page
private void writeShortHeader (PageClient p, XmaOutput xo) throws IOException {
xo.writeShort("id", p.getId());
}
// writes the id, the parent id and the typeId.
// Necessary for pages which have to be created at the server
private void writeLongHeader (PageClient p, XmaOutput xo) throws IOException {
xo.writeShort("id", p.getId());
PageClient parent = p.getParent();
short parentId = (parent == null ? -1 : parent.getId());
xo.writeShort("parntId", parentId);
xo.writeShort("typeid", p.getTypeId());
}
/**
* Here, we do not rely on any state the server component has. All models alive with
* all their data is transmitted.
*/
private void externalizeFull (XmaOutput xo) throws IOException {
// collect the all alive pages
HashSet pages = new HashSet();
Iterator iter = getPageModels();
while (iter.hasNext()) {
PageClient p = (PageClient) iter.next();
if (p.hasModels()) {
pages.add(p);
}
}
// write header information for every page
xo.writeShort("numPages", pages.size());
iter = pages.iterator();
while (iter.hasNext()) {
writeLongHeader ((PageClient)iter.next(), xo);
}
// fully write these pages
externalizePageSet (pages, xo, true);
}
/**
* This method gets the data stream after a server side event and applies
* the changes to this client side component.
*
* @see at.spardat.xma.mdl.Synchronization#internalize(at.spardat.xma.serializer.XmaInput)
*/
public void internalize (XmaInput in) throws IOException, ClassNotFoundException {
// properties
internalizeProperties(in);
// pages
internalizePageSet(in);
}
/**
* Returns the global context.
* @return XMAContext
*/
public XMAContext getContext() {
return session_.getContext();
}
/**
* Returns the Session this belongs to (you can rely on the returned object not to be null).
*/
public XMASessionClient getSession () {
return (XMASessionClient) session_;
}
/**
* Returns the Session this belongs to (you can rely on the returned object not to be null).
*/
public IRtXMASessionClient getRTSession () {
return (IRtXMASessionClient) session_;
}
/**
* Returns if the clients page model state is out of sync with respect to
* the servers state.
* This method must not be called or overwritten outside the framework.
*/
public boolean isOutOfSyncWithServer() {
return outOfSyncWithServer_;
}
/**
* Sets the out of sync state.
* This method must not be called or overwritten outside the framework.
*/
public void setOutOfSyncWithServer(boolean b) {
outOfSyncWithServer_ = b;
}
/**
* Constructs a {@link at.spardat.xma.rpc.RemoteCall RemoteCall} object to execute a
* server side method with the provided name. The corresponding server side Component
* class must have a method with the signature
*
* void <namEvent> (RemoteCall call, RemoteReply reply)
*
* This method will be called if you call execute on the RemoteCall
* object returned by this.
*
* @param namEvent the name of the server side method to call
* @return a RemoteCall object
*/
protected RemoteCallClient newRemoteCall (String namEvent) {
return new RemoteCallClient (this, namEvent);
}
/**
* Displays the provided notification in a modal message box.
*
* @return A reaction constant of the class INotification, this is one of the constants
* starting with praefix R_ and indicates the pressed push button on the
* message dialogue.
*/
public int showMessage (INotification notification) {
boolean disposeShell = false;
Shell shell = null;
try {
// find a suitable shell
if(shell==null) shell = getDisplay().getActiveShell();
if(shell==null) {
shell = new Shell (getDisplay());
disposeShell = true;
}
// show the box
return NotificationBox.show (notification, shell, getContext(), getSession());
} finally {
if(disposeShell) { shell.dispose();}
}
}
/**
* Used as key in the HashMap of fonts.
*/
private static class FontDescriptor {
String fName;
int fHeight;
int fStyle;
public FontDescriptor (String name, int height, int style) {
fName = name;
fHeight = height;
fStyle = style;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals (Object obj) {
FontDescriptor fdOther = (FontDescriptor)obj;
return fName.equals(fdOther.fName) && fHeight == fdOther.fHeight && fStyle == fdOther.fStyle;
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return fName.hashCode() ^ fHeight ^ fStyle;
}
}
/**
* Creates the Task with the given name. The default implementation
* takes the name as the fully qualified classname of the Task.
* @param name unique name for the task within the component.
* @since 1.4.0
*/
public ITask createTask(String name) {
try {
Constructor con = Class.forName(name).getConstructor(new Class[]{ComponentClient.class});
return (ITask) con.newInstance(new Object[] {this});
} catch (InvocationTargetException e) {
throw new SysException(e.getTargetException());
} catch (Exception e) {
throw new SysException(e);
}
}
/**
* Is called at the end of RemoteCallClient.execute(). May be overwritten
* by subclasses to implement some RPC-post processing. Is not called,
* if the RPC terminates with exceptions.
*
* @param rc the RemoteCallClient whose execute method is about to end
* @param reply the RemoteReply object that execute will return
*/
public void rpcFinished (RemoteCallClient rc, RemoteReply reply) {
}
/**
* Stores the page of the given parentComposite for using in exception handling.
* Exceptions thrown in component {@link #enter()} or {@link #leave()} methods
* are shown using this page
* @param parentComposite used to determine its corresponding page.
* May be null; in this case no page is stored.
* @since 2.2.0
*/
protected void setInvokingPage(Composite parentComposite) {
invokingPage=(PageClient) parentComposite.getData();
}
/**
* Notify the Component, that {@link #invoke(Composite)} is called.
* @since 2.2.0
*/
protected void enterBaseInvoke() {
try {
enter();
} catch (Exception exc) {
showException(exc);
}
}
/**
* This method will be called by the generated method {@link #invoke(Composite)}
* before any page is invoked.
* It can be overwritten for some initializations.
* @since 2.2.0
*/
protected void enter() {}
/**
* Notify the Component, that {@link #invoke(Composite)} is finished.
* @since 2.2.0
*/
protected void leaveBaseInvoke() {
try {
leave();
} catch (Exception exc) {
showException(exc);
}
}
/**
* This method will be called by the generated method {@link #invoke(Composite)}
* after the invocation of the page is finished.
* It can be overwritten for some cleanups.
* @since 2.2.0
*/
protected void leave() {}
/**
* Shows the given exception. If {@link #invokingPage} is not null
,
* it is used to show the exception.
* @since 2.2.0
*/
private void showException(Exception exc) {
if(invokingPage!=null) {
invokingPage.showException(exc);
} else {
PageClient.showExceptionImpl(exc,null,this);
}
}
}