Very High Activity
I Use This!


Analyzed 8 days ago. based on code collected 8 days ago.
Posted 2 days ago
Today a new beta is available from our download and update sites! Remember that since Beta1 we require Java 8 for installing and ... [More] using of JBoss Tools. We still support developing and running applications using older Java runtimes. See more in Beta1 blog. Installation JBoss Developer Studio comes with everything pre-bundled in its installer. Simply download it from our JBoss Products page and run it like this: java -jar jboss-devstudio-.jar JBoss Tools or Bring-Your-Own-Eclipse (BYOE) JBoss Developer Studio require a bit more: This release requires at least Eclipse 4.5 (Mars) but we recommend using the Eclipse 4.5 Mars JEE Bundle since then you get most of the dependencies preinstalled. Once you have installed Eclipse, you can either find us on the Eclipse Marketplace under "JBoss Tools" or "JBoss Developer Studio". We are now using Eclipse Marketplace feature of having just one market place entry for all old versions. For JBoss Tools, you can also use our update site directly if you are up for it. Note: Integration Stack tooling will become available from JBoss Central at a later date. What is new ? Full info is at this page. Some highlights are below. Bower We’ve added support for easy setup and invocation of Bower using your locally installed bower command line tool on Windows, OS X and Linux. We provide a Bower Init wizard for getting started. Once your project has a bower.json file you can now easily run bower update by right-clicking on the file and selecting Run ▸ As…​ ▸ Bower Update. We are working on contributing this and additional Javascript integration to Eclipse JSDT. We will keep you posted! OpenShift v3 We continue to work on improving OpenShift v3 tooling and this release has a few new features and important bug fixes but overall OpenShift v3 tooling is still in very early stages. Manage your OpenShift v3 Projects You can now create and delete OpenShift v3 projects. If you try to create a new application, but you have no project yet, the tools will prompt you to create one first. Once you are done you can always get back and manage your OpenShift projects via a link in the application wizard. Manually Trigger Builds You can manually trigger builds when selecting your Build Configs in the OpenShift Explorer. Once you triggered you should see a new build appear in the Builds category in the OpenShift Explorer. You can see its state next to its name or in the Properties view. Refreshing the Explorer will show you when the build completes. Port Forwarding Assuming that your application exposes ports you can now forward those to your local machine with JBoss Tools 4.3.0.Beta2. More details of new OpenShift v3 features are at Whats New. Java EE Batch Tooling The batch tooling now has hyperlink support for @BatchProperty to navigate between classes and their relevant job .xml files. There are more news at Whats New. Exploded nested jars In WildFly 8.2 there is now support for hotloading resources from exploded jars inside deployments, i.e. a jar inside your WEB-INF/libs. This allows you to have faster reload times for module web applications using resources from nested jars. Thanks to patch from Vsevolod Golovanov we now support this when you are using our server tools. Thanks Vsevolod! Deploy Hybrid project to FeedHenry You can now take a hybrid mobile project created with Thym and deploy it to a FeedHenry cloud. Enjoy! Alexey Kazakov [Less]
Posted 3 days ago by (Christian Pontesegger)
This years EclipseCon will be very exciting for me. Not only was my talk proposal I love scripting accepted as an early bird pick, there are also other parties starting to propose talks concerning EASE.I love to see this project start to fly and ... [More] like to give you some insights and an outlook of what to expect at EclipseCon.How it all beganI remember my first EclipseCon in 2012. I had this intriguing idea in my mind about a scripting framework in Eclipse, but no idea whom to talk to about it. By chance I met Wayne Beaton who offered help and encouraged me to find some interested parties to support my idea.It took me almost a year to provide a prototype and start advertising this idea, but soon after my first post on this topic on this blog, Polarsys got interested and things started to move very quickly. In summer 2013 we agreed to introduce scripting (called EScript at that time) to the e4 incubator. Thanks to Paul Webster we got a nice place to play and learn about the eclipse way of working on a software project.When the call for papers openend for EclipseCon Europe 2013 I thought 'What the hell' and sent a proposal for a talk on scripting. I never expected it to get accepted, but few months later I found myself talking about scripting at EclipseCon.Encouraged by the positive feedback Arthur Daussy and myself worked hard on the implementation. Finally we moved out of the e4 incubator in 2014 and now you may install this great scripting environment in your IDE.The role of EclipseConMeeting users, committers and eclipse staff members in person helped me a  lot  to make this project happen. In the beginning it was the encouragements and good advice I got from experienced members. Now I am looking forward to hear the user side, your success stories, your fresh ideas.If you read this far you are definitely interested in scripting, so take the chance and meet me in person @ EclipseCon. If there is enough interest, we may have a BOF on scripting topics there. please leave me a note if you would like to see this happen.I love scripting - what we will coverThis talk will give an overview what scripting can do for you and how you can implement it in your IDE or RCP. We will start to have a short look on the architecture (1%) and then immediately switch to a live demo (99%). There we will start with simple script commands, continue with Java integration and introduce scripting libraries. Next we will learn how to provide custom libraries for your RCP.Once the basics are clear, we will start to extend the IDE with user scripts, start to write scripted unit tests and finally show rapid prototyping by dynamically instantiating java files from your workspace.Expect a fast roller coaster ride through the features of EASE. I am sure you want more of it after your first ride!see you at EclipseCon [Less]
Posted 4 days ago
Join us November 3-5, 2015 at the Forum am Schlosspark in Ludwigsburg, Germany.
Posted 4 days ago
The Sphinx framework adds functionality for model management to the base EMF tooling. Since it was developed within the Artop/AUTOSAR activities, it also includes code to make sure that the name-based references of AUTOSAR models are always correct.  ... [More] This includes some post processing after model changes by working on the notifications that are generated within a transaction. Detecting changes in reference URIs and dirty state of resources. Assume that we have two resources SR.arxml (source) and target (TR.arxml) in the same ResourceSet (and on disk). TR contains an element TE with a qualified name /AUTOSAR/P/P2/Target which is referenced from a source element SE that is contained in SR. That means that the string “/AUTOSAR/P/P2/Target” is to be found somewhere in SR.arxml Now what happens if some code changes TE’s name to NewName and saves the resource TR.arxml? If only TR.arxml would be saved, that means that we now would have an inconsistent model on disk, since the SR.arxml would still contain “/AUTOSAR/P/P2/Target” as a reference, which could not be resolved the next time the model is loaded. We see that there are some model modifications that affect not only the resource of the modified elements, but also referencing resources. Sphinx determines the “affected” other resources and marks them as “dirty”, so that they are serialized the next time the model is written to make sure that name based references are still correct. But obviously, only changes that affect the URIs of referencing elements should cause other resources to be set to dirty. Features that are not involved should not have that effect. Sphinx offers the possibility to specify specific strategies per meta-model. The interface is IURIChangeDetectorDelegate. The default implementation for XMI based resources is:  @Override public List detectChangedURIs(Notification notification) { List uriChangeNotifications = new ArrayList(); Object notifier = notification.getNotifier(); if (notifier instanceof EObject) { EObject eObject = (EObject) notifier; uriChangeNotifications.add(new URIChangeNotification(eObject, EcoreResourceUtil.getURI(eObject))); } return uriChangeNotifications; } This will cause a change notification to be generated for any EObject that is modified, of course we do not want that. In contrast, the beginning of the Artop implementation of AutosarURIChangeDetectorDelegate looks like this:  public List detectChangedURIs(Notification notification) { List notifications = new ArrayList(); if (notification.getNotifier() instanceof EObject) { EObject eObject = (EObject) notification.getNotifier(); if (IdentifiableUtil.isIdentifiable(eObject)) { Object feature = notification.getFeature(); if (feature instanceof EAttribute) { EAttribute attribute = (EAttribute) feature; // we check that modified feature correspond to the shortname of the identifiable if ("shortName".equals(attribute.getName())) { //$NON-NLS-1$ A notification on a feature is only processed if the modified object is an Identifiable and the modified feature is the one used for URI calculation (shortName in AUTOSAR). There is additional code in this fragment to detect changes in containment hierarchy, which is not shown here. So if you use Sphinx for your own metamodel with name based referencing, have a look at AutosarURIChangeDetectorDelegate and create your own custom implementation for efficiency.  LocalProxyChangeListener In addition, Sphinx detects objects that have been removed from the containment tree and updates references by turning the removed object into proxies! That might be unexpected if you then work with the removed object later on. The rationale is well-explained in the Javadoc of LocalProxyChangeListener: Detects {@link EObject model object}s that have been removed from their {@link org.eclipse.emf.ecore.EObject#eResource() containing resource} and/or their {@link EObject#eContainer containing object} and turns them as well as all their directly and indirectly contained objects into proxies. This offers the following benefits: After removal of an {@link EObject model object} from its container, all other {@link EObject model object}s that are still referencing the removed {@link EObject model object} will know that the latter is no longer available but can still figure out its type and {@link URI}. If a new {@link EObject model object} with the same type as the removed one is added to the same container again later on, the proxies which the other {@link EObject model object}s are still referencing will be resolved as usual and therefore get automatically replaced by the newly added {@link EObject model object}. In big models, this approach can yield significant advantages in terms of performance because it helps avoiding full deletions of {@link EObject model object}s involving expensive searches for their cross-references and those of all their directly and indirectly contained objects. It does all the same not lead to references pointing at “floating” {@link EObject model object}s, i.e., {@link EObject model object}s that are not directly or indirectly contained in a resource.         [Less]
Posted 5 days ago
The problem I was having when running SWTBot tests in Travis CI was that I could not use the new container-based infrastructure of Travis, which allows to cache things like the local maven repository. This was not possible since to run SWTBot tests ... [More] you need a Window Manager (in Linux, you can use metacity), and so you had to install it during the Travis build; this requires sudo and using sudo prevents the use of the container-based infrastructure. Not using the cache means that each build would download all the maven artifacts from the start. Now things have changed When running in the container-based infrastructure, you’re still allowed to use Travis’  APT sources and packages extensions, as long as the package you need is in their whitelist. Metacity was not there, but I opened a request for that, and now metacity is available Now you can use the container-based infrastructure and install metacity together (note that you won’t be able to cache installed apt packages, so each time the build runs, metacity will have to be reinstalled, but installing metacity is much faster than downloading all the Maven/Tycho artifacts). The steps to run SWTBot tests in Travis can be summarized as follows:sudo: false language: java jdk: oraclejdk7 cache: directories: - $HOME/.m2 env: DISPLAY=:99.0 install: true addons: apt: packages: - metacity #before_install: # - sudo apt-get update # - sudo apt-get install metacity before_script: - sh -e /etc/init.d/xvfb start - metacity --sm-disable --replace 2> metacity.err &I left the old steps “before_install” commented out, just as a comparison. “sudo: false” enables the container based infrastructure “cache:” ensures that the Maven repository is cached “env:” enables the use of graphical display “addons:apt:packages” uses the extensions that allow you to install whitelisted APT packages (metacity in our case). “before_script:” starts the virtual framebuffer and then metacity. Then, you can specify the Maven command to run your build (here are some examples: Happy SWTBot testing!     Be Sociable, Share! Tweet [Less]
Posted 6 days ago
Sometimes you want the latest and greatest Eclipse on Fedora, as it includes the latest bug fixes. E.g To do so, you will have to install the rawhide repository (1) and then update the Eclipse packages to those of Rawhide (2) 1) Download Rawhide ... [More] Repository The below will download the repository file into your /etc/yum.repos.d/ (for both yum and dnf). (This will not make dnf use Rawhide for all your packages, it simply gives it access to the repo on demand.) dnf install fedora-repos-rawhide 2) Update Eclipse to Rawhide This command will update all “Eclipse” packages on your system to that of Rawhide: sudo dnf --enablerepo=rawhide update $(sudo dnf list installed | grep eclipse | cut -f1 -d " ") Explanation: – This lists all installed Eclipse packages: sudo dnf list installed | grep eclipse – This get’s the first column delimited by spaces: cut -f1 -d " " – This enables rawhide only for this update command: --enablerepo=rawhide How to downgrade back I haven’t actually done this myself yet, so downgrade only at your own risk :-). But you can downgrade by removing the new packages and then re-installing them from the regular repos. Use same command as above but instead of ‘update’ use ‘remove. If you have success with downgrading, please feel free to post a comment to let me know and I’ll update this post. Updating Eclipse in the future If you want to update eclipse, run the command above again. I haven’t gotten around to figuring out a way to make Fedora always use Rawhide for Eclipse for updates, if you know, please feel free to leave a comment. [Less]
Posted 6 days ago
I had a fantastic time at OSCON last week. It was a crazy busy week for Twitter announcing that we are helping form the Cloud Native Computing Foundation and unifying some of the work that has been going on in the Kubernetes and Mesos ecosystems: ... [More] we're joining the CNCF! we're looking forward to seeing the #k8s and @ApacheMesos communities collaborate together — Twitter Open Source (@TwitterOSS) July 21, 2015 It’s rare that you see two communities and the large companies behind them put their egos besides and do what is better for everyone in the long term in the infrastructure space. We also formally joined the Open Container Initiative and plan on donating an AppC C++ implementation in the future: we are happy to officially join and support the Open Container Initiative at #OSCON — Twitter Open Source (@TwitterOSS) July 22, 2015 Thank you to everyone who came to our ping pong tournament party and learned a bit more about the sport of table tennis: #twitteroscon #PingPong doors are open & competition is fierce! — TwitterDev (@TwitterDev) July 23, 2015 We also had a great @TODOGroup panel at OSCON discussing how different companies are running and establishing open source offices… along with what works and some lessons learned: Twitter's OSS lead @cra on the @todogroup panel at #oscon – sharing insights on running an Open Source program — TwitterDev (@TwitterDev) July 22, 2015 Finally, thank you to everyone who came to my talk about lessons learned from Twitter creating its open source office on Thursday: @oscon slides finally posted, thank you to who came! — Chris Aniszczyk (@cra) July 24, 2015 It’s always amazing to see how many companies are starting to form open source offices, from my talk I tried to highlight some of the better known ones from larger companies and even startups (along with their mission statements): Google: “…tasked with maintaining a healthy relationship with the open source software development community” Intel: “…international team dedicated to working within open communities.” Samsung: “The Open Source Group was formed in 2013 to do the following: Help guide the company in effective consumption, collaboration, and development of open source software. Provide advocacy on behalf of Samsung in external open source communities. Develop consistent open source strategy and governance policies for the enterprise at large.” Microsoft: “Microsoft’s commitment to openness and collaboration is ingrained… These collaborations have enabled new scenarios for customers and partners to take open source software and integrate it with a Microsoft platform.” Box: “we give back to the open source community whenever possible, by contributing code to outside projects and sharing projects that we’ve developed internally” Dropbox: “Dropbox loves open source! We participate in the open source community by using open source software internally and open sourcing our own projects” Facebook: “…we’re keen users and publishers of open software. We’ll keep you up-to-date with our new projects and releases…” GitHub: Twitter: I really expect this trend to continue in the future, for example Box is looking to hire their first Head of Open Source and even  Guy Martin was just hired to create and run an open source office at Autodesk… Autodesk! My first week here @autodesk & already finding cool #OSS work we are doing. I’ll be on the hunt for more! — Guy Martin (@guyma) July 17, 2015 At the end of the day, as more businesses become software companies to some nature, they will naturally depend on a plethora of open source software. Businesses will look to find ways to build better relationships with the open source communities their software depends on to maximize value for their business, it’s in their best interests. [Less]
Posted 6 days ago
You’ve chosen e4 and JavaFX as the technologies to implement your cool rich client application. Congrats! In the first iteration you’ve implemented all the form UIs you need in your application which you made flashy with the help of CSS, animations ... [More] for perspective switches, lightweight dialogs as introduced in e(fx)clipse 2.0, … . In the 2nd iteration your task now might be to implement some scripting support but for that you require an editor who at least supports lexical syntax highlighting. So you now have multiple choices: Use a WebView and use an editor written in JavaScript like Orion Use the StyledTextArea shipped with e(fx)clipse 2.0 and implement all the hard stuff like paritioning, tokenizing, … Get e(fx)clipse 2.1 and let the IDE generate the editor for you If you decided to go with the last option the following explains how you get that going by developing a e4 JavaFX application like shown in this video Get e(fx)clipse 2.1.0 As of this writing e(fx)clipse 2.1 has not been released so you need to grab the nightly builds eg by simply downloading our All-in-One build. Set up a target platform We have a self-contained target platform feature ( available from our runtime-p2 repository to get started super easy. Warning: Make sure you uncheck “Include required software” because the target won’t resolve if you have that checked! Get e(fx)clipse 2.1 You need the latest builds from the e(fx)clipse nightly jobs. The easiest way to get started is to download our nightly all-in-one build from Setup the project The project setup is done like you are used to for all e4 on JavaFX applications. The wizard should have created: The main application module The feature making up the main application module The product definition require for exporting The release engineering project driving the build Now we need to add some dependencies to your MANIFEST.MF: org.eclipse.fx.core: Some Core APIs org.eclipse.fx.code.editor: Core (=UI Toolkit independent) APIs for code editors org.eclipse.fx.code.editor.fx: JavaFX dependent APIs for code editors org.eclipse.text: Core APIs for text parsing, … org.eclipse.fx.text: Core APIs for text parsing, highlighting, … org.eclipse.fx.text.ui: JavaFX APIs for text parsing, highlighting, … org.eclipse.fx.ui.controls: Additional controls for eg a File-System-Viewer OSGi-Service APIs we make use of when generateing DS-Services org.eclipse.fx.core.di: Dependency Inject addons org.eclipse.fx.code.editor.e4: code editor integration to e4 org.eclipse.fx.code.editor.fx.e4: JavaFX code editor integration to e4 For export reasons also add all those bundles to the feature.xml in Generate editor infrastructure Having everything configured now appropriately we start developing: Create package Create a file named dart.ldef and copy the following content into it package at.bestsolution.sample.code dart { partitioning { partition __dftl_partition_content_type partition __dart_singlelinedoc_comment partition __dart_multilinedoc_comment partition __dart_singleline_comment partition __dart_multiline_comment partition __dart_string rule { single_line __dart_string "'" => "'" single_line __dart_string '"' => '"' single_line __dart_singlelinedoc_comment '///' => '' single_line __dart_singleline_comment '//' => '' multi_line __dart_multilinedoc_comment '/**' => '*/' multi_line __dart_multiline_comment '/*' => '*/' } } lexical_highlighting { rule __dftl_partition_content_type whitespace javawhitespace { default dart_default dart_operator { character [ ';', '.', '=', '/', '\\', '+', '-', '*', '<', '>', ':', '?', '!', ',', '|', '&', '^', '%', '~' ] } dart_bracket { character [ '(', ')', '{', '}', '[', ']' ] } dart_keyword { keywords [ "break", "case", "catch", "class", "const", "continue", "default" , "do", "else", "enum", "extends", "false", "final", "finally", "for" , "if", "in", "is", "new", "null", "rethrow", "return", "super" , "switch", "this", "throw", "true", "try", "var", "void", "while" , "with" ] } dart_keyword_1 { keywords [ "abstract", "as", "assert", "deferred" , "dynamic", "export", "external", "factory", "get" , "implements", "import", "library", "operator", "part", "set", "static" , "typedef" ] } dart_keyword_2 { keywords [ "async", "async*", "await", "sync*", "yield", "yield*" ] } dart_builtin_types { keywords [ "num", "String", "bool", "int", "double", "List", "Map" ] } } rule __dart_singlelinedoc_comment { default dart_doc dart_doc_reference { single_line "[" => "]" } } rule __dart_multilinedoc_comment { default dart_doc dart_doc_reference { single_line "[" => "]" } } rule __dart_singleline_comment { default dart_single_line_comment } rule __dart_multiline_comment { default dart_multi_line_comment } rule __dart_string { default dart_string dart_string_inter { single_line "${" => "}" //TODO We need a $ => IDENTIFIER_CHAR rule } } } integration { javafx { java "" e4 "" } } } Xtext will prompt to add the Xtext nature to your project The sources are generated into the src-gen folder you should add that one to your build path It’s important to note that beside the files generated by the ldef-Language there are 2 files generated to your OSGi-INF-Folder by DS-Tooling from ca.ecliptical.pde.ds I won’t explain the details of the dart.ldef-File because there’s already a blog post with a detailed description of the file. The only part that is new is the integration section: integration { javafx { java "" e4 "" } } who configures the code generator to: Generate Java code for the partitioning and tokenizing Generate e4 registration informations in terms of OSGi-Services In contrast to the last blog where we’ve run our stuff in an NONE-OSGi/NONE-e4-world where we had to wire stuff ourselves this is not needed this time because the Eclipse DI container will take care of that! Define a Filesystem-Viewer-Part To browse the filesystem we need a viewer which might look like this: package; import; import java.nio.file.Path; import java.nio.file.Paths; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; import org.eclipse.e4.core.di.annotations.Optional; import org.eclipse.e4.ui.di.PersistState; import; import org.eclipse.fx.core.Memento; import org.eclipse.fx.ui.controls.filesystem.FileItem; import org.eclipse.fx.ui.controls.filesystem.ResourceEvent; import org.eclipse.fx.ui.controls.filesystem.ResourceItem; import org.eclipse.fx.ui.controls.filesystem.ResourceTreeView; import javafx.collections.FXCollections; import javafx.scene.layout.BorderPane; public class ResourceViewerPart { @Inject TextEditorOpener opener; private Path rootDirectory; private ResourceTreeView viewer; @PostConstruct void init(BorderPane parent, Memento memento) { viewer = new ResourceTreeView(); if( rootDirectory == null ) { String dir = memento.get("root-dir", null); if( dir != null ) { rootDirectory = Paths.get(URI.create(dir)); } } if( rootDirectory != null ) { viewer.setRootDirectories(FXCollections.observableArrayList(ResourceItem.createObservedPath(rootDirectory))); } viewer.addEventHandler(ResourceEvent.openResourceEvent(), this::handleOpenResource); parent.setCenter(viewer); } @Inject @Optional public void setRootDirectory(@Named("rootDirectory") Path rootDirectory) { this.rootDirectory = rootDirectory; if( viewer != null ) { viewer.setRootDirectories(FXCollections.observableArrayList(ResourceItem.createObservedPath(rootDirectory))); } } private void handleOpenResource(ResourceEvent e) { e.getResourceItems() .stream() .filter( r -> r instanceof FileItem) .map( r -> (FileItem)r) .filter( r -> r.getName().endsWith(".dart")) .forEach(this::handle); } private void handle(FileItem item) { opener.openEditor(item.getUri()); } @PersistState public void rememberState(Memento memento) { if( rootDirectory != null ) { memento.put("root-dir", rootDirectory.toFile().toURI().toString()); } } } Define the application e4 applications as you already know are not defined by code but with the help of the e4 application model which is stored by default in e4xmi-Files. The final model has to looks like this: The important parts are: DirtyStateTrackingAddon: Is a special addon who tracks the dirty state added to the applications Addon section Handler: We using a framework handler org.eclipse.fx.code.editor.e4.handlers.SaveFile Window-Variables: We have 2 special variables defined at the window level (activeInput, rootDirectory) PartStack-Tags: We tagged the Part Stack who is hosting the editors with editorContainer Resource Viewer Part: We register the resource viewer implementation from above to the part definition Root Directory Handler: To set the root directory we have a handler who looks like this package; import; import java.nio.file.Path; import java.nio.file.Paths; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.fx.core.di.ContextValue; import; import javafx.stage.DirectoryChooser; import javafx.stage.Stage; public class SetRootDirectory { @Execute public void setRootDirectory(@ContextValue("rootDirectory") Property rootDirectory, Stage stage) { DirectoryChooser chooser = new DirectoryChooser(); File directory = chooser.showDialog(stage); if( directory != null ) { rootDirectory.setValue(Paths.get(directory.getAbsolutePath())); } } } [Less]
Posted 7 days ago
Previously in this blog series This post is part of the Introduction to Vert.x series. So, let’s have a quick look about the content of the previous posts. In the first post, we developed a very simple Vert.x 3 application, and saw how this ... [More] application can be tested, packaged and executed. In the last post, we saw how this application became configurable and how we can use a random port in test. Well, nothing fancy… Let’s go a bit further this time and develop a CRUD-ish application. So an application exposing an HTML page interacting with the backend using a REST API. The level of RESTfullness of the API is not the topic of this post, I let you decide as it’s a very slippery topic. So, in other words we are going to see: Vert.x Web - a framework that let you create Web applications easily using Vert.x How to expose static resources How to develop a REST API The code developed in this post is available on the post-3 branch of this Github project. We are going to start from the post-2 codebase. So, let’s start. Vert.x Web As you may have notices in the previous posts, dealing with complex HTTP application using only Vert.x Core would be kind of cumbersome. That’s the main reason behind Vert.x Web. It makes the development of Vert.x base web applications really easy, without changing the philosophy. To use Vert.x Web, you need to update the pom.xml file to add the following dependency: io.vertxgroupId> vertx-webartifactId> 3.0.0version> dependency> That’s the only thing you need to use Vert.x Web. Sweet, no ? Let’s now use it. Remember, in the previous post, when we requested http://localhost:8080, we reply a nice Hello World message. Let’s do the same with Vert.x Web. Open the class and change the start method to be: @Override public void start(Future fut) { // Create a router object. Router router = Router.router(vertx); // Bind "/" to our hello message - so we are still compatible. router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response .putHeader("content-type", "text/html") .end("Hello from my first Vert.x 3 application"); }); // Create the HTTP server and pass the "accept" method to the request handler. vertx .createHttpServer() .requestHandler(router::accept) .listen( // Retrieve the port from the configuration, // default to 8080. config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { fut.complete(); } else {; } } ); } You may be surprise by the length of this snippet (in comparison to the previous code). But as we are going to see, it will make our app on steroids, just be patient. As you can see, we start by creating a Router object. The router is the cornerstone of Vert.x Web. This object is responsible for dispatching the HTTP requests to the right handler. Two other concepts are very important in Vert.x Web: Routes - which let you define how request are dispatched Handlers - which are the actual action processing the requests and writing the result. Handlers can be chained. If you understand these 3 concepts, you have understood everything in Vert.x Web. Let’s focus on this code first: router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response .putHeader("content-type", "text/html") .end("Hello from my first Vert.x 3 application"); }); It routes requests arriving on “/“ to the given handler. Handlers receive a RoutingContext object. This handler is quite similar to the code we had before, and it’s quite normal as it manipulates the same type of object: HttpServerResponse. Let’s now have a look to the rest of the code: vertx .createHttpServer() .requestHandler(router::accept) .listen( // Retrieve the port from the configuration, // default to 8080. config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { fut.complete(); } else {; } } ); } It’s basically the same code as before, except that we change the request handler. We pass router::accept to the handler. You may not be familiar with this notation. It’s a reference to a method (here the method accept from the router object). In other worlds, it instructs vert.x to call the accept method of the router when it receives a request. Let’s try to see if this work: mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar By opening http://localhost:8080 in your browser you should see the Hello message. As we didn’t change the behavior of the application, our tests are still valid. Exposing static resources Ok, so we have a first application using vert.x web. Let’s see some of the benefits. Let’s start with serving static resources, such as an index.html page. Before we go further, I should start with a disclaimer: “the HTML page we are going to see here is ugly like hell : I’m not a UI guy”. I should also add that there are probably plenty of better ways to implement this and a myriad of frameworks I should try, but that’s not the point. I tried to keep things simple and just relying on JQuery and Twitter Bootstrap, so if you know a bit of JavaScript you can understand and edit the page. Let’s create the HTML page that will be the entry point of our application. Create an index.html page in src/main/resources/assets with the content from here. As it’s just a HTML page with a bit of JavaScript, we won’t detail the file here. If you have questions, just post comments. Basically, the page is a simple CRUD UI to manage my collection of not-yet-finished bottles of Whisky. It was made in a generic way, so you can transpose it to your own collection. The list of product is displayed in the main table. You can create a new product, edit one or delete one. These actions are relying on a REST API (that we are going to implement) through AJAX calls. That’s all. Once this page is created, edit the class and change the start method to be: @Override public void start(Future fut) { Router router = Router.router(vertx); router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response .putHeader("content-type", "text/html") .end("Hello from my first Vert.x 3 application"); }); // Serve static resources from the /assets directory router.route("/assets/*").handler(StaticHandler.create("assets")); vertx .createHttpServer() .requestHandler(router::accept) .listen( // Retrieve the port from the configuration, // default to 8080. config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { fut.complete(); } else {; } } ); } The only difference with the previous code is the router.route("/assets/*").handler(StaticHandler.create("assets")); line. So, what does this line mean? It’s actually quite simple. It routes requests on “/assets/*” to resources stored in the “assets” directory. So our index.html page is going to be served using http://localhost:8080/assets/index.html. Before testing this, let’s take a few seconds on the handler creation. All processing actions in Vert.x web are implemented as handler. To create a handler you always call the create method. So, I’m sure you are impatient to see our beautiful HTML page. Let’s build and run the application: mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar Now, open your browser to http://localhost:8080/assets/index.html. Here it is… Ugly right? I told you. As you may notice too… the table is empty, this is because we didn’t implement the REST API yet. Let’s do that now. REST API with Vert.x Web Vert.x Web makes the implementation of REST API really easy, as it basically routes your URL to the right handler. The API is very simple, and will be structured as follows: GET /api/whiskies => get all bottles (getAll) GET /api/whiskies/:id => get the bottle with the corresponding id (getOne) POST /api/whiskies => add a new bottle (addOne) PUT /api/whiskies/:id => update a bottle (updateOne) DELETE /api/whiskies/id => delete a bottle (deleteOne) We need some data… But before going further, let’s create our data object. Create the src/main/java/io/vertx/blog/first/ with the following content: package; import java.util.concurrent.atomic.AtomicInteger; public class Whisky { private static final AtomicInteger COUNTER = new AtomicInteger(); private final int id; private String name; private String origin; public Whisky(String name, String origin) { = COUNTER.getAndIncrement(); = name; this.origin = origin; } public Whisky() { = COUNTER.getAndIncrement(); } public String getName() { return name; } public String getOrigin() { return origin; } public int getId() { return id; } public void setName(String name) { = name; } public void setOrigin(String origin) { this.origin = origin; } } It’s a very simple bean class (so with getters and setters). We choose this format because Vert.x is relying on Jackson to handle the JSON format. Jackson automates the serialization and deserialization of bean classes, making our code much simpler. Now, let’s create a couple of bottles. In the MyFirstVerticle class, add the following code: // Store our product private Map products = new LinkedHashMap(); // Create some product private void createSomeData() { Whisky bowmore = new Whisky("Bowmore 15 Years Laimrig", "Scotland, Islay"); products.put(bowmore.getId(), bowmore); Whisky talisker = new Whisky("Talisker 57° North", "Scotland, Island"); products.put(talisker.getId(), talisker); } Then, in the start method, call the createSomeData method: @Override public void start(Future fut) { createSomeData(); // Create a router object. Router router = Router.router(vertx); // Rest of the method } As you have noticed, we don’t really have a backend here, it’s just a (in-memory) map. Adding a backend will be covered by another post. Get our products Enough decoration, let’s implement the REST API. We are going to start with GET /api/whiskies. It returns the list of bottles in a JSON Array. In the start method, add this line just below the static handler line: router.get("/api/whiskies").handler(this::getAll); This line instructs the router to handle the GET requests on “/api/whiskies” by calling the getAll method. We could have inlined the handler code, but for clarity reasons let’s create another method: private void getAll(RoutingContext routingContext) { routingContext.response() .putHeader("content-type", "application/json; charset=utf-8") .end(Json.encodePrettily(products.values())); } As every handler our method receives a RoutingContext. It populates the response by setting the content-type and the actual content. Because our content may contain weird characters, we force the charset to UTF-8. To create the actual content, no need to compute the JSON string ourself. Vert.x lets us use the Json API. So Json.encodePrettily(products.values()) computes the JSON string representing the set of bottles. We could have used Json.encodePrettily(products), but to make the JavaScript code simpler, we just return the set of bottles and not an object containing ID => Bottle entries. With this in place, we should be able to retrieve the set of bottle from our HTML page. Let’s try it: mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar Then open the HTML page in your browser (http://localhost:8080/assets/index.html), and should should see: I’m sure you are curious, and want to actually see what is returned by our REST API. Let’s open a browser to http://localhost:8080/api/whiskies. You should get: [ { "id" : 0, "name" : "Bowmore 15 Years Laimrig", "origin" : "Scotland, Islay" }, { "id" : 1, "name" : "Talisker 57° North", "origin" : "Scotland, Island" } ] Create a product Now we can retrieve the set of bottles, let’s create a new one. Unlike the previous REST API endpoint, this one need to read the request’s body. For performance reason, it should be explicitly enabled. Don’t be scared… it’s just a handler. In the start method, add these lines just below the line ending by getAll: router.route("/api/whiskies*").handler(BodyHandler.create());"/api/whiskies").handler(this::addOne); The first line enables the reading of the request body for all routes under “/api/whiskies”. We could have enabled it globally with router.route().handler(BodyHandler.create()). The second line maps POST requests on /api/whiskies to the addOne method. Let’s create this method: private void addOne(RoutingContext routingContext) { final Whisky whisky = Json.decodeValue(routingContext.getBodyAsString(), Whisky.class); products.put(whisky.getId(), whisky); routingContext.response() .setStatusCode(201) .putHeader("content-type", "application/json; charset=utf-8") .end(Json.encodePrettily(whisky)); } The method starts by retrieving the Whisky object from the request body. It just reads the body into a String and passes it to the Json.decodeValue method. Once created it adds it to the backend map and returns the created bottle as JSON. Let’s try this. Rebuild and restart the application with: mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar Then, refresh the HTML page and click on the Add a new bottle button. Enter the data such as: “Jameson” as name and “Ireland” as origin (purists would have noticed that this is actually a Whiskey and not a Whisky). The bottle should be added to the table. Status 201 ? As you can see, we have set the response status to 201. It means CREATED, and is the generally used in REST API that create an entity. By default vert.x web is setting the status to 200 meaning OK. Finishing a bottle Well, bottles do not last forever, so we should be able to delete a bottle. In the start method, add this line: router.delete("/api/whiskies/:id").handler(this::deleteOne); In the URL, we define a path parameter :id. So, when handling a matching request, Vert.x extracts the path segment corresponding to the parameter and let us access it in the handler method. For instance, /api/whiskies/0 maps id to 0. Let’s see how the parameter can be used in the handler method. Create the deleteOne method as follows: private void deleteOne(RoutingContext routingContext) { String id = routingContext.request().getParam("id"); if (id == null) { routingContext.response().setStatusCode(400); } else { Integer idAsInteger = Integer.valueOf(id); products.remove(idAsInteger); } routingContext.response().setStatusCode(204).end(); } The path parameter is retrieved using routingContext.request().getParam("id"). It checks whether it’s null (not set), and in this case returns a Bad Request response (status code 400). Otherwise, it removes it from the backend map. Status 204 ? As you can see, we have set the response status to 204 - NO CONTENT. Response to the HTTP Verb delete have generally no content. The other methods We won’t detail getOne and updateOne as the implementations are straightforward and very similar. Their implementations are available on Github. Cheers ! It’s time to conclude this post. We have seen how Vert.x Web lets you implement a REST API easily and how it can serve static resources. A bit more fancy than before, but still pretty easy. Next time, we are going to improve our tests to cover the REST API. Say Tuned & Happy Coding ! [Less]
Posted 8 days ago
In a recent post, I had written about Model-to-Model-transformation with Xtend. In addition to M2M-transformation, Xtend and the new Sphinx Check framework are a good pair for model validation. There are other frameworks, such as OCL, which are also ... [More] candidates. Xpand (formerly known as oAW) is used in COMASSO. This blog post sketches some questions / issues to consider when choosing a framework for model validation. Support for unsettable attributes EMF supports attributes that can have the status “unset” (i.e. they have never been explicitly set), as well as default values. When accessing this kind of model element attributes with the standard getter-method, you will not be able to distinguish whether the model element has been explicitly set to the same value as the default value or if it has never been touched. If this kind of check is relevant, the validation technology should support access to the EMF methods that support the explicit predicate if a value has been set. Inverse References With AUTOSAR, a large number of checks will involve some logic to see, if a given element is referenced by other elements (e.g. checks like “find all signals that are not referenced from a PDU”). Usually, these references are uni-directional and traversal of the model is required to find referencing elements. In these cases, performance is heavily influenced by the underlying framework support. A direct solution would be to traverse the entire model or use the utility functions of EMF. However, if the technology allows access to frameworks like IncQuery, a large number of queries / checks can be significantly sped up. Error Reporting Error Reporting is central for the usability of the generated error messages. This involves a few aspects that can be explained at a simple example: Consider that we want to check that each PDU has a unique id. Context In Xpand (and similar in OCL), a check could look like:context PDU ERROR "Duplicate ID in "+this.shortName: this.parent.pdu.exists(e| && e != this) This results in quadratic runtime, since the list of PDU is is fully traversed for each PDU that is checked. This can be improved in several ways: Keep the context on the PDU level, but allow some efficient caching so that the code is not executed so often. However, that involves some additional effort in making sure that the caches are created / torn down at the right time (e.g. after model modification) Move the context up to package or model level and have a framework that allows to generate errors/warning not only for the elements in the context, but on any other (sub-) elements. The Sphinx Check framework supports this. Calculation intensive error messages Sometimes the calculation of a check is quite complex and, in addition, generating a meaningful error message might need some results from that calculation. Consider e.g. this example from the ocl documentation:invariant SufficientCopies('There are ' +>select((book = self))->size().toString() + ' loans for the ' + copies.toString() + ' copies of \'' + name + '\''):>select((book = self))->size() <= copies; The>select((book = self))->size() is used in both the error message as well as the calculation of the predicate. In this case, this is no big deal, but when the calculation gets more complex, this can be annoying. Approaches are Factor the code into a helper function and call it twice. Under the assumption, that the error message is only evaluated when a check fails that should not incur much overhead. However, it moves the actual predicate away from the invariant statement. In Xpand, any information can be attached to any model elements. So in the check body, the result of the complex calculation can be attached to the model element and the information is retrieved in the calculation of the error message. In the Sphinx Check framework, error messages can be calculated from within the check body. User documentation for checks Most validation frameworks support the definition of at least an error code (error id) and a descriptive message. However, more detailed explanations of the checks are often required for the users to be able to work with and fix check results. For the development process, it is beneficial if that kind of description is stored close to the actual tests. This could be achieved by analysing comments near the validations, tools like javadoc etc. The Sphinx frameworks describes ids, messages, severities and user documentation in an EMF model. During runtime of an Eclipse RCP, it is possible to use the dynamic help functionality of the Eclipse Help to generate documentation for all registered checks on the fly.     Here are some additional features of the Xtend language that come in Handy when writing validations: TopicExplanation ComfortXtend has a number of features that make writing checks very concise and comfortable. The most important is the concise syntax to navigate over models. This helps to avoid loops that would be required when implementing in Java val r = eAllContents.filter(EcucChoiceReferenceDef).findFirst[ shortName == "DemMemoryDestinationRef"] } PerformanceXtend compiles to plain Java. This gives higher performance than many interpreted transformation languages. In addition, you can use any Java profiler (such as Yourkit, JProfiler) to find bottlenecks in your transformations. Long-Term-SupportXtend compiles to plain Java. You can just keep the compiled java code for safety and be totally independent about the Xtend project itself. Test-SupportXtend compiles to plain Java. You can just use any testing tools (such as JUnit integration in Eclipse or mvn/surefire). We have extensive test cases for the transformation that are documented in nice reports that are generated with standard Java tooling. Code CoverageXtend compiles to plain Java. You can just use any code coverage tools (such as Jacoco) DebuggingDebugger integration is fully supported to step through your code. ExtensibilityXtend is fully integrated with Java. It does not matter if you write your code in Java or Xtend. DocumentationYou can use standard Javadocs in your Xtend transformations and use the standard tooling to get reports. ModularityXtend integrates with Dependency Injection. Systems like Google Guice can be used to configure combinations of model transformation. Active AnnotationsXtend supports the customization of its mapping to Java with active annotations. That makes it possible to adapt and extend the transformation system to custom requirements. Full EMF supportThe Xtend transformations operate on the generated EMF classes. That makes it easy to work with unsettable attributes etc. IDE IntegrationThe Xtend editors support essential operations such as "Find References", "Go To declaration" etc.   [Less]