The Git Experience (Part 4)

In this part of the ‘Git Experience’ series we are looking at GitFlow. GitFlow is a branching model which helps you and your company to structure your work in a way which is understandable and has proven it’s value in many projects. I don’t want to copy all information given in the link about GitFolw but only use the image from the blog post:

GitFlow Model

GitFlow Model

What we see in this image is a timeline of development with releases, hot fixes, development and feature branches and how they work together. We like to use this model to structure the work of the development. The development needs to set up the software for releases which are delivered to the customer or an internal server. Then there is the need to supply hot fixes if a release version has a major bug. Nevertheless development has to develop for the next release, probably breaking the task into smaller pieces we call features. To keep this features in our repository as well we use feature branches which are merged back to the development branch once they are ready and tested.

The development branch is the grapevine for the development. Feature branches as well as release branches are started from the development branch. Once a release is ready the release branch is merged and tagged on the master branch and merged to the development branch.

IMPORTANT: you never work directly on the master branch!

In the last part ‘The Git Experience (Part 3)’ we started a new repository on GitHub which we use in this part to introduce GitFlow on it. There are several ways to do this. You can use the command line and execute the git commands from there. Or you use shell scripts to put multiple git commands as a unit of work together and call the script to e.g. start a new feature branch. The last and least complicated way is to use a tool which already has set up the scripts for you and gives you a nice GUI to work with.

We follow the last suggested way and use a tool with graphical user interface. As JDeveloper does not support the usage of GitFlow with a GUI we use an external tool like ‘SmartGit’ or ‘Source Tree’ which both come with a graphical user interface supporting GitFlow. For the remainder of this blog we use SmartGit as it’s available for Windows and Linux operating systems. It’s free for non commercial use.

Once we started SmartGit we can add our local repository to be shown in SmartGit. Don’t be confused this with cloning a repository. Cloning fetches a remote repository from a remote server and creates a local copy of it on your pc. As we already have the local repository on out machines we just add the local repository.

For those of you how did not create the repository in the last part you can clone it from my GitHub server repository using ‘’ as url for the clone command.

After this SmartGit looks the same as the last image after adding the repository. You now can play with the SmartGit UI (or any other too you are using). One thing I like to bring to attention is the ‘Log’ button. Clicking this button opens a new window which shows the timeline of all commits.

Right now we only see two nodes which were created during creation of the repository.

Let the fun begin: Introduce GitFlow to the project

Now that the local repository is up in the tool of choise, lets introduce GitFlow to it. For this we click the GitFlow Button, select the ‘Full’ radio button and leave the rest of the options as is.

This will add another branch to the repository named ‘develop’

Repository after GitFlow Introduction

Repository after GitFlow Introduction

However, this  new branch is not the current branch as the ‘master’ branch is still marked current. Please also note the different color of the GitFlow button. In this shape it starts a HotFix as the master branch is the current branch and all hot fixes are started from the master branch, or better a release tag on the master branch.

GitFlow Button: Start HotFix

GitFlow Button: Start HotFix

We change this by double clicking the develop branch to get

and see the GitFlow button changes to a different default action, ‘Start Feature’ as we are now working on the develop branch. Before we start our first feature we take a look at the GitHub remote repository:

GitHub Timeline

GitHub Timeline

As we see the remote repository still only have one branch ‘master’. This is a lesson we have to learn fast. Everything we do, we do only locally. The remote repository doesn’t know about our work until we tell about it or push our changes to the remote repository.

Let’s push the ‘develop’ branch to the remote repository by clicking the Push button

Last thing to do is to do some house keeping on the GitHub side. Here we set the ‘develop’ Branch as ‘default’ branch.

Now we are ready to start our first feature. Remember that the feature branch is only created on the local repository and not automatically pushed to the remote GitHub repository. If you like the feature branch to be visible in the remote repository you have to push it there after creating it.

We create a feature ‘Feature_1’ (you should choose a more meaningful name!):

As we see the new branch is the current working branch. We now make some changes e.g. adding a header above the table and then look at the changes in the SmartGit and GitHub UI.

