OAuth flow
March 13, 2014 1 Comment
I have tried to draw the flow of Twitter OAuth as well as possible. The signatures are yet to be investigated.
This is the best picture quality I could get.
Ask Forgiveness. Not permission.
March 13, 2014 1 Comment
I have tried to draw the flow of Twitter OAuth as well as possible. The signatures are yet to be investigated.
This is the best picture quality I could get.
March 10, 2014 1 Comment
I have not fully analyzed the OAuth flow yet. Another post will deal with that. So for now I am able to use OAuth to call the Twitter API and redirect to my callback URL.
I have registered this callback URL when I created the Twitter Application.
Configured these to be used by the Play application.
March 7, 2014 Leave a comment
I really cannot believe that the firms in Chennai do not have any need for newer technology. On the one hand requirements are clear about scalability, resilience etc. On the other hand the developers do not show interest in new ideas. We had a requirement to notify users when reports are generated in the background thread.
Why don’t we read books and learn to use newer ideas ?
Play has an event handling mechanism that publishes events that refresh the browser with new data.
When I submit new data in the browser on the right, it shows up immediately in the other browser.
February 27, 2014 Leave a comment
I have just completed the UI using Play’s assets. I need to explore the asset controller and compiler. This seems to be interesting and is not part of any Java framework I have used.
I had to install Sass
February 24, 2014 1 Comment
I followed the instructions to deploy the Play application to CloudBees.
I installed this SDK to interact with the cloud infrastructure. So this created a profile based
on my CloudBees account.
Mohans-MacBook-Pro:cloudbees-sdk-1.5.2 radhakrishnan$ bees help
# CloudBees SDK version: 1.5.2
# CloudBees Driver version: 1.3.8
Installing plugin: org.cloudbees.sdk.plugins:ant-plugin:1.3.0You have not created a CloudBees configuration profile, let’s create one now…
Enter your default CloudBees API end point [us | eu]: us
Enter your CloudBees account email address: radhakrishnan.mohan@gmail.com
Enter your CloudBees account password:
Plugin installed: org.cloudbees.sdk.plugins:ant-plugin:1.3.0
Installing plugin: org.cloudbees.sdk.plugins:app-plugin:1.5.6
Plugin installed: org.cloudbees.sdk.plugins:app-plugin:1.5.6
Installing plugin: org.cloudbees.sdk.plugins:config-plugin:1.3.2
Plugin installed: org.cloudbees.sdk.plugins:config-plugin:1.3.2
Installing plugin: org.cloudbees.sdk.plugins:db-plugin:1.3.3
Plugin installed: org.cloudbees.sdk.plugins:db-plugin:1.3.3
Installing plugin: com.cloudbees.sdk.plugins:service-plugin:1.2.3
Plugin installed: com.cloudbees.sdk.plugins:service-plugin:1.2.3
Type ‘bees help ‘ for help on a specific subcommand.SDK subcommands:
help List all commands
init Re-initialize the SDK config file
plugin:delete Delete a SDK plugin
plugin:info Get SDK plugin information
Mohans-MacBook-Pro:cloudbees-sdk-1.5.2 radhakrishnan$ bees config:set -a mohanr/playconf AppDynamics=false
Application config parameters for mohanr/playconf: savedApplication Parameters:
applyEvolutions.default=true
DB_USER=mohanr
DB_PASS=test
DB_URL=jdbc:mysql://ec2-50-19-213-178.compute-1.amazonaws.com:3306/playconftest
applyDownEvolutions.default=true
AppDynamics=false
Runtime Parameters:
java_version=1.7
The settings to enable evolutions did not work and I could not access the application.
So I switched off the evolution facility and removed 1.sql and then deployed the application. I think this evolution facility can be switched off in application.conf also.
Application Parameters:
DB_USER=mohanr
DB_PASS=test
applyDownEvolutions.default=false
applyEvolutions.default=false
DB_URL=jdbc:mysql://ec2-23-21-211-172.compute-1.amazonaws.com:3306/helloplaytest
AppDynamics=false
Runtime Parameters:
java_version=1.7
Mohans-MacBook-Pro:hello-play radhakrishnan$ ./activator dist
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[info] Loading project definition from /Users/radhakrishnan/Documents/hello-play/project
[warn] Multiple resolvers having different access mechanism configured with same name ‘typesafe-ivy-releases’. To avoid conflict, Remove duplicate project resolvers (`resolvers`) or rename publishing resolver (`publishTo`).
[info] Set current project to hello-play (in build file:/Users/radhakrishnan/Documents/hello-play/)
[info] Packaging /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT-sources.jar …
[info] Done packaging.
[info] Main Scala API documentation to /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/api…
[info] Wrote /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT.pom
[info] Packaging /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT.jar …
[info] Done packaging.
model contains 30 documentable templates
[info] Main Scala API documentation successful.
[info] Packaging /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT-javadoc.jar …
[info] Done packaging.
[info]
[info] Your package is ready in /Users/radhakrishnan/Documents/hello-play/target/universal/hello-play-1.0-SNAPSHOT.zip
[info]
[success] Total time: 16 s, completed Feb 23, 2014 9:23:11 PM
Mohans-MacBook-Pro:hello-play radhakrishnan$ bees app:deploy -a playconf -t play2 target/universal/hello-play-1.0-SNAPSHOT.zip
-bash: bees: command not found
Mohans-MacBook-Pro:hello-play radhakrishnan$ source ~/.profile
Mohans-MacBook-Pro:hello-play radhakrishnan$ bees app:deploy -a playconf -t play2 target/universal/hello-play-1.0-SNAPSHOT.zip
Deploying application mohanr/playconf (environment: ): target/universal/hello-play-1.0-SNAPSHOT.zip
Application parameters: {containerType=play2}
……………………uploaded 25%
……………………uploaded 50%
……………………uploaded 75%
……………………upload completed
deploying application to server(s)…
Application mohanr/playconf deployed: http://playconf.mohanr.cloudbees.net
The application was accessible now as the following screenshots show.
February 23, 2014 Leave a comment
I post as I work my way through the Play material. I have not still read The reactive manifesto and relate it to Play. So I used the same classic trick popularized by Struts to debug this. As far as this type of error display mechanism is concerned I did not find anything different between Play and old versions of Struts.
I did not initialize isApproved to false.
package models;
import javax.persistence.*;
import javax.validation.Valid;
import play.data.validation.Constraints.MaxLength;
import play.data.validation.Constraints.MinLength;
import play.data.validation.Constraints.Required;
import play.db.ebean.*;
@Entity public class Proposal extends Model {
@Id
public String id;
@Required public String title;
@MinLength(value = 10)
@MaxLength(value = 1000)
@Column(length=1000)
public String proposal;
@Required public SessionType type = SessionType.OneHourTalk;
@Required public Boolean isApproved;
public String keywords;
@Valid
@OneToOne(cascade=CascadeType.ALL)
public Speaker speaker;
}
@(proposal: play.data.Form[Proposal])
@import helper._
@main("New Proposal"){
@if(proposal.hasErrors) {
<div class="alert alert-error">
@proposal.errors
</div>
}
@form(action = routes.MainController.submitProposal()){
<h3>Proposal</h3>
@inputText(proposal("title"))
@textarea(proposal("proposal"))
@inputText(proposal("keywords"))
<h3>Speaker</h3>
@inputText(proposal("speaker.name"))
@inputText(proposal("speaker.email"))
@textarea(proposal("speaker.bio"))
@inputText(proposal("speaker.twitterId"))
@inputText(proposal("speaker.pictureUrl"))
<p class="submit">
<button type="submit" class="button green" id="submitForm">Submit</button>
</p>
}
}
I can customize it but this sufficed.
February 22, 2014 Leave a comment
I started worked with a play example and encountered this error.
package controllers;
import models.Proposal;
import play.data.Form;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Results;
import models.*;
public class MainController extends Controller {
public static Result welcome(String name) {
return ok("<h1> Welcome " + name + "</h1>").as("text/html");
}
public static Result index() {
return ok(views.html.index.render("Hi from Java"));
}
public static Result newProposal(){
Form<Proposal> proposalForm = Form.form(Proposal.class);
return ok(views.html.newProposal.render(proposalForm));
}
public static Result submitProposal(){
return Results.TODO;
}
}
[error] /Users/radhakrishnan/Documents/hello-play/app/controllers/MainController.java:23: error: incompatible types: play.data.Form cannot be converted to play.api.data.Form
[error] return ok(views.html.newProposal.render(proposalForm));
I struggled with this error until I set play.Project.playJavaSettings in my build.sbt
February 16, 2014 Leave a comment
I was trying to use the activator UI to play with the Play Framework. It worked except for this annoying issue.
So I switched to the eclipse setup which works quite well.
[hello-play] $ Mohans-MacBook-Pro:hello-play radhakrishnan$ ./activator
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[info] Loading project definition from /Users/radhakrishnan/Documents/hello-play/project
[warn] Multiple resolvers having different access mechanism configured with same name ‘typesafe-ivy-releases’. To avoid conflict, Remove duplicate project resolvers (`resolvers`) or rename publishing resolver (`publishTo`).
[info] Set current project to hello-play (in build file:/Users/radhakrishnan/Documents/hello-play/)
[hello-play] $ eclipse with-source=true
[info] About to create Eclipse project files for your project(s).
[info] Resolving com.typesafe.atmos#atmos-sigar-libs;1.3.1 …
[info] downloading http://repo1.maven.org/maven2/org/scala-lang/scala-library/2.10.2/scala-library-2.10.2-sources.jar …
[info] [SUCCESSFUL ] org.scala-lang#scala-library;2.10.2!scala-library.jar(src) (41827ms)
[hello-play] $ ~run
— (Running the application from SBT, auto-reloading is enabled) —
[info] play – Listening for HTTP on /0.0.0.0:9000
(Server started, use Ctrl+D to stop and go back to the console…)
[success] Compiled in 715ms
[info] play – Application started (Dev)
[info] Compiling 1 Java source to /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/classes…
[success] Compiled in 4s— (RELOAD) —
[info] play – Application started (Dev)
February 10, 2014 Leave a comment
This post is not exactly about NIO.2 even though I use SeekableByteChannel. It is about a pestering question asked by two interviewers in the past. I believe a coding task is a good and reliable first step in any interview process. But some people ask questions in a patronising way.
This is one such question. How do you identify duplicate rows in a file ?
So I decided to do what any programmer worth her salt will do. This is not the most efficient way but I wanted to try NIO.2’s SeekableByteChannel because none of the firms I have worked for in the past has any need for any new Java API. They still wallow in legacy Java applications. I don’t get a chance to use it for any project.
I wanted to filter duplicates in column 3 – the name of the page requested – from a sample log.
timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,Latency 1346999466187,32,Home page - anon,200,OK,Anonymous Browsing 1-2,text,true,31 1346999466182,37,Login form,200,OK,Node save 3-1,text,true,36 1346999466184,35,Home page - anon,200,OK,Anonymous Browsing 1-11,text,true,32 1346999466182,37,Home page - anon,200,OK,Anonymous Browsing 1-1,text,true,34 1346999466189,30,Home page - anon,200,OK,Anonymous Browsing 1-4,text,true,27 1346999466185,46,Home page - anon,200,OK,Anonymous Browsing 1-5,text,true,34 1346999466185,44,Search,200,OK,Search 4-1,text,true,35 1346999466188,28,Home page - anon,200,OK,Anonymous Browsing 1-3,text,true,26 1346999466182,33,Home page - anon,200,OK,Anonymous Browsing 1-7,text,true,32 1346999466182,36,Login Form,200,OK,Perform Login/View Account 5-1,text,true,35 1346999466182,35,Home page - anon,200,OK,Anonymous Browsing 1-10,text,true,33
package com.test;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
import java.util.Set;
import java.util.TreeSet;
public class DuplicateTest {
Set<String> values = new TreeSet<>();
public static void main( String... argv ){
DuplicateTest dt = new DuplicateTest();
dt.analyze();
}
private void analyze() {
Path p = Paths.get(File.separator + "Users"
+ File.separator + "radhakrishnan" +
File.separator + "Lambdas", "duplicate.txt");
ByteBuffer b = ByteBuffer.allocate(1);
String encoding = System.getProperty( "file.encoding");
b.clear();
char c;
StringBuilder sb = new StringBuilder();
try(
SeekableByteChannel skbc = Files.newByteChannel(p,
EnumSet.of(StandardOpenOption.READ))) {
//Move the position after the first line(heading)
skbc.position(89);
while( skbc.read( b ) > 0){
b.flip();
c = Charset.forName(encoding).decode(b).get();
//System.out.println(c);
sb.append(c);
if( c == '\n' || c == '\r'){
//Move the position to read the line after the new line
skbc.position(skbc.position());
extractAndStore(sb.toString());
sb = new StringBuilder();
}
b.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(values);
}
private void extractAndStore(String s) {
values.add(s.split("[,]")[2]);
}
}
[Home page - anon, Home page - auth, Login, Login Form, Login form, Logout, Node edit form, Random node - anon, Search, User profile page, node edit post]
January 24, 2014 Leave a comment
package com.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class ValueAnnotation {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
protected @interface TypeUse {
int value();
}
@TypeUse(value = 0) class Test<T>{
}
}
private void processEnclosedElements(List<? extends Element> enclosedElements,
RoundEnvironment roundEnv) {
for( Element e : enclosedElements ){
if (e.getKind() == ElementKind.CLASS){
System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e + "]");
processClassTypeParameters(e);
}
}
}
private void processClassTypeParameters(Element e) {
for( AnnotationMirror am : e.getAnnotationMirrors() ){
for(Map.Entry< ? extends ExecutableElement, ? extends AnnotationValue> m : am.getElementValues().entrySet()){
System.out.println( "[" + m.getKey() +"][" + m.getValue() + "]");
}
}
}
Annotation [@com.test.ValueAnnotation.TypeUse(0)] [com.test.ValueAnnotation.Test]
[value()][0]