Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Wednesday, February 17, 2016

Tapestry5 and the case of the disappearing bootstrap modal dialog

Tapestry5 has a pretty neat way to support JavaScript but once in a while I forget some things. Forgetting things then leads you to errors. In my case, the error was a bootstrap modal not properly displaying or disappearing immediately.

I was working on a simple but reusable modal Tapestry5 component. For some context on how to do this, go here. The important part here is the top part where you declare your JavaScript includes:

@Import(module = {"bootstrap/modal"}) 
public class ModalDialog implements ClientElement{...}

This loads the modal.js from bootstrap. Tapestry5 can do this because the framework is bootstrap aware. We then finish this up with the javascript and tml file for the component.

Thinking all was Ok, I then use this component on a page and this is where I encountered the "disappearing modal" dialog.

After debugging, I followed the bug to my layout component. Again, the important part here is where we declare the JavaScript includes:

@Import(stylesheet = {"context:datatables/css/dataTables.jqueryui.css","context:patternfly/css/patternfly.css", 
                      "context:patternfly/css/patternfly-additions.css"},
        library = {"context:patternfly/js/patternfly.js", "context:mybootstrap/js/bootstrap.min.js"})
public class Layout{...}

Apparently, bootstrap doesn't like when we double load modules. The bootstrap.min.js is a minified bootstrap and it already has the modal.js module. Then, when we load the page where we use the ModalDialog component which double loads the modal.js module.

This bug was easily fixed by removing the import annotation in my ModalDialog component.

I forgot about my JavaScript basics that invoking the script twice equals problems.

Also, this was confirmed by this StackOverflow question.

Wednesday, December 2, 2015

A tutorial on how to use the Tapestry-Security module Part 2

We pick up where we left off.

We start with our AppModule and configure our security service to use our "custom" realm.

    
    // @see http://tynamo.org/tapestry-security+guide
    @Contribute(WebSecurityManager.class)
    public static void addRealms(Configuration configuration, @InjectService("MiscAppRealm") AuthorizingRealm userRealm) {
        configuration.add(userRealm);
    }

With this we then update our MiscRealm.java code:
    
  @Inject
  private UserMembershipDAO umDAO;    

  public MiscAppRealm() {
        super(new MemoryConstrainedCacheManager());
        setAuthenticationTokenClass(UsernamePasswordToken.class);
        setCredentialsMatcher(new MiscRealmCredentialMatcher());
  }

  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        if(pc == null) throw new AuthenticationException("PrincipalCollection was null, which should not happen");
        
        if(pc.isEmpty()) return null;
        
        if(pc.fromRealm(getName()).size() <= 0) return null;
        
        String loginName = (String)pc.fromRealm(getName()).iterator().next();
        if(loginName == null) return null;
                
        AppUsers user = umDAO.FindAppUsersByLoginId(loginName);
        
        if(user == null) return null;
                
        Set roles = new HashSet<>(user.getRolesList().size());
        user.getRolesList().stream().forEach((role) -> {
            roles.add(role.getDescription());
        });
        
        System.out.println("Roles: " + roles);
        
        return new SimpleAuthorizationInfo(roles);
  }

  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {                
        UsernamePasswordToken token = (UsernamePasswordToken)at;
        
        String username = token.getUsername();
        
        if(username == null){
            throw new AccountException("Null usernames are not allowed by this realm");
        }
        
        AppUsers user = umDAO.FindAppUsersByLoginId(username);
                
        if(user.getIsLocked()){
            throw new LockedAccountException("Account: " + username + " is locked.");
        }
         
        return new SimpleAuthenticationInfo(username, user.getEncodedPassword(), new SimpleByteSource(user.getPasswordSalt()), getName());
 }

We then move on to our custom credential matcher (MiscRealmCredentialMatcher.java) which extends from SimpleCredentialsMatcher. The thing there is overriding the doCredentialsMatch() method on it. You need to remember though is that the UserMembership table stores the encrypted password instead as plain text. You'll get the idea when you see the jasypt documentation.