We add a panelGroupLayout to the top facet of the panelStretchLayout to add a header telling us what we see and another text telling that this was added with ‘Feature-1’. This is just for the time we are playing with the GitFlow features. We later can safely remove this second text.

As we see, all tools showing the same changed files. The interesting thing is that we see a changed file. The only change we made was to add something to the index.jsf file!

Well, this second change was not intended but is the result of a setting in JDeveloper which adds a property to a backing bean for every component we add to the index.jsf file. Before we remove this nonsense setting let’s save the changes to our repository and look at the different tools:

In the first image we see an interesting info: ‘Outgoing (1)’. This means that SmartGit knows that this branch isn’t connected to the remote repository and can’t seen there. This isn’t really necessary as Git is a distributed version control system, but other users can’t get to this branch if the PC holding it isn’t available (due to network restrictions or because it’s offline).

After this the new branch is visible and tracked in GitHub. Now we can remove the not needed nor wanted backing bean.

Why is it there in the first place?

If we create a new view in a task flow we have the option to activate the automatic component binding to a backing bean in this dialog

Automatic Component Binding

Automatic Component Binding

Well, it’s either a bug in JDev 12.1.3 or a saved configuration I made to investigate something else which uses automatic component binding. Les’s assume the latter and remove this setting.

Now we have to remove line 76 in the index.jsf file, fix the bindings in index.jsf by replacing them (find: binding=\”#{backingBeanScope.backing_index..*\”), remove the bean from adfc-config.xml and finally remove the file from the project

Now we can compile the source, test the application and then save the changes in the repository. Don’t forget to push the changes to the remote repository!

If you use SmartGit to commit the changes you can commit and push in one command by clicking the ‘Commit & Push’ button in the dialog. The final timeline in SmartGit looks like

SmartGit Timeline

SmartGit Timeline

Time to wrap everything up. We made some changes and now are finished with our feature. We now finish the feature in SmartGit by clicking the GitFlow button and follow the dialog

The second image shows the options we have to finish a feature. Here we can decide to remove the feature branch completely or, as we do, keep it for later. As features are not used by GitFlow to build a release or hot fix on them, there is generally no need to keep them after they are finished and merged back into the development branch.

The final thing to make the circle is to build a release from the current development branch.

We add a release note part to the README.MD file to make the release visible in the file too. Now we commit the change (not shown) and finish the release

In image 2 we can set the options we want to use to finish the release. The one we change from the default is that we like to keep the release branch so that we can see it in the timeline. This is not necessary as you can’t do anything with the branch (beside cherry picking :)). The last image shows the SmartGit timeline where we see all commits and the different branches used. This show look like the GitFlow image we started this blog with.

This finishes part 4 of the blog. The repository (and it’s branches) and be cloned or loaded from GitHub.

The Git Experience (Part 3)

Almost a year ago I posted the second part of my git experience series (JDeveloper The Git Experience (Part 2)). In this part I announced a third part which should handle working with remote git repositories.

I totally forgot about this. Only after a question on OTN JDeveloper and ADF forum I looked up the older blogs about git. Since the last post a new JDev version 12.1.3 has arrived so I decided to use this new version to continue the series.

In this part we are talking about setting up a remote repository. As remote git server I use GitHub which allows you to easily set up an account for non commercial use without any cost. Please read the all about the process on the GitHub Help web page.

Before we begin we have to talk about security accessing the remote repository. There are multiple possible connection strategies. The more common are ssh and https. Both are supported by GitHub, https is the recommended.

In this blog I use https to authenticate and work with GitHub, all you need to remember is your GitHub username and it’s password. I tested ssh too but like https better as you don’t have to handle the ssh keys on every pc you use (and I use up to 10 different machines).

I assume you have built yourself an account on GitHub which you can use. If you don’t want to create one yourself you can use the repository of this blog (link available at the end of the blog). Creating a new remote repository yourself can’t be done without an account. For those of you part 4 of the series which will be published in a couple of days will talk about how to do real work with remote repositories and introduce GitFlow as work template.

