Scout/Documentation
Contents
Overview
Architecture
Main Parts of a Scout Project
Client,shared,swt,server Equinox client server
Client / Server Communication
Service Tunnel
Proxy services, Service Factories Entry point server (servlet) Outgoing point client
Message Structure
Base64 encoded Serialized objects
Session Handling
ServerSession
ClientSession
Client Concepts
Separation of UI and GUI
Job Queue
Component Model
Client Session
The client session is the main entry point for client-server communication.
Desktop
The desktop is the entry point of every Scout client application. It can (may) consist of top-level menus, active message box stack, set of available outline, active outline, active tableview, active detail form, active search form, form stack (swing: dialogs on desktop as JInternalFrames; eclipse: editors or views), dialog stack of modal and non-modal dialogs (swing: dialogs as JDialog, JFrame; eclipse: dialogs in a new Shell).
Outline
Typically a Desktop holds multiple outlines. They represent different entry points for the navigation within the application. For every outline a tree is available which allows navigating within the application.
Sorting of Columns
- Oracle (or whatever database you prefer) sorts the columns, if an
order by
clause is specified. Oracle sorts according to theNLS_SORT
parameter, which is set per database and can be overwritten in the session.select * from V$NLS_PARAMETERS WHERE PARAMETER = 'NLS_SORT';
tells you the current setting. - If you click on a column (client), Scout does the sort.
- StringColumn: Scout orders the entries according the
NlsLocale
(seejava.text.Collator
) - SmartColumn:
- If
isSortCodesByDisplayText()
is set, the sort is done by Java according theNlsLocale
. - otherwise the Sortcode is used.
- If
- StringColumn: Scout orders the entries according the
Form
A form is both a model structure of a ui concept known as dialog or view and also a model of a wizard page. Wizard buttons are added automatically to the main box if missing.
Form fields
Form fields are the basic elements for user inputs fiels within a form. Examples are:
- TextField
- SmartField
- NumberField
- DateField
- FileChooser
- ListBox
- TreeBox
- CheckBox
- RadioButton
- ToogleButton
Futhermore there exists composites fields like:
- GroupBox
- TabBox
- SequenceBox
- SnapBox
- RangeBox
- RadioButtonGroupBox
Menu
The menu component include all links, functionalities, etc... available within the application.
Tool
Tool component is used for grouping or dividing different views. This can be used for building business views on datas or just structuring your own application.
Wizard
Wizards support a user to work in a process driven approach on a task.
Server Concepts
Server Side Equinox
Jetty, ServerApplication as Startup Point
Transaction Handling
Configuration
SQL Support
Statement Builder
config.ini
Inside of the config.ini in the server it is possible to override the member variables of services.
For example:
com.bsiag.mnet.server.services.common.sql.SqlService#directJ dbcConnection=true
If the service SqlService has a setter method for the member directJdbcConnection then the member has at runtime the value true.
With Scout Eclipse this works for all classes which extends AbstractService
For other classes it must be done by yourself for example with the class FilterConfigInjection at startup.
Server Side Proxy
If the server application needs to access a server in the web and in between your application server and the server in the web is a proxy that needs authentication, you need to set the proxy parameters (like username or password) somewhere.
In the web you find several sites that tell you to start Java with the following options:
-Dhttp.proxyHost=proxyHost
-Dhttp.proxyPort=proxyPort
-Dhttp.proxyUser=proxyUser
-Dhttp.proxyPassword=proxyPassword
(You can set these options in the Tomcat by right-clicking on the Tomcat tray icon, then click on 'Configure...', go to the Java tab & add the four lines to the Java options)
When the request is sent, the proxy host and the proxy port are known & the request is sent over the proxy. However the authentication does not work. Even though these options are loaded when Java / the Tomcat is started.
Either Java does not care about the options for the username and the password or the proxy we use does the authentication not as expected / usual.
If you have problems with the upper solution, you can solve the problem by setting the proxy informations in Java before you send the request (read the proxy informations from the config.ini-file).
Your code could look similar to the following code snippet:
URL url = new URL(myUrl);
URLConnection conn;
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(myProxyHost, myProxyPort));
conn = url.openConnection(proxy);
String encoded = Base64Utility.encode((myProxyUsername + ":" + myProxyPassword).getBytes());
conn.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
However, with this solution you need to set the proxy parameters for each request anew.
Security
Authentication / Authorization
- Failover Switch
- Determines whether the next filter should be used to try to authenticate / authorize the user.
The last filter has to set this tofalse
- Authentication
- Identify the user trying to access the system
- Authorization
- Determine the users rights and permissions according to his identity
Security Filters
The security filters need to be included as extensions in the server's plugin.xml
as extensions. The configuration of these extensions points works as defaults, but is overriden by the #Settings in config.ini.
BasicSecurityFilter | org.eclipse.scout.rt.server.servlet.filter.BasicSecurityFilter
|
---|---|
The basic filter with the usernames and passwords directly configured in the configuration file (or the extension point).
E.g.: org.eclipse.scout.rt.server.servlet.filter.BasicSecurityFilter#users=frank\=test,mark\=test,steve\=test |
|
DataSourceSecurityFilter | org.eclipse.scout.rt.server.servlet.filter.DataSourceSecurityFilter
|
Uses the users and passwords defined in the database. |
Settings in config.ini
For every filter you can set the four options (example with the BasicSecurityFilter
).
org.eclipse.scout.rt.server.servlet.filter.BasicSecurityFilter/process#active=false org.eclipse.scout.rt.server.servlet.filter.BasicSecurityFilter/updatesite#active=false org.eclipse.scout.rt.server.servlet.filter.BasicSecurityFilter/test#active=false org.eclipse.scout.rt.server.servlet.filter.BasicSecurityFilter/services#active=true
The settings determine, whether the security filter is used for a given servlet path. The often used paths are:
- process
- This is where all Scout internals are connect, i.e. the calls from the client to the server.
- updatesite
- Authentication for users connecting to the updatesite (via browser) to download the client. This also includes the automatic updates of the client.
- test
- Authentication for test servlets
- services
- Authentication for webservices, this will probably always be the
BasicSecurityFilter
as the other side's implementation has the credentials configured somewhere as well.
org.eclipse.scout.rt.server.servlet.filter.BasicSecurityFilter#failover=true
Determines, whether the filter should deny access, if not successfully authenticated (false
) or if the next filter should try to authenticate (true
).
Example Setups
Granting
Describe the Permisssion Classes, the permission store, ACCESS....
Utilities
Codetypes
NLS-Support
to do
Logging
Scout has moved to slf4j. slf4j is a logging facade, which is implemented by various loggers.
slf4j also offers bridges that map calls to the "old" loggers to slf4j.
The development environment contains just Logback, impl.simple, impl.nop and the bridges.
Logger Usage
Scout code should only use the IScoutLogger
.
private static IScoutLogger logger = ScoutLogManager.getLogger(MyOwnClass.class);
The IScoutLogger
-Interface is implemented by SLF4JDelegateLogger
, which is returned by the above call to ScoutLogManager.getLogger(Class)
. This wrapps one of the various possible log implementations.
In your config.ini
you can set the property org.eclipse.scout.commons.logger.level
. If set to another value than -1 it will override all other configurations for logging. You will probably want to not set this property and configure the logging in a logback.xml
(see Using slf4j/Logback).
Example:
### Logging # sets the default loglevel, -1=INHERITED (definitions from logback-test.xml), # 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=TRACE, if set and to another value than -1 this will take precedence to all configurations in logback-test.xml org.eclipse.scout.commons.logger.level=2
Logger Implementations
- Logback
- The native implementation and a successor to log4j
- impl.simple
- Redirection of slf4j calls to std-out
- impl.Log4j
- Redirection of slf4j calls to log4j
- impl.jakarta.commons.logging
- Redirection slf4j calls to jcl
- impl.Java.util.logging
- Redirection of slf4j calls to jul
- impl.nop
- Redirection of slf4j calls to "nothing"
Using slf4j/Logback
To use slf4j/Logback the following fragments / plugings are required. Include them as dependencies in your product-file.
- ch.qos.logback.core
- ch.qos.logback.slf4j
- org.slf4j.api
- org.slf4j.ext
- org.slf4j.jcl (optional)
- org.slf4j.jul (optional)
- org.slf4j.log4j (optional)
- a dedicated fragment:
fragment.name.org
Make sure the following dependencies have NOT been included:
- org.slf4j.impl.nop
- org.slf4j.impl.siml
Also do not include fragments implementing log4j (these calls will be intercepted by org.slf4j.log4j and forwarded to slf4j).
fragment.name.org
Additionally a dedicated fragment is required (the name is up to you of course). The fragment contains the configuration file for logback and a manifest.
MANIFEST.MF
:
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Logback Fragment Bundle-SymbolicName: fragment.name.org Bundle-Version: 1.0.0.qualifier Bundle-Vendor: .... Fragment-Host: org.slf4j.api;bundle-version="1.6.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.6
logback-test.xml
:
<configuration scan="true"> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> <pattern>%d{ISO8601} %-5level [%thread] %logger: %msg%n</pattern> </encoder> </appender> <logger name="org.eclipse.scout.commons.ConfigIniUtility"> <level value="WARN" /> </logger> <root> <level value="WARN" /> <appender-ref ref="CONSOLE" /> </root> </configuration>
logback.xml
:
<configuration scan="true"> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>c:/temp/project.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>c:/temp/project-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 100MB --> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!-- keep 30 days' worth of history --> <maxHistory>30</maxHistory> </rollingPolicy> <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> <pattern>%d{ISO8601} %-5level [%thread] %logger: %msg%n</pattern> </encoder> </appender> <logger name="org.eclipse.scout.commons.ConfigIniUtility"> <level value="WARN" /> </logger> <logger name="org.eclipse.scout.rt.server.services.common.sql"> <level value="INFO" /> </logger> <logger name="org.eclipse.scout.rt.ui.swing.SwingIconLocator"> <level value="WARN" /> </logger> <root> <level value="INFO" /> <appender-ref ref="FILE" /> </root> </configuration>
build.properties
bin.includes = META-INF/,\ licence.html,\ logback-test.xml
Logback Configuration
Different Configuration for Production and Development
You probably do not want the same configuration for production / deployment and development. An easy way to solve this is to have two configuration files. A logback.xml
for production / deployment and a logback-test.xml
for the development (both in the fragment fragment.name.org
). Then you edit the build.properties
so the logback-test.xml
is not included in the build.
If you start the Scout application from Eclipse, the logback-test.xml
takes precedence.
And for the deployment there is only the logback.xml
, so nothing to worry about either.
Limitations: This does only allow for two configurations and only one that is deployed. If you have several systems with different configurations you need another solution. You will probably want to have your xml file somewhere else and not included in the application.
Automatically Rescanning the Configuration
The automatic scanning for configuration changes is enabled by the attribute scan="true"
in the configuration xml.
<configuration scan="true">
- TODO: Where does it look for the configuration?
Scout Services
scout.commons
Scheduler
- The instance for the Job is only created exactly once. Every run of a job is by the same instance.
- The timer (when to start) is hardcoded (see example).
Usage
- Derive a class from
AbstractSchedulerJob
- implement a constructor calling
super(groupId, jobId);
- implement / override
execAcceptTick
- implement / override
run
- In the ServerApplication you need something like
public class ServerApplication implements IApplication{ public Object start(IApplicationContext context) throws Exception { //start the scheduler Scheduler scheduler=new Scheduler(Activator.getDefault().getBackendSubject(),ServerSession.class); scheduler.addJob(new LoadJobs()); // scheduler.addJob(new FetchMailSchedulerJob()); scheduler.addJob(new LdapSchedulerJob()); scheduler.addJob(new UpdatePLAOrdersJob()); scheduler.start(); Activator.getDefault().setScheduler(scheduler); ...
Example:
public class MyJob extends AbstractSchedulerJob { private static IScoutLogger s_logger =ScoutLogManager.getLogger(MyJob.class); private final static String groupId = "MyGroup"; private final static String jobId = "MyJob"; /** * <p><code>true</code> the job is currently running, <code>false</code> else</p> * <p>Access needs to be guarded / synchronized by <code>this</code>, because it is possible, that the same reference to the job * is called twice.</p>. */ private boolean m_running; public MyJob() { super(groupId, jobId); } @Override protected boolean execAcceptTick(TickSignal signal, int second, int minute, int hour, int day, int week, int month, int year, int dayOfWeek, int dayOfMonthReverse, int dayOfYear, int secondOfDay) { return (second==0 && minute%10==0); /* start every 10 minutes */ } @Override public void run(IScheduler scheduler, TickSignal signal) throws ProcessingException { synchronized (this) { if (m_running) { /* prevent the job from being started twice */ s_logger.warn("The Job " + getGroupId() + "." + getJobId() + " is already running, but should be started. Job was not started."); return; } m_running = true; } try { s_logger.info("Started scheduled job: " + getGroupId() + "." + getJobId() + ", process all PLA Orders."); IXYZService service = SERVICES.getService(IXYZService.class); try { service.doStuff(); } catch (Exception e) { s_logger.error("Error in Job " + getGroupId() + "." + getJobId(), e); } s_logger.info("Finished scheduled job: " + getGroupId() + "." + getJobId() + ", process all PLA Orders"); } finally { synchronized (this) { m_running = false; } } } }
Client Notification
Scout SDK
Idea Behind Scout SDK
Main Features
Building Forms and Outlines
Generation of DTOs (form data, field data)
NLS Editor
Support for Webservices
Architecture of Scout SDK
Describe how JDT and PDE is used
Back to Scout