@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
     
     AppUsers target = FindAppUsersByLoginId(UserId);
     String encryptedPassword = target.getPassword();
        
     BasicPasswordEncryptor passwordEncryptor = new BasicPasswordEncryptor();
        
     return passwordEncryptor.checkPassword(String.valueOf(token.getPrincipal()), encryptedPassword);
}

The last part of the puzzle is how we handle the Login form when we submit it. The Tynamo-Security's own code is helpful here.

    
void onValidateFromLogin() throws ValidationException {
        
     Subject currentUser = securityService.getSubject();
                
     if(currentUser == null){
         throw new IllegalStateException("Subject can`t be null");
     }
        
     UsernamePasswordToken token = new UsernamePasswordToken(loginId, password);
     token.setRememberMe(rememberMe);
        
     try {
          currentUser.login(token);
            
     } catch (UnknownAccountException e) {
         login.recordError(loginIdField, "");
         login.recordError(passwordField, "Invalid user name or password.");
     } catch (IncorrectCredentialsException e) {
         login.recordError(loginIdField, "");
         login.recordError(passwordField, "Invalid user name or password.");
     } catch (LockedAccountException e) {
         login.recordError(loginIdField, "Account is Locked. Please see Administrator");
     } catch (AuthenticationException e) {
         login.recordError(loginIdField, "");
         login.recordError(passwordField, "Invalid user name or password.");
     }
}

Object onSuccessFromLogin() throws MalformedURLException, IOException {
    if (StringUtils.hasText(successURL)) {
        if ("^".equals(successURL)) {
             return pageRenderLinkSource.createPageRenderLink(componentResources.getPage().getClass());
        }
        return new URL(successURL);
    }

    if (redirectToSavedUrl) {
         String requestUri = loginContextService.getSuccessPage();
         if (!requestUri.startsWith("/") && !requestUri.startsWith("http")) {
             requestUri = "/" + requestUri;
         }
         loginContextService.redirectToSavedRequest(requestUri);
        return null;
    }
    return loginContextService.getSuccessPage();
}

What's left is to annotate the pages to secure.

Edit: smallish changes to code

Monday, November 30, 2015

A tutorial on how to use the Tapestry-Security module Part 1

It often bothered me how many times I've been answering questions from my students (and Stack) this question: "How do you use Tapestry-Security?"

Actually, Tynamo already wrote a guide but some are actually having a hard time figuring it out. They are confused by the database part and how it connects to the authentication and authorization parts. So this is where I come in and since this is should be pretty long post, I'm breaking it into two parts. Also, I'd be working on the assumption readers:
  • Have working knowledge of Tapestry5
  • Can get a Tapestry5 DAO service going
  • Basic understanding how Shiro works (or at least read the tutorial); YOU NEED TO UNDERSTAND SHIRO because Tapestry-Security is based on it.
  • Are OK with me using jasypt lib for encryption; I know it's not the best so chill your titties, we need to make work first THEN we'll deal with a much stronger encryption procedure.
To get started,

Open your POM.xml file and add the Tapestry-Security and Jasypt modules as a dependency.

<dependency>  
  <groupId>org.tynamo</groupId>  
  <artifactId>tapestry-security</artifactId>  
  <version>0.6.2</version>  
</dependency> 

<dependency>  
  <groupId>org.jasypt</groupId>  
  <artifactId>jasypt</artifactId>  
  <version>1.9.2</version>  
</dependency> 

Rebuild your project after to get the module.

Once that's out of the way, we should start creating a Realm. We are making an Authorizing Realm, which authenticates subjects (or users) AND authorizes them with either Roles or Permissions. Here's a sample:

public class MySecurityRealm extends AuthorizingRealm {

    @Inject
    private UserMembershipDAO umDAO;
    