Let’s start with a typical workflow. We want to implement a new application using JDev 12.1.3 and want to use git as version control system. As the development is done on multiple locations, the repository should be accessible for all team members 24/7. This exclude a repository on a local pc which others might not be able to reach (e.g. if it’d down).

We generate a new ADF Fusion Web Application. I spare the walk through this process. As name of the new application workspace we choose BlogReadConfigFile, every other name you like is OK too.

Once the new application workspace is ready we like to put it under git control. We first do this locally by using the ‘Team->Version Application…’ menu. See the gallery below fro the whole process.

Notice the ‘.git’ folder which holds all information about the git versions of the application on your local pc. The fresh created local repository can be used already to make changes and commit them to the local repository. Other team members can clone the repository from your pc if they have access to it.

As the new workspace is under version control we can and should open a new window in JDev via menu ‘ Window->Team->Version’ to get a view of the version information available in JDev:

Open Version Window

Open Version Window

Expanded Version Window

Expanded Version Window

As you’ll notice all remote nodes in the tree are empty. The local master branch is the current branch we are working on, visible through the green badge. Now we want to make this local repository available to a remote git server GitHub. First problem is that JDev 12.1.3 (and all other version I know of) don’t support creating a remote repository. We can add existing remote repositories by right clicking to the ‘Remotes’ node and ‘add remote…’

Add a Remote Repository

Add a Remote Repository

Add Remote Dialog

Add Remote Dialog

As you see you can only add the URL to the remote repository but can’t create it. So we have to create the remote repository on GitHub first. Read ‘Setup a new Repository’ to find out how to do this. Make sure you make it a public repository and leave the check box to init the repository with a file empty for the moment.

Create Repository in GitHub

Create Repository in GitHub

You can add default ‘.gitignore’ fie and a licence via this dialog too. We use a ‘.gitignore’ file from other JDev projects as the default java one doesn’t know about some of the artifacts used by JDev. After finishing the dialog you get the information from GitHub how to get data into the new repository.

How to add Data

How to add Data

If you decide to use ssh instead of https you can click the button on the left side of the URL and the info switches accordingly.

As we already have our local repository we use the second method ‘…or publish an existing repository from the command line’. For this we open a command shell and open the location of the workspace (‘/data/development/ENTW_12.’ on my machine). Copy the commands from the second option into the command shell. You are asked for your credentials to login into GitHub, after that the local repository is pushed to GitHub.

Command Lines to Push Data to Repository

Command Lines to Push Data to Repository

When we look at the GitHub web page we see the data from the workspace

Finished Remote Repository

Finished Remote Repository

As mentioned at the button of the page we should add a file. This can be done directly on the web page or you can add such a file on your local pc and push it to the repository. I like to do this through the web page as it copies the description from the creation of the repository into the file.



Now if we look at the Versions window in JDev we see that the remote repository is visible in JDev too.

Updated Version Window

Updated Version Window

Dev knows about the changes as they all in the ‘.git’ folder in the workspace. Right now command line git , JDev git and third party tools like SmartGit, SourceTree or mysygit (or Tortoise Git on windows) play well together. You can use them interchangeably.

As we have added the file using the web page, out first action is to refresh the workspace to get the file into our local repository. For this we use the menu ‘Team->Git->Pull…’, work through the wizard and check the file system after the work has finished.

This concludes this part 3 of the series. You can clone the repository from GitHub. Stay tuned for the next part where we introduce GitFlow and start working on the repository.

Handling images/files in ADF (Part 5)

I received a couple of questions regarding the handling of the images directly after upload for the sample application done in part 1-4.

    Part 1 gives an overview of the sample application I’m going to build and how to set it up
    Part 2 shows how to upload a file, store it and download it back to the client
    Part 3 implements two techniques to show the data (image) on the user interface
    Part 4 backport of the sample to JDeveloper 11gR1
    Part 5 implements a technique to show the uploaded file right after upload without the need to commit first

