Recent Posts

Integrating Magnolia CMS and custom application security

We have an application integrated into Magnolia CMS. and it’s quite natural to have a single way of handling security. Both Magnolia and our application use JAAS for authentication. However magnolia uses JCR repository to store security data, while our application uses database. Since we didn’t want to cause some possible side effects in Magnolia – the following model was applied: users and a limited set of roles is synchronized between application and Magnolia.

Let’s look at how it looks like.

The first step is to edit login.conf file
Initially it looks like:

appRealm {
com.app.security.AppLoginModule required;
};


magnolia {
info.magnolia.jaas.sp.jcr.JCRAuthenticationModule requisite;
info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required;
};

Lets change it to:

appRealm {
com.app.security.AppLoginModule requisite;
};


magnolia {
com.app.security.CustomLoginModule requisite;
info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required;
};

Where com.app.security.CustomLoginModule, is a new class which is inherited from info.magnolia.jaas.sp.jcr.JCRAuthenticationModule. Below is the code which is used to


public class CustomLoginModule extends JCRAuthenticationModule {
  // Cached user data from the database
  UserDto cachedUser;
  // Cached entity
  Entity entity;

  @Override
  protected void initUser() {
    // Get magnolia a chance to load it's own user.
    super.initUser();
    try {      
      // If the user is not available in Magnolia 
      // JCR repository - null is returned.
      if(getUser() != null) {
         // Lets synchronize data from JCR repository 

         // with the data in the app database.
         synchronizeUser(getUser(), User.class);
      }

      // Reading user data from DB
      final InitialContext ic = new InitialContext();
      Object service = ic

        .lookup("com.app.service.users.AuthenticationService");
      final Class authenticationServiceClass 

        = service.getClass();

      final Method authenticationMethod =
        authenticationServiceClass.getMethod("authenticateUser",

        String.class, String.class);

      cachedUser = (UserDto) authenticationMethod.invoke(
        service, name, new String(pswd));

      // In case if the password of the user has been 
      // changed in magnolia - synchronize it.
      if(getUser() == null) {  
        cachedUser.password = new String(pswd);
      }

      // Add required roles into JAAS context
      final RoleListImpl roleListImpl = new RoleListImpl();
      for (String group : cachedUser.groups) {
        roleListImpl.add(group);            
      }

      // In case if the subject was intialized by 
      // the Magnolia - initialize it.
      if(getUser() == null) {
        subject.getPrincipals().add(getEntity());
        subject.getPrincipals().add(roleListImpl);
        subject.getPrincipals().add(new GroupListImpl());

        // Custom user implementation which extends 
        // info.magnolia.cms.security.ExternalUser
        GenesUser genesUser = 

          new GenesUser(subject, cachedUser);
        user = genesUser;
     }
     // Synchronize user stored in Magnolia with 

     // the data from app database.
     synchronizeUser(cachedUser, UserDto.class);

     // Since now the users are synchronized
     // - login programatically into into application.
     new ProgrammaticLogin().login(name, new String(pswd), "app"
       MgnlContext.getWebContext().getRequest(), 

       MgnlContext.getWebContext().getResponse(), true);
    } catch (Exception e) {
      LOGGER.error(e.getMessage());
    }
  }

 // Builds entity object from the cached user.
 public Entity getEntity() {
   if(entity == null) {            
     entity = new EntityImpl();
     entity.addProperty(Entity.NAME, this.cachedUser.username);
     entity.addProperty(Entity.FULL_NAME, 

       this.cachedUser.fullName);
     entity.addProperty(Entity.PASSWORD, new String(this.pswd));
     entity.addProperty(Entity.EMAIL, cachedUser.email);
     entity.addProperty(Entity.ADDRESS_LINE, 

       cachedUser.address);
     for (String group : cachedUser.groups) {
       addRoleName(group);
     }
   }      
   return entity;
 }

  // Synchronizes users of Magnolia and app, 
  // It's a simple reflection call to some
  // other class which is responsible for synchronization.
  private void synchronizeUser(Object user, Class paramClass) {      
    try {
      final Class classData = Class.forName(

        "com.soluter.genes.AccountSynchronizer");
      final Method method 

        = classData.getMethod("synchronizeUser", paramClass);
      method.invoke(null, user);
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }
}

AccountSynchronizer does two-way synchronization between JCR repository and application database.

public class AccountSynchronizer {
  // Gets data from the magnolia user and outs them into app database.