    public MiscAppRealm() {
        super(new MemoryConstrainedCacheManager());
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

You then need to configure your WebSecurityManager to use this realm. The WebSecurityManager service is something that Tapestry-Security module adds. Also, don't worry about the unimplemented methods in the realm. We're going to fix that on the next post.

Friday, December 5, 2014

Putting Groovy on Mint (and other Linux distros) the easy way

Installing Groovy on any Linux distro is a pain in the ass. Generally, the procedure is:

  1. Install the requisites. This could be an involved process because you could be potentially install a lot of stuff but at minimum just need Java.
  2. Download the binaries for groovy. If your Linux distro has a repo like Debian, I don't recommend using it because it not the latest.
  3. Do a bit of file handling and doing a bunch of sym links to the binaries.
  4. Configure your bash shell for groovy. Just like step 3, not fun and just plain tedious.
Fortunately for me, I've found a much easier way to do these steps with GVM. GVM is a tool for managing parallel Versions of multiple Software Development Kits on most Unix based systems. Inspired by Ruby's RVM, it's a convenient command line interface for installing, switching, removing and listing Groovy libraries. GVM call these libraries as candidates.

Just do this to install GVM:

curl -s get.gvmtool.net | bash

And then do this to install Groovy.

gvm install groovy

That should install the latest version of groovy and we're off and running with groovy development.

Sunday, September 14, 2014

SparkJava and Webjars

I've been playing around with Per Wendel's Spark framework. It's a micro framework inspired by Sinatra and it's in the same vein of node.js and ruby-on-rails. Just the thing is, Spark is Java and by being Java, the whole Java ecosystem is available.

I started learning Spark via the readme section of the site. Once you get through the basics, you start working in your favorite Java stuff. For me, the first thing I wanted to work in is Webjars.

Webjars is this thing we it pack jars with client-side libraries. This allows us to manage client-side libraries using various Java build tools like maven, ivy or gradle.

Adding webjars into an maven project is painless. It's a dependency. Here's a webjar for bootstrap3:

<dependency>  
    <groupId>org.webjars</groupId>  
    <artifactId>bootstrap</artifactId>  
    <version>3.2.0</version>  
</dependency>  

With the webjar added. We now need to tell Spark about it and serve them files. This took me a couple of hours to make it work. I had to figure out that webjars unpack to /META-INF/resources folder and tell Spark about it. It also helped that I looked at Spark's source code and realized that is a special Java servelet.

// Serve our client-side files from here
staticFileLocation("/META-INF/resources"); 

And reference it in our template like this:
<link rel='stylesheet' href='webjars/bootstrap/3.1.0/css/bootstrap.min.css'>

There. Spark app with webjars.

Monday, June 9, 2014

Somehow I got it to work: Tapestry 5.4-beta10 and Google App Engine

Aside from a bunch of crummy errors and missing files, I manage to to get Tapestry 5.4-beta10 to run in a Google App Engine instance. Here's what I learned:
  1. Java 8 and Tapestry 5 don't like each other. A bunch of guys reported it like Matt Raible. There's a work around and it isn't exactly safe for production (yet).
  2. YUIcompressor is missing again from the staging repo.
  3. You need to MAKE sure that your GAE instance name matches your appengine-web.xml application name. 
So how to go about getting your Tapestry5 into GAE. 
  1. Start by creating a Tapestry 5 project via maven. Which one though depends on what version of Java is on your dev machine. I'm running Java 8 so I had to use something greater than 5.4-beta4. I just updated the pom.xml and ran mvn clean compile.
  2. Add a appengine-web.xml to the src/main/webapp/WEB-INF folder.
    <?xml version="1.0" encoding="utf-8"?>  
     <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">  
       <application>YOURAPPNAMEHERE</application>  
       <version>1</version>  
       <threadsafe>true</threadsafe>  
       <sessions-enabled>true</sessions-enabled>  
     </appengine-web-app>
    
  3. Edit the pom.xml to include google app engine devserver. Look for the plugins section and add this lines.
    <!-- Run the application using "mvn appengine:devserver" -->  
     <plugin>  
               <groupId>com.google.appengine</groupId>  
               <artifactId>appengine-maven-plugin</artifactId>  
               <version>${appengine.target.version}</version>  
               <configuration>  
                         <enableJarClasses>false</enableJarClasses>  
                         <port>8182</port>  
                         <address>0.0.0.0</address>  
               </configuration>  
     </plugin> 
    
    Also, add these values in the properties node:
            <appengine.target.version>1.9.6</appengine.target.version>
    
  4. Run mvn appengine:devserver
    There is where it gets hairy, if it fails to run, check the stack trace. If it says yuicompressor is missing then comment it out in the pom.xml and then make sure to run the app in dev mode by adding this line in the AppModule.java in the contributeApplicationDefaults method:
       configuration.add(SymbolConstants.PRODUCTION_MODE, false);
    
    There should clear it up. If there are more problems refer to the appengine docs for maven.
  5. If all goes well and you should have a running Tapestry5 app running locally inside a appengine devserver instance. The next step is to upload it to the appengine servers because that's the whole point.
  6. Run mvn appengine:update
    There should open a web page where authentication code to paste into the command line. Also, I do hope you already created a matching app engine project. No? You are a dumbass.
Here is my tapestry5 after all of that.

Friday, August 17, 2012

Autobind All Tapestry5 services!

Norman Franke, Dmitry Gusev and a bunch of other guys in the Tapestry5 mailing list show us a very cool way to bind services via package traversal. No more binder declarations for DAO services several miles long.

The technique they showed made me want to smack my older self - Why didn't you think of that!? This autobind technique basically just needs a bit of planning - a "convention" if you will. The idea is to put the "implementation" package as a folder below your DAO interfaces. Typically, you would append an "Impl" tag to your DAO interfaces so for example: UserDAO = UserDAOImpl and then place them in the correct packages: com.myapp.dao for the DAO interfaces and then com.myapp.dao.impl for the DAO implementations. The rest is done in the AppModule of Tapestry5.

...
public static void Bind(ServiceBinder binder) throws ClassNotFoundException  
{  
   autoBindServices(binder, ProjectDAO.class.getPackage());  
   .....  
}  
private static void autoBindServices(ServiceBinder binder, Package interfacePackage) throws ClassNotFoundException  
{  
  List<Class<?>> interfaces = Utils.getClassesForPackage(interfacePackage.getName());  
  for(Class intf : interfaces)  
  {  
     String className = interfacesPackage.getName() + ".impl." + intf.getSimpleName() + "Impl";  
     try  
     {  
         Class impl = Class.forName(className);  
         binder.bind(intf, impl);  
     }  
     catch(ClassNotFoundException e)  
     {  
         logger.warn("Class not found during autobinding: {}", className);  
     }  
  }  
}
Very cool stuff.

Sunday, May 20, 2012

Be a game programmer they said

Be a games programmer they said. It's going to be fun they said.

Making games from scratch 10 years ago was hard. Try reading Tricks of the 3D Game Programming Gurus-Advanced 3D Graphics and Rasterization by Andrew LaMothe. The Math alone will make you cry, I did. I thought making a game for Android will be equally as hard. Glad to know there's AndEngine.

AndEngine is a framework for building games on the Android platform. It provides a lot of abstractions so as a programmer you don't have to deal with the low-level details. I particularly like the AndEngine physics extension - rolling your own physics engine is no walk in the park.

A few pointers on getting started with AndEngine:

1. You'll need an actual phone for this. The AndEngine examples can't run on the virtual devices since they can't support the OpenGL stuff.
2. AndEngine is designed for 2D not 3D.
3. As for the turtorial, when done you will get errors. Don't just give up, troubleshoot it. Giving up? What's the fun in that?
4. AndEngine is open-source.

Now, what game should I be making? Any suggestions?


Sunday, March 4, 2012

Quirky stuff with JNDI and MSSQL

My last post talked about getting Glassfish and MSSQL connected. By doing this, we effectively hand over the management of the our database connection to the application container. One less thing to deal with in code.

Now, we try to get some data and see if it works. I decided to try out JDBC first. I could just jump to Hibernate but remember Hibernate just glosses over the details. If JDBC works then I know that Hibernate will work. So my code started as:
        ....
        try{
            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource)ctx.lookup("MSSQL2008");
            
            Connection conn = ds.getConnection();
            Statement stmt = conn.createStatement();
            
            ResultSet rs = stmt.executeQuery("SELECT * FROM [TestDB].[dbo].[Users]");
            String temp = rs.getString("email");
            
            stmt.close();
            conn.close();
           
            return temp;
        }catch(Exception e){
            e.printStackTrace();
        }
That didn't go off without errors. I got a "SQLServerException: The result set has no current row." error. Apparently, the Microsoft JDBC driver I was using didn't move the cursor to the first row of the result set. Feature or bug?
To fix this we forcibly move the cursor to the first row by adding the line: rs.absolute(1).
The code then will look like:

        ....
        try{
            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource)ctx.lookup("MSSQL2008");
            
            Connection conn = ds.getConnection();
            Statement stmt = conn.createStatement();
            
            ResultSet rs = stmt.executeQuery("SELECT * FROM [TestDB].[dbo].[Users]");
            rs.absolute(1);
            String temp = rs.getString("email");
            
            stmt.close();
            conn.close();
           
            return temp;
            
        }catch(Exception e){
            e.printStackTrace();
        }
Save, compile and redeploy and.....another error. Typical. This time the error I got was: SQLServerException: The requested operation is not supported on forward only result sets. Can you get what's the error? So we need to NOT create a forward only result set. This is done by adding the line: createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY). 
The final code is then:
        ....
        try{
            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource)ctx.lookup("MSSQL2008");
            
            Connection conn = ds.getConnection();
            Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
            
            ResultSet rs = stmt.executeQuery("SELECT * FROM [TestDB].[dbo].[Users]");
            rs.absolute(1);
            String temp = rs.getString("email");
            
            stmt.close();
            conn.close();
           
            return temp;
            
        }catch(Exception e){
            e.printStackTrace();
        }
All should be OK now. Now to do some real damage. *evil grin*

Saturday, October 8, 2011

Writing new Java is Groovy

Way back when - this was when I was in college, you had to choose a programming language. Unfortunately for my instructors, I wasn't the sheep they thought I was. I wasn't about to be cowed into using VB6, which by the way, they were ramming it down the throats of my classmates - well most of my classmates. A few of us decided it was our duty to give them the finger and tell them to shove where the sun don't shine.