The sample application finished in part 3 (part 4 is a backport to JDev 11gR1 only) has one minor glitch: it doesn’t display an uploaded image directly to the user after uploading it. The user has to commit the data after insert or update of an image before the image becomes visible. Users like to see the newly uploaded image before committing the row. This allows the users to cancel the change or select and upload another image. In this 5th part of the series we implement this.

Before we start to implement let’s talk about how to implement this enhancement. Why isn’t it possible to upload the image data into the blob and then just show the image from the blob via the servlet (see part 3)?
The problem is that the BlobDomain uses a stream to read the data uploaded from the user. This stream can only be read after the BlobDomain is saved, meaning after the commit.

The solution we implement in this part stores the uploaded data (inserted or updated) in a temporary file on the server. Then the server uses the image data from the temporary file to visualize the data. This sounds easy enough, however there is some house keeping to do to make it work.

First we have have to find a place (folder) where we can store the uploaded data until it’s stored in the db or the operation is canceled. Then we need to distinguish which data to show from the servlet (file or blob). Finally we have to clean up the temporary file when we are done.

Lets dive into the implementation. We start from the application at the end of part 3. As the current JDeveloper version is 12.1.3 we do the implementation in this version. The first task is to migrate the old application to 12.1.3. This is done automatically when opening the old work space in JDev 12.1.3 by answering the ‘OK’ to the migration popup. Nothing need to be done here. However, when you download  the work space you’ll notice some clean up I did, like changing the old af:commandButton to the new af:button.

One thing to notice is that the Apache Commons-IO version is updated to 2.4. This update made one other change necessary in the weblogic-application.xml file.


This entry allows the application to use the included commons-io jar to be loaded before the already available commons-io jar, of an older version, in WebLogic server 12.1.3.

Here are the steps we take to implement the tasks:
1) Save the uploaded data to a temporary file as well as to the blob. This is done for convenience. It’S possible to store the data first in the temporary file and only copy it to the BlobDomain when the user commits the changes.
We implement a new java class UploadBlob which holds the BlogDomain and the path to the temporary file. This class also allows to test if a temporary is available.


import oracle.jbo.domain.BlobDomain;

 * This type class holds the BlogDomain and a path to a temporary file holding the uploaded image data
public class UploadBlob {
     * Holds the uploaded data
    BlobDomain dataBlob;

     * Path to the temporary file if availabe
    String tempFile;