  public static void synchronizeUser(User user) {
    // Skip user synchronization for the default users
    if (MgnlUserManager.ANONYMOUS_USER.equals(user.getName())
        || MgnlUserManager.SYSTEM_USER.equals(user.getName())) {
      return;
    }
 

    // Reading user.
    final UserService userService 
      = getServiceLocator().getUserService();
    UserDetailsDto userData 

      = userService.getUserDetails(user.getName());
    boolean newUser = userData == null;
    if (newUser) {
      // In case if the user does not exist in app - create it.

      userData = new UserDetailsDto();
    }

    // Synchronizing data and roles.
    userData.password = user.getPassword();
    userData.username = user.getName();
    userData.email = user.getProperty(Entity.EMAIL);

    
    // Saving data.
    try {
      if (newUser) {
        userService.createUser(userData);
      } else {
        userService.saveUser(userData);
      }
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }




  // Synchronizes Magnolia user with the data from app data base 
  public static void synchronizeUser(UserDto user) {
    try {

      // Reading public branch of the USERS workspace
      final HierarchyManager hierarchyManager 

        = MgnlContext.getSystemContext()
          .getHierarchyManager(ContentRepository.USERS);
      Content content = ContentUtil.getOrCreateContent(

        hierarchyManager.getRoot().getContent("public"),
        user.username, ItemType.USER, true);
      MgnlUser mgnlUser = new MgnlUser(content) {



        // Change behaviour of what should happen in case of 
        // adding role.
        @Override
        public void addRole(String roleName) {
          final HierarchyManager hierarchyManager 

            = MgnlContext.getSystemContext()
            .getHierarchyManager(ContentRepository.USER_ROLES);
          try {

            // Change behaviour of what should 
            // happen in case of adding role
            Content node = ContentUtil
              .getOrCreateContent(this.getUserNode(), 
              "roles", ItemType.CONTENTNODE, true);
            String value = hierarchyManager.getContent(

              "/" + roleName).getUUID();
            HierarchyManager usersHM 

              = MgnlContext.getSystemContext()
               .getHierarchyManager(ContentRepository.USERS);
            String newName = Path.getUniqueLabel(

              usersHM, node.getHandle(), "0");
            // New node is created in repo
            node.createNodeData(newName).setValue(value);
          } catch (Exception e) {
            e.printStackTrace();
          }
        }

        // Change behaviour of what should happen 
        // in case of removing  role.
        @Override
        public void removeRole(String roleName) {
          final HierarchyManager hierarchyManager 

            = MgnlContext.getSystemContext()
              .getHierarchyManager(
                ContentRepository.USER_ROLES);
          try {
            Content node = ContentUtil

              .getOrCreateContent(this.getUserNode(), "roles",
                ItemType.CONTENTNODE, true);
            // Pass through all of the nodes and get 
            // determine node to be deleted
            for (NodeData nodeData : 
              node.getNodeDataCollection()) {
              if (hierarchyManager.getContentByUUID(

                nodeData.getString())
                .getName().equalsIgnoreCase(roleName)) {
                // Node is deleted from repo
                nodeData.delete();
              }
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      };

      // Syncronizing roles/profile data of the user.
      if (user.password != null) {
        mgnlUser.setProperty(

          MgnlUserManager.PROPERTY_PASSWORD,
          new String(Base64.encodeBase64(user.password.getBytes())));
      }
      mgnlUser.setProperty(MgnlUserManager.PROPERTY_EMAIL,

        user.email);

      // determine roles to be added     
      final List rolesToAdd = ...;    
     
// determine roles to be removed     
      final List rolesToRemove = ...; 
      final List currentRoles = Arrays.asList(user.groups);


      // Remove roles.

      for (String roleName : rolesToRemove) {
        mgnlUser.removeRole(roleName);
      }


      // Add roles.

      for (String roleName : rolesToAdd) {
        mgnlUser.addRole(roleName);
      }

      // Save user data.
      mgnlUser.getUserNode().save();
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }
}

Since we already have application UI which is used to create roles specific for the application, change user details and password - we call AccountSynchronizer#synchronizeUser every time we update user account.

Also we allow anonymous users to access web site and have a separate login form. To provide logins both into magnolia and application from the form - the following code is used:


// Login into application
new ProgrammaticLogin().login(username, password,
  "app", getThreadLocalRequest(), getThreadLocalResponse(),
  true);

// Login into magnolia
CredentialsCallbackHandler callbackHandler = new PlainTextCallbackHandler(
  username, password.toCharArray(), "public");

SecuritySupport.Factory.getInstance().authenticate(
  callbackHandler, "magnolia");

Java Resource File Editor 2

Localization support in Java is rather good. But what about the convenience of providing localized resource bundles?

I usually use NetBeans for the development and editing resource files. But what if you would like to provide this localization files for your customer? So we’ve decided to do some investigations on this topic. The primary criteria according to which the tools were estimated are the following:

  1. Simplicity of use
  2. Support of simultaneous display of multiple language data (required)
  3. Detecting keys with the missed translations and highlighting them
  4. Usually I group properties in some way, so that properties from the same screen are situated closely in the properties file. It would be nice not break this groups.
  5. Stability
  6. License should allow you to change the source-code in case if you need to fix some defects occur. (required)

Let’s start with small standalone tools, which can be easily used if you already have JRE installed.

Resource Bundle Editor

Pros:

  1. It’s a single tool in the review which does versioning of the content by itself. It adds specific comments which allow to track changes across files.
  2. Good documentation. I personally believe that it was created because the tool itself is rather complex to use.

Cons:

  1. Not supported since 2006
  2. Not stable. While playing for 10 minutes – I’ve noticed several defects.
  3. No highlight of the missed items
  4. Complex UI

After saving file – it’s totally changed and contains added comments required for versioning.


Personal Opinion: Unstable tool which has a very complex UI and a unique versioning feature. Changes properties file incredibly. Not going to propose it to our customers.

Popeye

Pros:

  1. Highlightning of the missed values
  2. Cute and simple UI

Cons:

  1. Not supported since 2007
  2. Not very stable. I’ve observed several exceptions in the console but didn’t notice that it has influenced any functionality.

After saving – the content of the properties files was reorganized but it was done in quite a smart way.



Personal Opinion: If you need a simple and a smart tool – Popeye is your choice. Not absolutely sure about the general stability of it but it worked nicely in my case. Going to propose it for our customers.

prbeditor

Pros:

  1. Simple and functional UI
  2. Seems to be rather stable, no problems were observed during testing.

Cons:

  1. Not supported since 2007
  2. Rows with the missed values are not highlighted

The result after save was rather strange.

Personal Opinion: Stable, simple and nice tool which lacks highlight of the missed items. The order of the saved values seems to be rather strange. Won’t propose to our customer because of the absent highlighting.

Zaval

Previously this tool was used by one of our customers.

Pros:

  1. Simple
  2. Missed values are highlighted

Cons:

  1. UI from the 90th
  2. Not stable. A number of exception and problems were observed during testing
  3. Last release occurred in 2004

The order of the content became rather strange after editing in Zaval

Personal Opinion: Not stable tool from the past. Won’t recommend it to our customer.

Conclusion

Based on the results of the review, Popeye was selected to be proposed for customer.

However as you can see, all of the mentioned tools are a bit outdated. So it was decided to look at a more dynamic and supported segment of IDEs. Three of the most popular IDEs were under review: NetBeans, Eclipse and IntelliJ IDEA Community Edition

NetBeans: Resource Bundle Editor

Pros:

  1. Integrated into my favourite IDE :-)

Cons:

  1. Rows with the missed values are not highlighted
  2. Seems to be a bit outdated. Support for 6.5 is declared only. But works fine in 6.8

The behaviour of the save operation is ideal. Everything remains on its own places.

Personal Opinion: Nice plug-in which unfortunately does not highlight missed values.

IntelliJ IDEA Community Edition

Pros:

  1. Everything works perfectly. It fully meets specified criteria.
  2. No need to install plug-in. It’s already bundled in the installation.



Order of the saved is also perfect.



Personal Opinion: I really like the way it’s implemented in IDEA. Simple, stable and rather smart.

Eclipse: Babel

Pros:

  1. Babel is unbelievably smart and unbelievably integrated into Eclipse. Duplicated and missed entries are displayed in the Problems view.
  2. Missed items are highlighted

Cons:

  1. Binary bundles are not available on the official page. You’ll need either to build plug-in from sources or find built already somewhere else.

I was absolutely disappointed by the sort order. It appeared to be sorted and added spaces.

Personal Opinion: It’s the smartest plug-in I’ve seen. However the need to build from sources and order of the saved properties is a bit disappointing.

Conclusion


In my point of view IntelliJ IDEA has the most stable and mature support of the localized files. It even has it without installing any additional plug-ins. From the other side, Babel demonstrates unique features which I would like to see in other IDEs. Unfortunately NetBeans plug-in is not the best option here.



As a result, I can admit that there’s a bunch of tools which can help you and your customer in editing resource bundle files. Of course you can use one of the massive IDEs, but you can also select a small tool based on your needs.

It’s absolutely possible that I’ve missed some interesting features or even tools which still meet of needs. May be I’ve even missed something that meets our needs – but it means that usability is not so good to make this feature enabled very quickly.

Some words about JNDI

I think all Java-developers know JNDI (Java Naming and Directory Interface) and all of them use it. The common case of its use is getting datasource and getting JMS queue. In this post I’d discuss usage of JNDI for custom objects.

On one of our project we need to have access to one common knowledge base, which should be shared between several application deployed on this application server (it was glassfish v3, but it doesn’t matter).

Thus our application is based on spring framework the first idea dealt with it. We thought about implement this recommendation: http://springtips.blogspot.com/2007/06/using-shared-parent-application-context.html. But after that we found that knowledge base should work like database, but uses another API (our own). So we decided to use JNDI and implement own ObjectFactory (http://java.sun.com/javase/6/docs/api/javax/naming/spi/ObjectFactory.html).

First we created simple Data Transfer Object, which should be created by ObjectFactory and provides all necessary data to our application. It looks like:

public class Data {

private final byte[] idf;

public CkbData(final RealVector idf) {

this.idf = idf;
}

public RealVector getIdf() {

return idf;
}

}

After that we created simple implementation of ObjectFactory:

public class DataFactory implements ObjectFactory {

@Override
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable environment) throws Exception {
final Reference reference = (Reference) obj;
final String property1 = (String) reference.get(”property1″).getContent();
final String property2 = (String) reference.get(”property2″).getContent();
// do something
return result;
}

}

So here name provides name of necessary resource and using obj object you may read configuration properties of this resource. After that based on these data you make create required object and return it.

By the way glassfish provides good UI for configuration custom resources – it is illustrated on the following screen:

It was very easy task and does not take a lot of time, but effect was amazing, because:

  • we have common knowledge base for all application – it significant decreased memory usage and deploying/starting time of new applications;
  • we can configure our knowledge base in runtime by changing properties of JNDI resource;
  • we should not change source of our application – we only need to change configuration files.

Therefore I suggest to take into account possibility of JNDI – it may be very useful!

Improving GWT compilation speed 1

Yesterday we have moved one of our projects from GWT 1.7 to GWT 2.0. And GWT compilation appeared to run slower on my host.

So I’ve started looking for a way to make this process faster.

The initial compilation of the project took 207 seconds and permutation compilation 170 seconds

The main idea of speeding up compilation is to reduce the number of the compiled permutations. Permutation is a combination of the supported browser and locale.

By default permutations for the following browsers are compiled:

  • ie6
  • ie8
  • gecko
  • gecko1_8
  • safari
  • opera

So in case of having three locales – 18 permutations are compiled.

But do we need all these during development? I guess no. Usually you develop within one browser and the rest are used once the development is completed.
So lets reduce the list of the supported browsers by adding the following string in our *.gwt.xml file

<set-property name="user.agent" value="gecko"/>

This reduces the list of browsers to the gecko based ones, like FireFox or SeaMonkey.
Now compilation takes 84 seconds and permutations compilation – 66 seconds. Not too bad, right?

Okay, lets go further.
Lets add draftCompile GWT compiler flag. Since our project is built by Maven – go to pom.xml and put the following string into the configuration section of the GWT plugin:

<draftCompile>true</draftCompile>

This option allows you to skip JavaScript optimization step. And the compilation time reduces to 65 seconds, permutation compilation – 48 seconds.

The next option which I’ve tried – is the localWorkers compilation option. This option specifies the number of parallel processes used to compile GWT permutations. The default value is quite fine and changing it didn’t bring any speed up.

So the last option I’ve tried was reducing permutations count by reducing count of the compiled locales. I’ve specified the following string in my *.gwt.xml file

<set-property name="locale" value="en"/>

So there’s only one english locale compiled. Now we have only one permutation compiling: English locale for Gecko-based browsers. The compilation time reduced to 48 seconds(30 seconds to compile permutations).

All of the results are combined into the table below

Description Compilation (in sec.) Permutation Compilation (in sec.)
Initial 207 170
After specifying user.agent property 84 66
After specifying draftCompile parameter 65 48
After specifying localWorkers parameter 66 48
After specifying locale property 48 30

As you can see – the compilation speed decreased more than 5 times. This difference is really vivid on a smal project and can bring you a huge benefit on a large project.

The following environment was used during the testing: Fedora 13 x86_64, Oracle JDK 1.6.0_20, GWT 2.0.3, Maven 2.1.0.

Working with JCR in Magnolia-CMS

Magnolia CMS is popular Java-based CMS, but unfortunately there is not enough documentation regarding it. For example, I decide to store and load some data into built-in JCR repository and I did not find guide for it. Thus I decided to create this post.

So my goal is use JCR as storage for my custom data. I want to store data into it and load data.

So let’s start. First I’d to get Content and then add same entities into it.

info.magnolia.cms.util.ContentUtil is main class, which we will use. Its getContent-method returns content by id of repository and path to content. The following screen illustrates where you may find name of repositories (by the way name of repository equals to id of repository :-) ) and how to use path.

So the following code check does “myfolder” (I will use this folder for storing my entities) exist and creates it if it doesn’t exist:

Content myfolder = ContentUtil.getContent(”website”, “/myfolder”);
if (myfolder == null) {
final Content root = ContentUtil.getContent(”website”, “/”);
myfolder = root.createContent(”myfolder”);
root.save();
}

Note that I call save-method of owner of created content – not of this content.

After that we have created myfolder and now we may start to add entities into it by the following way:

final Content contentNode = myfolder.createContent(entityname, ItemType.CONTENTNODE);
myfolder.save();

contentNode.createNodeData(”property1″, PropertyType.LONG).setValue(each.getId());
contentNode.createNodeData(”property2″, PropertyType.STRING).setValue(each.getText());
contentNode.createNodeData(”property3″, PropertyType.DATE).setValue(Calendar.getInstance());
contentNode.save();

So here entityname is name of entity, which should be created and contentNode is representation of it and you should call save-method of parent folder for creating this entity. After that you may specify properties of this entity by creating node data and setting values of it. When all properties are specified you may store all changes by calling save-method of contentNode.

In conclusion, I’d note that all ContentUtil uses Context, which is stored and managed by MgnlContext. By default it has right of current user.

Some words about domain name scams

Yesterday we received a letter with such content:

(If you are NOT CEO,please forward this to your CEO, because this is urgent.Thanks.)

Dear CEO,

We are the department of registration service in China. we have something need to confirm with you. We formally received an application on Jun. 2, 2010, One company which self-styled “Mintor(Japan)Venture Capital Co.,Ltd” are applying to register(softteco) as internet brand name and domain names as below (softteco.cn softteco.com.cn softteco.mobi softteco.asia softteco.in softteco.hk softteco.cc softteco.tw etc.).

After our initial checking, we found the internet brand name and these domain names being applied are as same as your company’s, so we need to get the confirmation from your company. If the aforesaid company is your business partner or your subsidiary company, please DO NOT reply us, we will approve the application automatically. If you have no any relationship with this company, please contact us within 15 workdays. If out of the deadline, we will approve the application submitted by “Mintor(Japan)Venture Capital Co.,Ltd” unconditionally.

Please forward the email to your decision maker,and let them contact me in time,so that we can handle this in reasonable,Look forwarding to hearing from you.

Best Regards,

Kevin Wu
Senior Director
TEL: +86 21 69929440
Fax: +86 21 69929447
Website:http://www.qp-world.org.cn

Address:Room 902,8th,nong 1518,Jinyuan 1st Road,Jiading District, Shanghai city.

It a bit worried me as a CEO. Despite we haven’t any business so far in asia, it is not very comfortable to have another one company with same name as yours.
After viewing prices that are quite high (from 30 to 50 EUR per year), I started thinking that it’s a kind of new trend of Internet fraud. And really, after some googling I found quite a lot of sites about domain name scams from asia.
One that I like with explanation of what domain name scams means:
http://www.firetrust.com/en/blog/chris/domain-name-scams?page=13

Simple web server in 5 seconds

Web server is a useful thing. Specially if it is instant:

  • Share files with neighbors
  • Try-out the latest “super-duper” site from designer (having resources at /xxx URLs)
  • Fix that site and see your changes

All you need is Python installed (you are developer, aren’t you?) and command line (console) opened:

cd MY_SITE_DIRECTORY
python -m SimpleHTTPServer

You will get a web server working:

Serving HTTP on 0.0.0.0 port 8000 …

Get your files! Open in your browser:

http://127.0.0.1:8000/

To stop the server press [Ctrl-C] or just close the console window.

P. S. If you have index.html file it will be shown instead of directory index.
P. P. S. You may use any IP that your machine have. For example, 127.0.x.x. You may change your hosts file to access this server at any domain you want.

Try [Ubuntu] Linux in 5 minutes SAFELY 4

If you never tried Linux OS you should give it a try.

It is worth it:

  • Technically one the most advanced OS in the world
  • Very reliable, stable and secure
  • Pretty fast and high-performance
  • Virus-free
  • Support for almost all hardware is out-of-the-box
  • (Ubuntu) Pretty simple, easy-to-use and nice
  • Software for daily tasks is out-of-box (web browsers, Office applications, music and video players, image viewers and editors)
  • Useful low-level tools for developers and administrators is out-of-box
  • Easy to try (no need to install)
  • Completely open-source
  • Completely customizable
  • FREE

Nowadays all you need to try it out is USB flash (at least 1Gb) and internet connection needed. It would not modify any of your HDD.

Just few steps towards:

  1. Get liveCD ISO image of Linux
    You should download the liveCD image of the Linux distributive that you want to check. I advise you to try last release of Ubuntu from ubuntu.com .
    You may skip this step and download the image automatically.
  2. Install UNetbootin
    Go to UNetboot site, select your OS (Windows/Linux distributive/*BSD), download and install it to your machine. It may need administrative rights.
  3. Format USB flash
    Format USB flash to FAT32. On Linux you may use gparted for that.
  4. Run UNetbootin
    You may need administrative rights for that.
  5. Provide ISO image
    Provide the image – select “Disk Image”, “ISO”, select the image file you have.
    If you skipped step #1 you should download the image automatically – select “Distribution”, select distrubution and version.
  6. Write image to USB flash
    Select Type => “USB drive”, Drive => your USB flash, and click “OK” button. Wait for image to write.
  7. Restart your computer
  8. Boot from USB flash
    By default your computer should boot from your USB flash. If it doesn’t you should enter your BIOS settings and set up booting from remote devices. You may also enter BIOS boot menu (if any) and select to boot from your USB flash.
  9. Enjoy!

After you finished with Linux – just restart it, detach your USB flash and boot back to your common environment.

You may use blank CD-R/RW instead of USB flash:

  1. Get liveCD ISO image of Linux
  2. Burn the image to your CD-R/RW or DVD-R/RW
  3. Restart computer
  4. Boot from CD/DVD
  5. Enjoy!

Have a nice flight in Linux world!

Make a simple daemon

In large projects some daemons are always needed for processing routines tasks in background (clearing caches, reload application, push or pull data, etc.).

There are a lot of ways to daemonize an application in Linux – from simple to complicated. I’d like to show some simplest approaches from my experience that proved that they are simple, easy and reliable enough for staging or development purposes.

Let me walk trough them.

Application in screen

It seems to be the most obvious approach, that is the most transparent to the user:

  • Run screen command:

    screen -S your_label

  • Execute command:

    ./myapp

  • Detach from the screen:

    Press [Ctrl-A], [Ctrl-D]

That’s it. You may manage your “daemons” at any time:

  • See “daemons” list:

    screen -ls

  • See last “daemon” output:

    screen -r your_label

  • Stop (being on “daemon output” screen):

    Press [Ctrl-C]

  • Restart (stop, then run application again):

    ./myapp

  • Don’t forget to close unneeded screen session after you stopped the daemon:

    exit

Run application in background

That’s sound easy. Let’s try:

./myapp

But you can’t run anything else because application doesn’t go background itself. Let’s move it to background:

./myapp &

But output goes to console and obstruct working. Let’s move output to the log file:

./myapp > myapp.log &

But errors output still goes to console. Let’s move error output to the log file too:

./myapp > myapp.log 2>&1 &

Pretty good. However, application would be killed if we close the console (for example, leave that SSH session). Also, your “daemon” application may capture your input if it needs input. Let’s try special application for solving these issues:

nohup ./myapp > myapp.log 2>&1 &

Now it works as expected – in complete background mode. You may manage it:

  • See all application output:

    less myapp.log

  • See recent application output (will add as application outputs):

    tail -f myapp.log

  • See if it is running (first column is the process PID):

    ps -A | grep myapp

  • Stop (using PID from the previous example):

    kill myapp_pid

Almost daemon

Let’s expand previous method so it can be easily managed. I would just provide the final solution (save it as myapp_daemon.sh):


#!/bin/sh
# you may need /bin/bash for that

if [ -z "$1" ]; then

  echo "Please provide daemon command to run: start, stop, restart, status"
  exit 1

fi

APP="./myapp"
APP_NAME="myapp"
APP_LOG="myapp.log"
APP_PID="myapp.pid"

function start(){
    echo "Starting ${APP_NAME}..."
    nohup ${APP} > ${APP_LOG} 2>&1 &
    echo $! > ${APP_PID}
    echo "Started."
}

function stop(){
    echo "Stopping ${APP_NAME}..."
    kill `cat ${APP_PID}`
    rm -f ${APP_PID}
    echo "Stopped."
}

function restart(){
    stop
    start
}

function status(){
    echo "Gathering ${APP_NAME} status..."
    if [ -f ${APP_PID} ]; then
        pid=`cat ${APP_PID}`
        processes=`ps -no-headers --pid $pid`
        if [ "$?" -ne "0" ]; then
            echo "${APP_NAME} process is not found, possible crash"
        else
            echo "${APP_NAME} is running:"
            echo "$processes"
            tail ${APP_LOG}
        fi
    else
        echo "${APP_NAME} is not started"
    fi
    echo "Done."
}

$1

Then make executable:

chmod +x myapp_daemon.sh

And enjoy – start / restart / see status / stop:

./myapp_daemon.sh start
./myapp_daemon.sh restart
./myapp_daemon.sh status
./myapp_daemon.sh stop

Conclusion

You may easily create simple but powerful daemons yourself. However, you should look at more complex approaches for production environment when you need scheduled run and processes respawn.

Model – View – Controller (MVC) 1

MVC is very old and very famous design pattern. It is used in web and desktop applications, in different programming languages (C++, Java, .NET, Python, etc.).
First I read about it in Design Patterns. Elements of Reusable Object-Oriented Software and since that time I have heart a lot of things about it and see a lot of realization of this pattern.
I decide to write this post thanks to statement of my good friend – he said that MVC is not used in Java web frameworks. Thus I want to show that it is used and MVC realization in Java is not worse than in Python/Django.
So let’s start from small review of MVC pattern.
The following diagram illustrates main concept of MVC pattern.
Here model is object, which contains information about domain. Model does not have visual interface and it contains all data, which does not link with visual interface. So it may be domain object or script.
View is responsible for showing data of model using UI mechanisms.
All changes of data should be handled by Controller, which receive data, make all necessary operations and refreshes view. So in this case graphical interface consists of view and controller. Thus division between view and controller is not so important and therefor sometime it is not visible.
Dependency between view and model is much more important, because they belong to different areas of software development. Because when you’re working on view you should care about user interface and its usability, but when you’re working on model you should concentrate on business logic. Moreover there are cases when the same information should be shown by different ways.
The following table shows model, view and controller in different web frameworks:
Frameworks Model View Controlle
GWT DTOs, which are placed in common part Custom and standard widgets and composition of them Listeners and callbacks within servlet-based services
Spring MVC DTOs, which are placed in Spring Model class JSP Spring Controller classes
JSF DTOs, which backing beans return JSP Backing beans
Python/Django JSON-based DTOs Template Set of request handler methods
Also notes that some frameworks need additional JavaScript-based mechanisms, which are responsible for processing AJAX calls. These mechanisms are also part of controller.
So as you can see Java web frameworks actively and successfully use MVC pattern.
May be my friend mean that we did not use RESTful services together with JavaScript libraries like jQuery or DOJO, but it is another story and I’d to describe it in one of next posts.