⬆️ ⬇️

Stand-alone application RAP

Greetings to all! This is my first article, so please take it with understanding.



Since I first saw RAP and OSGi, a year has passed, but at first glance I just fell in love with these technologies. Unfortunately, even the network has very little documentation on RAP, which allows you to write something cool (except hello world) from scratch. First, of course, you need to know what OSGi is. On this topic, the information in the network is enough - you can google. Since the article is about RAP, it is understood that the reader already knows how to create OSGi bundles, how to install and run them.



That is, the task is set as follows: “to make the custom interface of the site using the RAP”. How to create an OSGi bundle project in Eclipse, the reader, I assume, knows.



So. Practically all examples of using RAP are based, apparently, on one principle - no one will ever use anything other than the workbench. No doubt, workbench is remarkable in business applications when it is necessary to operate with tabular data and the interface should not be very intuitive and flexible. However, when the task sounds like “make a site using RAP” - workbench is no longer suitable.

')

First you need to make an entry point to the application. And without the use of Declarative Services. In this case, and specifically in this case, the DS is evil. I’ll say right away that in my application there is also MVC, where Application is a View, there is also a usecase concept ... Such a “disgrace” in general cannot be done with the help of DS. But we will go in a simplified way, for a start.



Create an abstract class entry point to the application, then to inherit from it our application:



abstract public class ApplicationEntryPoint implements EntryPoint { private ApplicationSession mSession; private ApplicationWindow mApplicationWindow; private ApplicationController mController; private String mDeferredUsecaseRun; public ApplicationEntryPoint(UseCaseRegister usecaseRegister) { mSession = new ApplicationSession(); } public ApplicationSession getSession() { return mSession; } protected Shell createMainShell( Display display ) { Shell shell = new Shell(display, SWT.NO_TRIM); shell.setMaximized(true); shell.setData(RWT.CUSTOM_VARIANT, "mainshell"); shell.setLayout(new FillLayout()); return shell; } protected void clearShell(Shell shell) { Control[] controls = shell.getChildren(); for (int i = 0; i < controls.length; i++) { if(controls[i] != null) { controls[i].dispose(); } } } } 




Here is a simplified entry point class. We are interested in two methods: createMainShell - which creates a Shell - in terms of SWT is the main window of the application, and in our case it is a page in the browser. And clearShell, which simply deletes everything on the page, that is, in the main application window. If you need to show other content, simply destroy everything that was in the shell and fill it with new data.



Next, create an ApplicationConfig:



 public class ApplicationConfig implements ApplicationConfiguration { public ApplicationConfig() {} public void configure( Application application ) { application.setOperationMode(OperationMode.SWT_COMPATIBILITY); application.addResource("/images/16/help2.png", new ResourceLoader() { @Override public InputStream getResourceAsStream(String arg0) throws IOException { return ApplicationConfig.class. GetClassLoader(). getResourceAsStream("/images/16/help2.png"); } }); Map<String, String> properties = new HashMap<String, String>(); properties.put( WebClient.FAVICON, "/images/16/help2.png" ); properties.put( WebClient.PAGE_TITLE, "Public area" ); application.addEntryPoint("/public", new PublicAreaEntryPointFactory(), properties); properties = new HashMap<String, String>(); properties.put( WebClient.PAGE_TITLE, "Main area" ); application.addEntryPoint("/main", new MainApplicationEntryPointFactory(), properties); } } 




This implies that you can configure several areas accessible to different URIs: in this case, / public and / main. Each region can have its own favicon and page title. An application in RWT is created through a factory, which we will now do.



 abstract public class ApplicationEntryPointFactory implements EntryPointFactory { public ApplicationEntryPointFactory() {} public EntryPoint create() { return null; } } 




This is an abstract factory, you never know what will come in handy. What then reshape the entire application - do it right away. I will say that it was useful to me.