     * C'tor.
    public UploadBlob() {
        tempFile = null;
        dataBlob = null;

     * Gets the status of the temporary file
     * @return true if a temporary file is available, false otherwise
    public Boolean getTempFileAvailabe() {
        return (tempFile != null ? Boolean.TRUE : Boolean.FALSE);

     * @param inageBlob
    public void setInageBlob(BlobDomain dataBlob) {
        this.dataBlob = dataBlob;

     * Gets the BlobDomain holding the uploaded data
     * @return
    public BlobDomain getDataBlob() {
        return dataBlob;

     * Sete the path to the temporary file holding the uploaded data
     * @param tempFile path to the temporary file
    public void setTempFile(String tempFile) {
        this.tempFile = tempFile;

     * Getter for path to temp file holding the data of the uploaded data
     * @return path to the temporary file holding the uploaded data
    public String getTempFile() {
        return tempFile;

2) Use this class in the class where the uploaded data is read. This happens in the valueChangeListener uploadFileValueChangeEvent(ValueChangeEvent valueChangeEvent).

     * @param valueChangeEvent
    public void uploadFileValueChangeEvent(ValueChangeEvent valueChangeEvent) {
        // The event give access to an Uploade dFile which contains data about the file and its content
        UploadedFile file = (UploadedFile) valueChangeEvent.getNewValue();
        // Get the original file name
        String fileName = file.getFilename();
        // get the mime type
        String contentType = ContentTypes.get(fileName);
        // get the current roew from the ImagesView2Iterator via the binding
        DCBindingContainer lBindingContainer = (DCBindingContainer) BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding lBinding = lBindingContainer.findIteratorBinding("ImagesView2Iterator");
        Row newRow = lBinding.getCurrentRow();
        // set the file name
        newRow.setAttribute("ImageName", fileName);
        // create the BlobDomain and set it into the row
        UploadBlob blob = createBlobDomain(file, Boolean.TRUE);
        newRow.setAttribute("ImageData", blob.getDataBlob());
        // set the mime type
        newRow.setAttribute("ContentType", contentType);
        String tmp = (blob.getTempFileAvailabe() ? blob.getTempFile() : null);
        UIComponent ui = (UIComponent) valueChangeEvent.getSource();
        // PPR refresh a jsf component
        ui = ui.getParent();


Instead of reading the data into the BlobDomain a changed method createBlobDomain is called (line 18). the method now returns an instance of the new class UploadBlob. Below is the code of the new method:

    private UploadBlob createBlobDomain(UploadedFile file, Boolean createTempFile) {
        // init the internal variables
        InputStream in = null;
        OutputStream outTmp = null;
        UploadBlob blobDomain = null;
        OutputStream out = null;
        File tempfile = null;"Starting to create UploadBlog from data...");
        try {
  "... create BlobDomain...");
            blobDomain = new UploadBlob();
            // Get the input stream representing the data from the client
            in = file.getInputStream();
            // if a temporary file should be created , we do this first as we can't get
            // data data back from the blob until we commit the row. in the next step we
            // write the upload data to a temp file and then copy it into the blob
            if (createTempFile) {
      "... Creating temporary file...");
                File tempdir = FileUtils.getTempDirectory();
                String ext = FilenameUtils.getExtension(file.getFilename());
                if (!ext.isEmpty()) {
                    ext = "." + ext;
      "... set extension to " + ext + "...");
                tempfile = File.createTempFile("upl", ext, tempdir);
      "... " + tempfile.getAbsolutePath() + "...");
                // set path to temporary file
                FileOutputStream fileOutputStream = FileUtils.openOutputStream(tempfile);
      "... copy data to temporary file...");
                IOUtils.copy(in, fileOutputStream);
                in = FileUtils.openInputStream(tempfile);
      "... set inputstream for blog to temporary file...");
            // create the BlobDomain datatype to store the data in the db
            blobDomain.setInageBlob(new BlobDomain());
            // get the outputStream for hte BlobDomain
            out = blobDomain.getDataBlob().getBinaryOutputStream();
            // copy the input stream into the output stream
  "... copy data to BlobDomain ...");
             * IOUtils is a class from the Apache Commons IO Package (
             * Here version 2.0.1 is used
             * please download it directly from
            IOUtils.copy(in, out);
  "... Finished OK");
        } catch (Exception e) {
            logger.severe("Error!", e);
            if (tempfile != null) {
                // delete temp file on exception but don'T throw one if there is another exception
      "Deleted temporary file " + tempfile.getAbsolutePath());
        // return the filled BlobDomain
        return blobDomain;

Depending on the new boolean parameter passed to the method a temporary file is created and the uploaded data is first saved to the temporary file. After that the data is copied from the temporary file into the BlobDomain. At this point the path to the temporary file is saved in the new class for later reference. In case of an exception the temporary file is removed.
Finally in line 22 and 23 of the value change listener we check if a temporary file was generated and we set the path to it to a pageDef variable (see Creating Variables and Attribute Bindings to Store Values Temporarily in the PageDef). For this we use the code below.

     * Set the temporary file name into a page variable for later use
     * @param name
    private void setTemporaryFileVar(String name) {
        // set pathto temporary file to page variable
        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
        // get an ADF attributevalue from the ADF page definitions
        AttributeBinding attr = (AttributeBinding) bindings.getControlBinding("TemporaryFile1");
        if (attr != null) {

The variable is used in the af:image component in the editImage.jsff fragment

                   <af:image source="/render_image?id=#{bindings.ImageId.inputValue}&tmp=#{bindings.TemporaryFile1.inputValue}" id="i1"
                              shortDesc="#{bindings.ImageName.hints.tooltip}" inlineStyle="width:200px;" partialTriggers="cb3" visible="true"/>

here the path to the temporary file is passed to the servlet as second parameter ‘tmp’. In lines 24-27 of the value change listener we send a ppr to the parent component of the af:image to show the now uploaded image.

Another thing to do is to cleanup after the user either cancel or commit the changes. This is done in the cancel_action() or the commit_action() in the ImageBean. Here we call the deleteTemporaryFile() method which checks the existence of a temporary file and deletes it.

     * delete the temporary file if is present
    public void deleteTemporaryFile() {
        String tempfile = getTemporaryFileVar();

3) The final part of the implementation is done in the servlet which is used to get the data back to the client. This is simple as we read the second parameter passed to the servlet. If it’s not empty we always read the image data from the temporary file. If the parameter is empty the servlet gets the data by reading the row from the DB and read the data from the blob. Here are the relevant parts from the servlet:

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        StringBuilder sb = new StringBuilder(100);
        String appModuleName = "";

        sb.append("ImageServlet ").append(appModuleName);

        try {
            // get parameter from request
            Map paramMap = request.getParameterMap();
            oracle.jbo.domain.Number id = null;
            String tmporaryFilePath = "";
            if (paramMap.containsKey("id")) {
                String[] pVal = (String[]) paramMap.get("id");
                id = new oracle.jbo.domain.Number(pVal[0]);
                sb.append(" id=").append(pVal[0]);
            // check if we find a temporary file name. In this case we allways use this!
            if (paramMap.containsKey("tmp")) {
                String[] pVal = (String[]) paramMap.get("tmp");
                tmporaryFilePath = pVal[0];
                sb.append(" tmp=").append(pVal[0]);

            OutputStream outputStream = response.getOutputStream();
            InputStream inputStream = null;
            BlobDomain image = null;
            String mimeType = null;
            // no temporary file path given, read everything from DB
            if (tmporaryFilePath.isEmpty()) {
                // get method action from pagedef
                BindingContext bindingContext = BindingContext.getCurrent();
                DCBindingContainer amx = bindingContext.findBindingContainer("de_hahn_blog_uldl_view_image_dummyPageDef");
                JUCtrlActionBinding lBinding = (JUCtrlActionBinding) amx.findCtrlBinding("getImageById");
                // set parameter
                lBinding.getParamsMap().put("aId", id);
                // execute method
                // get result
                Object obj = lBinding.getResult();
                ImageAccessViewRow imageRow = (ImageAccessViewRow) obj;

                // Check if a row has been found
                if (imageRow != null) {
                    // Get the blob data
                    image = imageRow.getImageData();
                    mimeType = imageRow.getContentType();
                    // if no image data can be found and no temporary file is present then return and do nothing
                    if (image == null) {
              "No data found !!! (id = " + id + ")");
                    inputStream = image.getInputStream();
                } else {
                    mLogger.warning("No row found to get image from !!! (id = " + id + ")");
                sb.append(" ").append(mimeType).append(" ...");
            } else {
                // read everything from temporary file path
                mimeType = ContentTypes.get(tmporaryFilePath);
                File file = FileUtils.getFile(tmporaryFilePath);
                FileInputStream fileInputStream = FileUtils.openInputStream(file);
                inputStream = fileInputStream;

            // Set the content-type. Only images are taken into account
            response.setContentType(mimeType + "; charset=utf8");
            IOUtils.copy(inputStream, outputStream);
            if (tmporaryFilePath.isEmpty()) {
                // cloase the blob to release the recources
            // flush the outout stream
        } catch (Exception e) {
            mLogger.log(Level.WARNING, "Fehler bei der Ausführung: " + e.getMessage(), e);
        } finally {

The gallery below shows the new work flow.

The work space for part 5 can be downloaded from the ADF EMG Sample side
Or if you are in GIT you can get the work space from GitHub BlogUploadDownload_12.1.3V4