So I looked at and tried a lot of stuff during this time.
  1. C/C++. Its like using a chainsaw without the chain guard - its liable to cut of your hand when you do something stupid. Damn overflows and pointers in the wrong addresses.
  2. Pascal and/or Delphi. Very cool IDE but very heavy with the keywords. I also just didn't like the language - this is more of a personal preference rather than something that has technical merit. So, Pass.
  3. xBase languages like Clipper. No IDE during that time so programming was done with notepad and a stash of batch files. No dice.
  4. Powerbuilder. It was the gold standard for rapid software development that time. It just cost a couple thousand bucks for the whole thing. Ouch.
So that just leaves Java, which was still owned by Sun Microsystems. It was free, no pointers, had several IDEs to choose from and language idiom that "spoke" to me. That was 10 years ago and like any good hack, I'm still learning, hacking, tweaking new stuff. And this is where Groovy came into the picture.

I'll be the first one to admit, Java as a programming language is far from perfect. Java code is overly verbose is one such flaw. Groovy is more leaner but its still Java; consider the fact that Almost all Java code ever written is also valid Groovy. 

To make my point, take a look that this standard but rather trivial Java POJO.

import java.util.Date;

public class Person {

    String firstName;
    String lastName;
    Date birthDay;

    public Person() {}

    public Person(String firstName, String lastName, Date birthDay) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthDay = birthDay;
    }
    
    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}


No suprises here. I will concede that this can be generating by the IDE but you can't escape the fact that the code is still extensive. Compare this to the equivalent Groovy code.

class Person {
    String firstName;
    String lastName;
    Date birthDay;
}

Seriously, that’s the whole class. Groovy classes are public by default, as are Groovy methods. Attributes are private by default. Access to an attribute is done through dynamically generated getter and setter methods, so even though it looks like we’re dealing with individual fields, we’re actually going through getter and setter methods.

Also Groovy works with my favorite Java framework, Tapestry5 and is supported by Netbeans since 6.5.

And like Ash in Army of Darkness getting the powered glove in place of his right hand: Groovy.