I almost forgot about the class of the application session, which is just used right through, throughout the application:



 final public class ApplicationSession { private PersistentManager mPersistent; private HttpSession mHttpSession; private String mLogin = ""; private Boolean mLoggedIn = false; private Locale mLocale = null; private User mUser; private Logger mLogger; public ApplicationSession() { mLocale = new Locale("ru", "RU"); mHttpSession = RWT.getUISession().getHttpSession(); mPersistent = new PersistentManager("mo"); /* *      . */ if (mHttpSession.getAttribute("login") != null) mLogin = (String) mHttpSession.getAttribute("login"); if (mHttpSession.getAttribute("user") != null) mUser = (User) mHttpSession.getAttribute("user"); mLogger = LoggerFactory.getLogger(ApplicationSession.class); } final public void login(User user, String login) { mLogin = login; mPersistent.setUser(user); mHttpSession.setAttribute("login", mLogin); mHttpSession.setAttribute("user", user); logger().debug("   {}", mLogin); } final public Logger logger() { return mLogger; } final public void setUser(User user) { mUser = user; mHttpSession.setAttribute("user", user); } final public User getUser() { return mUser; } final public PersistentManager persistent() { return mPersistent; } final public String getId() { return mHttpSession.getId(); } final public Locale getLocale() { return mLocale; } final public void setLanguage(String language) { if (language.toUpperCase().equals("RUSSIAN") || language.toUpperCase().equals("RU")) { mLocale = new Locale("ru", "RU"); } else { mLocale = new Locale("en", "EN"); } } } 




As you can see, in the session we store all that is possible. Here, both the ORM and the link to the HTTP session and the User object User and the user's locale and logger ... In general, everything you need personally at any point in the application can be stored in the session. I have it available everywhere, even other application bundles.



Well, then, we implement our abstract EntryPoint:



 /** *       . *       -   *     . */ public class MainApplicationEntryPointFactory extends ApplicationEntryPointFactory { public MainApplicationEntryPointFactory() { super(); } @Override public EntryPoint create() { MainApplicationEntryPoint mainApp = new MainApplicationEntryPoint(getUsecaseRegister()); return mainApp; } } /** *     ,    . *            *    URI,    . */ public class MainApplicationEntryPoint extends ApplicationEntryPoint { private Shell mShell; private CommonController mLoginController; private ApplicationController mCtrl; public MainApplicationEntryPoint() { super(); } @Override public int createUI() { Display display = new Display(); mShell = createMainShell( display ); //    try { if (getSession().getUser() != null) { //      //   . mCtrl = new MainApplicationController(getSession(), mShell); mCtrl.init(); } else { mCtrl = new PublicAreaController(getSession(), mShell); mCtrl.init(); } catch (Exception ex) { MessageDialog.openError(mShell, "!", ex.getMessage()); } //  ,      , //      . mShell.open(); //   while( !mShell.isDisposed() ) { if( !display.readAndDispatch() ) { display.sleep(); } } display.dispose(); return 0; } } 




I already wrote that I have MVC, so everything inside the main window is already created using the appropriate controllers. For the public domain and for the application - its controller for each. But this is what works already inside the application.



In general and in general, Shell is the same Composite and it can be used for packaging controls and other composites into it. If nothing is created in it, then we get an empty shell. The principle of working with him can be found in the SWT literature. But, importantly, it will be an application available at a specific URI.



More importantly, we are no longer tied to the architecture that the RWT workbench provides. However, in order to use resources (for example, pictures or external JS), you need to change the application context to your own. I will give another example of the activator of the bundle application:



 public class Activator implements BundleActivator { public void start(BundleContext context) throws Exception { /* *    */ Dictionary<String, Object> props = new Hashtable<String, Object>(); props.put("contextName", "app"); context.registerService(ApplicationConfiguration.class.getName(), new ApplicationConfig(), props); } public void stop(BundleContext context) throws Exception { } } 




Thus, the application will be accessible through a context that will participate in the URI: / app / public or / app / main.



Ps. The code that I gave is approximate, conceptual. Stupidly copy it and expect that it will work - it will not work. However, if I had such a manual in my time, one could save a lot of time.



Pps. For comrades who want to get to know each other better. RAP is the former Rich Ajax Platform, now the Remote Application Platform. RAP is a development of the Eclipse Foundation and is a Java toolkit for building a thin browser client. Information about the utility and features of this project is available on eclipse.org/rap . One of the main features is the open JSON-based data exchange protocol between the client (browser) and the server. The second is RWT overrides the SWT interfaces. That is, almost everything that is true for SWT can be ported, and this is a very big feature for an effective code-reusage. Theoretically, the same application can be applied to the classpath differently, run as a service, with the client in the form of a browser or as a desktop Java application. And this with minimal code changes. Almost similar functions, though not so fundamentally defining the architecture of building an interface, are performed by GWT.

Source: https://habr.com/ru/post/179411/



All Articles