Skip to content

Feed aggregator

Access the original calling context in a callback function in TypeScript

AMIS Technology blog - 11 hours 37 min ago

While working on my Ionic 2 application, I made use of the exif.js library (for extracting meta-data from image files). Some of the key functions in this library are called and passed a callback function that is invoked when the image has been analyzed. From this callback function, I wanted to invoke a function (TypeScript method) defined in my class. Inside the callback function however, I did not have access to the calling context. Inside the callback function, this referred to the object passed into the callback function – and not to what this referred at the point of making the call to EXIF:

image

It took me some wondering, experimenting, mild cursing and browsing to figure out how to resolve this issue. Using some threads on StackOverflow, I worked out a solution. The callback function is produced by a helper method that produces the callback function and in doing so injects context references into it. Any parameters passed into this method are available as context inside the callback function. In this example, a parameter called outerThis of type AddBeadModal – the class this code resides in – is expected. Any elements defined on this class are now accessible inside the callback function, as is demonstrated with the call to convertDegToDec and the reference to the location property.

Code for exifHandleGetData – the helper method that produces the callback function:

image

When the call is made to EXIF, the result from the call to exifHandleGetData(this) is passed to EFIX as the callback function. This parameter carries references to the calling scope – through the parameter this.

Code for handlePictureSelection – the method that receives an update to an input type=file component and has EXIF process the selected image (and updates an Angular 2 form component subsequently.

image

 

Resources

This thread on StackOverflow helped me deal with my challenge: http://stackoverflow.com/questions/14471975/how-can-i-preserve-lexical-scope-in-typescript-with-a-callback-function.

The post Access the original calling context in a callback function in TypeScript appeared first on AMIS Oracle and Java Blog.

Categories: Companies

JVM Dive for Mere Mortals

Java TV - 13 hours 22 min ago
For developers using Java on a daily basis, JVM is a pretty important component – it runs our software. But it is usually treated like a magic box, which takes code in and produces business features. Have you ever thought about what you are missing with such an approach? This talk covers some of the […]
Categories: Blogs

Are You a ''Leading Edge'' Java Developer?

There is clearly some differences on opinions out there and not all of them are positive for the JVM community. What does it mean to be a “leading edge” developer on the JVM. On the JVM, there are many languages like Scala, Kotlin and Clojure to name languages with real forward momentum.

Are All Languages Welcome on the JVM?

So can you program in two (or more) languages at the same time? Comments like this one give me pause.

Categories: Communities

Refactoring Uncommon Design Smells

We started working on design smells many years earlier than when we started writing our book "Refactoring for Software Design Smells" (see http://www.designsmells.com). I was digging through some of the old documents and remembered that we did not cover many smells, considering them to be "uncommon smells". By "uncommon smells", I mean the ones that we (co-authors of the book) hadn't seen commonly occurring in software projects, and so did not think that they were worth discussing in detail in the book. We toyed with the idea of listing them in an appendix in the book, but dropped that idea because some readers could object the selection of the smells that formed the core of the book; for example, readers may question the choice of smells covered in the book, and may consider some of the smells mentioned as "uncommon smells" as common in their projects!.

Given the fact that it's been a couple of years since the book was published, I thought it would be interesting to see what you think about these smells. So with that, here are some of the smells that did not make it to our book. If this article generates much interest, I can post more smells in future articles!

Categories: Communities

Using the Play Framework to Create a Java Web Application on Top of a .NET Back-End

Java web applications have come a long way since the days of servlets and Java Server Pages (JSPs). There are now many Java web frameworks for a developer to choose from, including Spring MVC, Java Server Faces, Struts, GWT, Play, and Grails.  As with many other emerging technologies, an abundance of choices of web frameworks will lead to developer fatigue, the feeling of being overwhelmed by the need to keep up with the modern development world’s rapidly multiplying set of options. Interoperability tools like JNBridgePro are an ideal way to deal with many kinds of developer fatigue, particularly when the new technologies are based on Java or .NET. With JNBridgePro, you can learn a small piece of a new technology, while bridging back to other parts of your project, which use the old, familiar technology.

For example, let’s say that you’re a .NET developer maintaining an all-.NET web application using ASP.NET as the web framework. If you’re tasked with updating the application to use a modern Java web framework, you can simplify your task and avoid developer fatigue by reimplementing only the front end, while preserving the familiar .NET code in the back end.

Categories: Communities

Functional Default Arguments, Part Two

In part one, we started to look at a new approach to defining default arguments for methods. Here we continue with a few detailed examples. 

Default Arguments and Functional Programming

Let me introduce you to the MaleProgrammer class, which I'll use as an example for the rest of this newsletter:

Categories: Communities

When Web Companies Grow Up They Turn Into Java Shops [Video]

Earlier this month I attended Pivotal’s SpringOne platform conference in Las Vegas.  In case you’re not familiar with it, Spring is a Java Framework “that helps development teams everywhere build simple, portable, fast and flexible JVM-based systems and applications.”

For some of you out there you may be thinking Java is old school and not relevant in in today’s modern world of digital business.  Au contraire mon frere.  James Governor, the D’artagnan of the analyst world,  countered this belief of irrelevance in his SpringOne talk entitled, “When Web Companies grow up, the become Java Shops.”

Categories: Communities

JVM Debugger Memory View for IntelliJ IDEA

Every day we try to find new ways to improve developer experience with IntelliJ IDEA. It may be a bugfix, a performance improvement, or a new feature (usually in this order). Today we’d like to introduce a new plugin called JVM Debugger Memory View.

The plugin extends the built-in debugger with capabilities to explore objects in the JVM heap during a debug session. The Memory View shows you the total number of objects in the heap grouped by their class name.

Categories: Communities

Functional Default Arguments, Part One

Outline

Java lacks a built-in way to define default arguments for methods and constructors. Over the years, several approaches have been proposed, each with its pros and cons. The most widely-known one uses method overloading, though varargs, null values, the builder pattern, and even maps have been used as well. Here we propose a new approach based on functional constructs.

Functional Default ArgumentsBackground

Many languages support default arguments for methods and constructors out of the box, i.e. Scala:

Categories: Communities

Plugging Leaky Abstractions

In 2002, Joel Spolsky coined something he called “The Law of Leaky Abstractions.”  In software, an “abstraction” hides complexity of an underlying system from those using the abstraction.  Examples abound, but for a quick understanding, think of an ORM hiding from you the details of database interaction.

The Law of Leaky Abstractions states that â€śall non-trivial abstractions, to some degree, are leaky.”  â€śLeaky” indicates that the abstraction fails to adequately hide its internal details.  Imagine, for instance, that while modifying the objects generated by your ORM, you suddenly needed to manage the particulars of some SQL query.  The abstraction leaked, forcing you to understand the details that it was supposed to hide.

Categories: Communities

Using and including a 3rd party JavaScript library in an Ionic 2 and Angular 2 [typescript] application

AMIS Technology blog - Mon, 08/22/2016 - 05:56

While working on a Ionic 2 (and Angular 2) application, I needed to make use of a 3rd party library (exif – https://github.com/exif-js/exif-js – to be exact, a JavaScript library for client side image analysis). This article describes the few steps I learned I had to go through in order to include that library in my application and use it in my [typescript]code. Note: this X-Team blog article showed me the way, after I read many internet resources that did not help.

1. Download the JS library and add it to the www directory of the Ionic 2 application

image

2. Add a script tag – to load the JavaScript file – in the index.html file in [that same]directory www

SNAGHTMLcd2aad2

3. In every TS file in which you want to use the library, declare a variable of type any and with the name of the function from the 3rd party library – to act as a placeholder for the 3rd party JS library. During compilation, the real 3rd JS library is not visible, so any direct references to it will cause errors unless there is such a placeholder as shown here. Because the 3rd party library is loaded by the index.htm- the main page in the single page application – its functions will always be available (no lazy loading) and the references to the placeholder become references to the real library as a result.

The next figure shows how I did this for the exif library. Its main object is called EXIF, so my placeholder has that name. In the typescript function I can refer to functions that I know exist on  EXIF – and I do not get compilation errors (nor of course do I get code completion or type safety). At runtime the references to EXIF are satisfied because then the exif.js file has been loaded.

 

image

 

Resources

Ionic 2 and External Libraries – good overview of including JavaScript libraries that are offered as node  module and for which typesettings are available – http://mhartington.io/post/ionic2-external-libraries/

Include JavaScript Libraries in an Ionic 2 TypeScript Project (including JavaScript libraries for which no node module and/or type settings exist) – http://x-team.com/2016/06/include-javascript-libraries-in-an-ionic-2-typescript-project/

The post Using and including a 3rd party JavaScript library in an Ionic 2 and Angular 2 [typescript] application appeared first on AMIS Oracle and Java Blog.

Categories: Companies

The Benefits of Coding Offline: On Encapsulated Codebases and Headspaces

Last weekend I spent an afternoon at a coffee shop with no wifi in order to solve a problem that I thought should have been simple (automatic de-duping) but which had stumped me for weeks. (I was getting false positives in a pattern I couldn't figure out.)

It took me less than an hour to solve the problem. Turns out I had been counting on one number (but really a string) being very unlikely to collide with other numbers for more than a few digits, when in fact that number -- for domain-specific reasons -- was supposed to share lots of n-grams with other numbers. Dead-simple fix, once I figured this out..and felt stupid for not noticing it before.

Categories: Communities

JDK 9 @Deprecated Annotation Enhancements

In the post What Might a New @Deprecated Look Like?, I used the description of JEP 277 ("Enhanced Deprecation") at that time to guide the creation of an enhanced customized @Deprecated annotation. Since that post, however, there have been significant changes made in JEP 277. This post summarizes the changes and the currently planned enhancements to @Deprecated that are slated for JDK 9.

The changes made to JDK-8065614 ("JEP 277: Enhanced Deprecation") on 2016-03-03 18:04 remove the portion of the JEP description that described the proposed @Deprecated enum. The "Alternatives" section of the main JEP 277 page documents why the enum was removed:

Categories: Communities

An Introduction to Working With JAXB

I am in the process of migrating a few modules that are dependent on Apache XMLBeans to JAXB. It has been an exciting and challenging few days. I thought of jotting down a few important things I came across for anyone who might find it useful in the future.

First of all, let us look at setting up the maven plugin for the JAXB code generation. As of the time of writing this post, I came across two maven plugins. I ended up using the first one as I found the configuration to be quite straightforward.

Categories: Communities

Eight Tools Every Java Developer Should Know (and Love)

At Stormpath, we take quality and productivity very seriously. As any good craftsmen already knows, having talent is not enough, you also need the right tools for the job. Engineering isn’t just a science, it’s also an art, so although we undoubtedly have talent (wink wink) at Stormpath, we always look to supplement with the tool that best fits our needs. Our engineers are always eager to share new tools with the rest of the team. And now, with all the other talented Java developers out there!

In this post, I’ll share the tools that our Java SDK team uses for daily tasks, how we use them, and hopefully, share a few tips that will be useful for you.

Categories: Communities

Integrating Oracle Fusion Middleware MapViewer with Oracle JET

There are many map components in the world out there—and I have documented how to integrate several of them in an Oracle JET application, e.g., 3DCityDB, Mapbox, Leaflet, and LuciadRIA, as well as Oracle JET's ojThematicMap component

However, Oracle has its own map component, as described in detail below, which includes the Oracle Maps Javascript library:

http://www.oracle.com/technetwork/middleware/mapviewer/overview/index.html

Oracle Fusion Middleware MapViewer is a development toolkit for incorporating interactive maps and spatial analyses. It is optimized for use with Oracle Spatial and Graph. (The related Oracle blog is blogs.oracle.com/oracle_maps_blog.) Here below is how it looks when integrated into an Oracle JET application, with many thanks to my colleague Jayant Sharma, who made it happen and provided the instructions that follow, which I have successfully used and I can report that it works.

Instructions for integrating Oracle Fusion Middleware MapViewer with Oracle JET, assuming you have set up an Oracle JET application, e.g., via the Oracle JET QuickStart Basic template:

  1. Add the Oracle Maps V2 kit into js/libs as a folder named 'oraclemaps'. The kit can be downloaded from here and specifically here: http://download.oracle.com/otn/other/mapviewer/12c/12211/v2_122110_full.zip

  2. Modify "main.js" to include the various Oracle map libraries, in the requires.config "path" and "shim" sections. I.e., add these entries in the "paths" section:
    //File paths for Oracle Maps HTML5 API
    'omapsv2-hammer': 'libs/oraclemaps/v2/jquery/jquery.hammer-full.min',
    'omapsv2-i18n-properties': 'libs/oraclemaps/v2/jquery/jquery.i18n.properties-min-1.0.9',
    'omapsv2-mousewheel.min': 'libs/oraclemaps/v2/jquery/jquery.mousewheel.min',
    'omapsv2-rtree': 'libs/oraclemaps/v2/rtree/rtree-min',
    'omapsv2-fortknox': 'libs/oraclemaps/v2/fortknox-libs/fortknox-canvas',        
    'omapsv2_core': 'libs/oraclemaps/v2/oraclemapsv2_core'

    ...and these in the "shim" section:

    //Oracle Maps HTML5 API dependencies
    'omapsv2-i18n-properties':  ['jquery'],
    'omapsv2-hammer': ['jquery'],
    'omapsv2-mousewheel.min' : ['jquery'],     
    'omapsv2_core': {
       deps: ['jquery','hammerjs','omapsv2-fortknox','omapsv2-rtree','omapsv2-hammer','omapsv2-i18n-properties','omapsv2-mousewheel.min'],
       exports: 'OM'
    }
  3. Modify the view of an Oracle JET module, e.g., "home.html", in the way it's done for the MapBox example, i.e., rewrite "home.html" to be the following and include "css/styles.css" containing "#map { width:100%; height:100%; }": 
  4. <STYLE TYPE="text/css">
    <!--
      @import url(css/styles.css);
    -->
    </STYLE>
    
    <div id='map'></div>
    
  5. Modify the viewModel of an Oracle JET module, e.g., "home.js", to be as follows, and read the comments below to understand the code:
    define(['ojs/ojcore', 'knockout', 'omapsv2_core'],
        function (oj, ko) {
            function mainContentViewModel() {
                var self = this;
                self.handleAttached = function () {
                    /* */
                    if (OM !== undefined) {
                        //Where to load Oracle Maps HTML5 API resource files (fonts, css and icons et al):
                        OM.gv.setResourcePath("js/libs/oraclemaps/v2");
                        //Default http method when fetching remote geospatial contents:
                        OM.gv.setHttpMethod("GET");
                    } else
                        console.log('OM not loaded');
                    var X = -77;
                    var Y = 38.9;
                    var initialZoom = 11;
                    //This function adds various map controls to the provided OM.Map instance:
                    var addMapControls = function (myMap)
                    {
                        //defines various properties for the navigation control:
                        var navConfig = {
                            orientation: 1,
                            style: OM.control.NavigationPanelBar.STYLE_ZOOM_BUTTONS_ONLY,
                            anchorPosition: 1
                        };
                        //creates the navigation control:
                        var navigationControl = new OM.control.NavigationPanelBar(navConfig);
                        // navigation control (and other map controls) are typically added
                        //to the map as map decorations:
                        myMap.addMapDecoration(navigationControl);
                        //defines the basic properties for the map scale bars:
                        var sbConfig = {
                            format: "BOTH",
                            anchorPosition: 4,
                            endMarks: false
                        };
                        //defines the display style of the scale bars:
                        var sbStyle = {
                            thickness: 5,
                            color: '#257db3',
                            shadow: true
                        };
                        //creates the actual scale bar instance and sets the display style:
                        var scaleBar = new OM.control.ScaleBar(sbConfig);
                        scaleBar.setStyle(sbStyle);
                        //adds the scale bar to the map as another map decoration:
                        //myMap.addMapDecoration(scaleBar);   
                    };
                    var showMap = function ()
                    {
                        //This is the DIV that will display the map; it needs to be passed into
                        //the map instance:
                        var mapDiv = document.getElementById('map');
                        if (!mapDiv)
                        {
                            console.log("Map container DIV not found!");
                            return;
                        }
                        //Creates a new map instance. Notice we are not supplying a Universe
                        //like in helloworld.js, since the universe will be defined when we
                        //add the tile layer to the map. Every tile layer includes its own
                        //universe definition as part of the tile layer's configuration:
                        var map = new OM.Map(mapDiv, {mapviewerURL: ''});
                        //This is how we create an Oracle eLocation tile layer: by creating
                        //a new instance of the OM.layer.ElocationTileLayer class. Check
                        //the <a href="https://apidoc/index.html">API Doc</a> for other built-in tile 
                        //layers such as Bing maps:
                        var tileLayer = new OM.layer.ElocationTileLayer("elocation");
                        //Adds the tile layer to the map:
                        map.addLayer(tileLayer);
                        //creates a point object located at the given longitude and latitude: 
                        var point = new OM.geometry.Point(X, Y);
                        //Adds various map controls to the map:
                        //console.log('adding mapControls');
                        addMapControls(map);
                        // set the initial map zoom level and center (same as the location marker):
                        map.setMapCenter(point);
                        map.setMapZoomLevel(initialZoom);
                        //Now we can complete the initialization of the map. You must
                        //only call this method once.  Note however map layers can
                        //be added even after calling this method:
                        map.init();
                    }; //showMap
                    // console.log('call showMap');
                    showMap();
                    /*  */
                }; // handleAttached
            }
            return new mainContentViewModel();
        });

That's it. Run the project and you'll see the same as in the screenshot above.

Categories: Open Source

Configure and Run Plain Java Apps in Eclipse Che

This post will demonstrate how to develop and run standard Java applications in Eclipse Che. We’ll start by creating and running a simple “Hello World” example using one of the Che template apps. Then we’ll clone a plain Java project from Git, configure the classpath, add a library to the classpath, and run the application.

Create an Empty Java Workspace

In the user dashboard select “Workspaces” from the left nav and hit the “+” in the upper-right corner to create a new workspace. Then select Java and hit the “Create Workspace” button at the bottom:

Categories: Communities

LinkedIn's {Py}Gradle Plugin Brings Build Automation to Python

Yesterday, LinkedIn released their open source PyGradle plugin for running Python builds in the popular Gradle software build automation system. With PyGradle, Python and Java shops can all use the same build system. The plugin is accessible under an Apache 2 license.

LinkedIn is trying to use open source to gauge the community’s perspectives on what people want out of PyGradle. They are going to be accepting pull and feature requests. The plugin is currently in the0.3 release stage, with a 1.0 released planned in about two weeks.

Categories: Communities

Dockerizing a Spring Boot Application

baeldung - Coding and Testing Stuff - Fri, 08/19/2016 - 19:09
The Master Class of "Learn Spring Security" is out:

>> CHECK OUT THE COURSE

1. Overview

In this article we’ll focus on how to dockerize a Spring Boot Application to run it in an isolated environment, a.k.a. container.

Furthermore we’ll show how to create a composition of containers, which depend on each other and are linked against each other in a virtual private network. We’ll also see how they can be managed together with single commands.

Let’s start by creating a Java-enabled, lightweight base image, running Alpine Linux.

2. Common Base Image

We’re going to be using Docker’s own build-file format: a Dockerfile.

A Dockerfile is in principle, a linewise batch file, containing commands to build an image. It’s not absolutely necessary to put these commands into a file, because we’re able to pass them to the command-line, as well – a file is simply more convenient.

So, let’s write our first Dockerfile:

FROM alpine:edge
MAINTAINER baeldung.com
RUN apk add --no-cache openjdk8
COPY files/UnlimitedJCEPolicyJDK8/* \
  /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/
  • FROM: The keyword FROM, tells Docker to use a given image with its tag as build-base. If this image is not in the local library, an online-search on DockerHub, or on any other configured remote-registry, is performed
  • MAINTAINER: A MAINTAINER is usually an email address, identifying the author of an image
  • RUN: With the RUN command, we’re execute a shell command-line within the target system. Here we utilizing Alpine Linux’s package manager apk to install the Java 8 OpenJDK
  • COPY: The last command tells Docker to COPY a few files from the local file-system, specifically a subfolder to the build directory, into the image in a given path

REQUIREMENTS: In order to run the tutorial successfully, you have to download the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files from Oracle. Simply extract the downloaded archive into a local folder named ‘files’.

To finally build the image and store it in the local library, we have to run:

docker build --tag=alpine-java:base --rm=true .

NOTICE: The –tag option will give the image its name and –rm=true will remove intermediate images after it has been built successfully. The last character in this shell command is a dot, acting as build-directory argument.

3. Dockerize a Standalone Spring Boot Application

As example for an application which we can dockerize, we will take the spring-cloud-config/server from the spring cloud configuration tutorial. As  a preparation-step, we have to assemble a runnable jar file and copy it to our Docker build-directory:

tutorials $> cd spring-cloud-config/server
server    $> mvn package spring-boot:repackage
server    $> cp target/server-0.0.1-SNAPSHOT.jar \
               ../../spring-boot-docker/files/config-server.jar
server    $> cd ../../spring-boot-docker

Now we will create a Dockerfile named Dockerfile.server with the following content:

FROM alpine-java:base
MAINTAINER baeldung.com
COPY files/spring-cloud-config-server.jar /opt/spring-cloud/lib/
COPY files/spring-cloud-config-server-entrypoint.sh /opt/spring-cloud/bin/
ENV SPRING_APPLICATION_JSON= \ 
  '{"spring": {"cloud": {"config": {"server": \
  {"git": {"uri": "/var/lib/spring-cloud/config-repo", \
  "clone-on-start": true}}}}}}'
ENTRYPOINT ["/usr/bin/java"]
CMD ["-jar", "/opt/spring-cloud/lib/spring-cloud-config-server.jar"]
VOLUME /var/lib/spring-cloud/config-repo
EXPOSE 8888
  • FROM: As base for our image we will take the Java-enabled Alpine Linux, created in the previous section
  • COPY: We let Docker copy our jar file into the image
  • ENV: This command let us define some environment variables, which will be respected by the application running in the container. Here we define a customized Spring Boot Application configuration, to hand-over to the jar-executable later
  • ENTRYPOINT/CMD: This will be the executable to start when the container is booting. We must define them as JSON-Array, because we will use an ENTRYPOINT in combination with a CMD for some application arguments
  • VOLUME: Because our container will be running in an isolated environment, with no direct network access, we have to define a mountpoint-placeholder for our configuration repository
  • EXPOSE: Here we are telling Docker, on which port our application is listing. This port will be published to the host, when the container is booting

To create an image from our Dockerfile, we have to run ‘docker build’, like before:

$> docker build --file=Dockerfile.server \
     --tag=config-server:latest --rm=true .

But before we’re going to run a container from our image, we have to create a volume for mounting:

$> docker volume create --name=spring-cloud-config-repo

NOTICE: While a container is immutable, when not committed to an image after application exits, data stored in a volume will be persistent over several containers.

Finally we are able to run the container from our image:

$> docker run --name=config-server --publish=8888:8888 \
     --volume=spring-cloud-config-repo:/var/lib/spring-cloud/config-repo \
     config-server:latest
  • First, we have to –name our container. If not, one will be automatically chosen
  • Then, we must –publish our exposed port (see Dockerfile) to a port on our host. The value is given in the form ‘host-port:container-port’. If only a container-port is given, a randomly chosen host-port will be used. If we leave this option out, the container will be completely isolated
  • The –volume option gives access to either a directory on the host (when used with an absolute path) or a previously created Docker volume (when used with a volume-name). The path after the colon specifies the mountpoint within the container
  • As argument we have to tell Docker, which image to be used. Here we have to give the image-name from the previously ‘docker build‘ step
  • Some more useful options:
    • -it – enable interactive mode and allocate a pseudo-tty
    • -d – detach from the container after booting

If we ran the container in detached mode, we can inspect its details, stop it and remove it with the following commands:

$> docker inspect config-server
$> docker stop config-server
$> docker rm config-server
4. Dockerize Dependent Applications in a Composite

Docker commands and Dockerfiles are particularly suitable for creating individual containers. But if you want to operate on a network of isolated applications, the container management quickly becomes cluttered.

To solve that, Docker provides a tool named Docker Compose. This comes with an own build-file in YAML format and is better suited in managing multiple containers. For example: it is able to start or stop a composite of services in one command, or merges logging output of multiple services together into one pseudo-tty.

Let’s build an example of two applications running in different docker containers. They will communicate with each other and be presented as “single unit” to the host system. We will build and copy the spring-cloud-config/client example described in the spring cloud configuration tutorial to our files folder, like we have done before with the config-server.

This will be our docker-compose.yml:

version: '2'
services:
    config-server:
        container_name: config-server
        build:
            context: .
            dockerfile: Dockerfile.server
        image: config-server:latest
        expose:
            - 8888
        networks:
            - spring-cloud-network
        volumes:
            - spring-cloud-config-repo:/var/lib/spring-cloud/config-repo
        logging:
            driver: json-file
    config-client:
        container_name: config-client
        build:
            context: .
            dockerfile: Dockerfile.client
        image: config-client:latest
        entrypoint: /opt/spring-cloud/bin/config-client-entrypoint.sh
        environment:
            SPRING_APPLICATION_JSON: \
              '{"spring": {"cloud":  \
              {"config": {"uri": "http://config-server:8888"}}}}'
        expose:
            - 8080
        ports:
            - 8080:8080
        networks:
            - spring-cloud-network
        links:
            - config-server:config-server
        depends_on:
            - config-server
        logging:
            driver: json-file
networks:
    spring-cloud-network:
        driver: bridge
volumes:
    spring-cloud-config-repo:
        external: true
  • version: Specifies which format version should be used. This is a mandatory field. Here we use the newer version, whereas the legacy format is ‘1’
  • services: Each object in this key defines a service, a.k.a container. This section is mandatory
    • build: If given, docker-compose is able to build an image from a Dockerfile
      • context: If given, it specifies the build-directory, where the Dockerfile is looked-up
      • dockerfile: If given, it sets an alternate name for a Dockerfile
    • image: Tells Docker which name it should given to the image when build-features are used. Otherwise it is searching for this image in the library or remote-registry
    • networks: This is the identifier of the named networks to use. A given name-value must be listed in the networks section
    • volumes: This identifies the named volumes to use and the mountpoints to mount the volumes to, separated by a colon. Likewise in networks section, a volume-name must be defined in a separate volumes section
    • links: This will create an internal network link between this service and the listed service. This service will be able to connect to the listed service, whereby the part before the colon specifies a service-name from the services section and the part after the colon specifies the hostname at which the service is listening on an exposed port
    • depends_on: This tells Docker to start a service only, if the listed services has started successfully. NOTICE: This works only at container level! For a workaround to start the dependent application first, see config-client-entrypoint.sh
    • logging: Here we are using the ‘json-file’ driver, which is the default one. Alternatively ‘syslog’ with a given address option or ‘none’ can be used
  • networks: In this section we’re specifying the networks available to our services. In this example we let docker-compose create a named network of type ‘bridge’ for us. If the option external is set to true, it will use an existing one with the given name
  • volumes: This is very similar to the networks section

Before we continue, we will check our build-file for syntax-errors:

$> docker-compose config

This will be our Dockerfile.client to build the config-client image from. It differs from the Dockerfile.server in that we additionally install OpenBSD netcat (which is needed in the next step) and make the entrypoint executable:

FROM alpine-java:base
MAINTAINER baeldung.com
RUN apk --no-cache add netcat-openbsd
COPY files/config-client.jar /opt/spring-cloud/lib/
COPY files/config-client-entrypoint.sh /opt/spring-cloud/bin/
RUN chmod 755 /opt/spring-cloud/bin/config-client-entrypoint.sh

And this will be the customized entrypoint for our config-client service. Here we use netcat in a loop to check whether our config-server is ready. You have to notice, that we can reach our config-server by its link-name, instead of an IP address:

#!/bin/sh
while ! nc -z config-server 8888 ; do
    echo "Waiting for upcoming Config Server"
    sleep 2
done
java -jar /opt/spring-cloud/lib/config-client.jar

Finally we can build our images, create the defined containers and start it in one command:

$> docker-compose up --build

To stop the containers, remove it from Docker and remove the connected networks and volumes from it, we can use the opposite command:

$> docker-compose down

A nice feature of docker-compose is the ability to scale services. For example, we can tell Docker to run one container for the config-server and three containers for the config-client.

But for this to work properly, we have to remove the container_name from our docker-compose.yml, for letting Docker choose one, and we have to change the exposed port configuration, to avoiding clashes.

After that, we are able to scale our services like so:

$> docker-compose build
$> docker-compose up -d
$> docker-compose scale config-server=1 config-client=3
5. Conclusion

As we’ve seen, we are now be able to building custom Docker images, running a Spring Boot Application as a Docker container and creating dependent containers with docker-compose.

For further reading about the build-files, we refer to the official Dockerfile reference and the docker-compose.yml reference.

As usual, the source codes for this tutorial can be found on Github.

The Master Class of "Learn Spring Security" is out:

>> CHECK OUT THE COURSE

Categories: Blogs

Translating Oracle JET Applications

The Oracle JET MOOC starts on Monday. When we talk about Oracle JET we always say that it solves "enterprise challenges". One of these is internationalization/localization/translation of JavaScript applications. Recently I started playing with the translation features of Oracle JET and they're pretty impressive. Really, if you want to create JavaScript applications that need to be translated, you should look no further than Oracle JET.

Let's start by looking at the result of a small sample I've been working on. Here's an application that can be switched to 4 different languages, with a screenshot of 3 of them below: 

Everything to achieve the above is documented in "Internationalizing and Localizing Applications" in the Oracle JET Developer Guide. This topic is also dealt with in the 3rd week of the Oracle JET MOOC.

There are several bits and pieces involved in this sample: 

  1. Bundled translations for Oracle JET components. Oracle JET components, such as the date/time picker that you see above, have already been translated. The translations are found in libs/oraclejet/dist/js/libs/oj/resources/nls.

  2. Custom translation bundles. Aside from the Oracle JET components, which have already been translated, Oracle JET provides a facility for storing and loading your own translations. Below, you can see a folder called "resources/nls", with subfolders for each of the languages I am supporting:



    In "main.js", I have this, which registers the "resources/nls/l10" structure and merges it with the translations that are provided by Oracle JET:
    config: {
        ojL10n: {
            merge: {
                'ojtranslations/nls/ojtranslations': 'resources/nls/l10'
            }
        }
    }

    The most important file in "resources/nls" is the file named "l10.js", which could be named anything at all, so long as it matches the registration in "main.js" shown above. It looks like this, in my case:

    define({
      "root": {
        "date": "Date:",
        "greeting": "Good Morning"
    },
      "ar": true,
      "fr": true,
      "cs": true
    });
    In each of the folders that have been enabled above, i.e., "ar", "fr", and "cs", translations of the above texts are found, e.g., in "ar":



    Now, anywhere in our viewModel, we can use this statement to retrieve the greeting of the current locale:
    oj.Translations.getTranslatedString('greeting')
  3. RTL Support. Bidirectional features are included too, read here, simply by setting the "dir" attribute of the "html" element to "rtl" and back to "ltr".

  4. Dynamic Locale Switching. Via the buttons you see above, the locale can be switched, as described here.

Following from the above, the complete code for the viewModel is as follows, focused on enabling the switching between locales, which will cause the translation bundles to be loaded dynamically:

define(['ojs/ojcore', 'knockout', 'ojs/ojbutton', 'ojs/ojdatetimepicker'],
    function (oj, ko) {
        function mainContentViewModel() {
            var self = this;
            self.formats = ko.observableArray(["english"]);
            self.date = ko.observable();
            self.greeting = ko.observable("Good Morning");
            self.localeDate = ko.observable();
            self.localeDate(oj.Translations.getTranslatedString('date')); 
            self.localeGreeting = ko.observable();
            self.localeGreeting(oj.Translations.getTranslatedString('greeting')); 
            self.setLang = function (data) {
                var newLang = '';
                switch (data) {
                    case 'Arabic':
                        newLang = 'ar-EG';
                        self.formats(["arabic"]);
                        break;
                    case 'Czech':
                        newLang = 'cs-CZ';
                        self.formats(["czech"]);
                        break;
                    case 'French':
                        newLang = 'fr-FR';
                        self.formats(["french"]);
                        break;
                    default:
                        newLang = 'en-US';
                        self.formats(["english"]);
                }
                oj.Config.setLocale(newLang,
                    function () {
                        $('html').attr('lang', newLang);
                        if (newLang === 'ar-EG') {
                            $('html').attr('dir', 'rtl');
                        } else {
                            $('html').attr('dir', 'ltr');
                        }
                        self.localeDate(oj.Translations.getTranslatedString('date')); 
                        self.localeGreeting(oj.Translations.getTranslatedString('greeting')); 
                        $('#dateInput').ojInputDateTime('refresh');
                    }
                );
            };
        }
        return new mainContentViewModel();
    });

And here's the view:

<div data-bind="ojComponent: {component: 'ojButtonset', checked: formats}">
    <!--Arabic-->
    <label for="arabic">Arabic</label>
    <input data-bind="click: function(){setLang('Arabic');}" 
           type="checkbox" value="arabic" id="arabic"/>
    <!--Czech-->
    <label for="czech">Czech</label>
    <input data-bind="click: function(){setLang('Czech');}" 
           type="checkbox" value="czech" id="czech"/>
    <!--French-->
    <label for="french">French</label>
    <input data-bind="click: function(){setLang('French');}" 
           type="checkbox" value="french" id="french"/>
    <!--English-->
    <label for="english">English</label>
    <input data-bind="click: function(){setLang('English');}" 
           type="checkbox" value="english" id="english"/>
</div>
<br/>
<br/>
<span style="font-size: 50pt" id="greeting" data-bind="text: localeGreeting"></span>
<br/>
<span data-bind="text: localeDate"></span>
<input id="dateInput" type="text" 
    data-bind="ojComponent: {
        component:'ojInputDateTime', 
        value: date,
        datePicker: {changeMonth: 'none', changeYear: 'none'}
    }"/>

That's it. And here's the sample code shown above:

https://github.com/GeertjanWielenga/OJETCourse/tree/master/Part-024

A next step is to generate all the buttons automatically from JavaScript, i.e., there should be some way to provide new buttons to switch to new languages easily, without having to code them in HTML, i.e., in the viewModel, find the lists of available translation locales and create the buttons, and their logic, based on that. 

Categories: Open Source