Saturday, June 23, 2012

AWS Elastic Beanstalk Gotchya

I've been digging into using AWS (Amazon Web Services) to deploy my apps to the cloud. It is very promising as it employs a "pay as you go" model and scales very nicely.  

Since I'm a java guy, I downloaded the AWS plugin for eclipse (3.7) and started in with the sample app, which is a travel log. It was very easy to setup as when you create a new AWS project, it is an option to create the sample travel log app. Once created, you can simply right click on it and choose "run on server", which has the nice effect of deploying to the AWS cloud.

Mind you that I'm skipping a few steps about creating an AWS account, getting the credentials, adding those credentials to eclipse via the preferences panel and all that. Most tutorials you'll find online (including the very nicely written one from AWS) all describe this.

At any rate, performing the "run on serve" will fire up an elastic beanstalk instance and deploy the webapp to it. Within a few minutes I was able to navigate to the app via firefox and interact. Very cool.

After a few days I wanted to kill that instance as I didn't want the app continually running (remember, pay as you go right). I logged into the AWS management site, selected the instance and told it to stop. It did indeed stop. Within a minute or so, a new elastic beanstalk instance was running the app and was listed in the running instances table. wtf right?

I guess the whole point of the elastic beanstalk is it will fail over to a new instance and keep at least one instance of your app running in the cloud. This is outstanding for a production system but sucks for dev. I fumbled around google for awhile trying to figure out to do.

I came across a nice article that explained how to really stop the app. Using eclipse, bring up the AWS exlorer. Drill through AWS Elastic Beanstalk until you hit your app. Simply right click and select "terminate". You'll get an alert box asking if you're sure. Select yes and it will undeploy your app from the cloud, effectively killing the instance.

I thought I'd pass along this little nugget in case any other devs where freaking out about usage. :-)

Friday, November 7, 2008

EJB3 example of adding/removing elements from a ManyToMany relationship

Here's the use case: I have two entities in a many to many relationship, a User and a Referral. A User can have many referrals assigned to them and a Referral can have many Users assigned to it.

Database:
users (User Table)
id (primary key)
username
...

referral (Referral Table)
id (primary key)
name
...

Referral_User_Queue Table (join table)
referral_id (foreign key to the referral table, id column)
user_id (foreign key to the user table, id column)

EJB's

@Entity
@Table(name = "users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
...
@JoinTable(name = "referral_user_queue", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, inverseJoinColumns = {@JoinColumn(name = "referral_id", referencedColumnName = "id")})
@ManyToMany
private Collection referralIdCollection;

...
getters and setters
}

@Entity
@Table(name = "referral")
public class Referral implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;

...

@ManyToMany(mappedBy = "referralIdCollection")
private List userIdCollection;

...
getters and setters
}


The User is the owning entity

I have stateless session beans that are facades to these entities (since netbeans generates them for me). The calls I make below are simply calls that end up as "merge" and "find" nothing more. So a call to userFacade.updateUser(User user) ends up being em.merge(user) where em is the injected EntityManager in the stateless session bean.

Here's the test method (I'm using a servlet as a test client for simplicity)

public class TestReferralServlet extends HttpServlet {

@EJB
private UserFacadeLocal userFacade;

@EJB
private ReferralFacadeLocal referralFacade;

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
this.moveReferral(out);
.....
}

private void moveReferral(PrintWriter out) {
//locate the referral, I just happen to have one with the
//primary key of 31
Referral referral = referralFacade.find(new Integer(31));

User me = userFacade.findUser(1);
User advisor = userFacade.findUser(3);
User drs = userFacade.findUser(5);
User counslor = userFacade.findUser(6);

out.println("
1) users size=" + referral.getUserIdCollection().size());

//you have to make a copy of the collection or you will get a
//concurrent update exception when removing from within a loop.
List users = new ArrayList(referral.getUserIdCollection().size());
for(User u : referral.getUserIdCollection()) {
users.add(u);
}

//clean out any users and start with a fresh slate
for(User u : users) {
referral.getUserIdCollection().remove(u);
u.getReferralIdCollection().remove(referral);
userFacade.updateUser(u);
referralFacade.updateReferral(referral);
}

//grab fresh copy just to make sure everything is clean
referral = referralFacade.find(new Integer(31));
out.println("
2) users size=" + referral.getUserIdCollection().size());

//add all users to the referral
referral.getUserIdCollection().add(me);
me.getReferralIdCollection().add(referral);

referral.getUserIdCollection().add(drs);
drs.getReferralIdCollection().add(referral);

referral.getUserIdCollection().add(counslor);
counslor.getReferralIdCollection().add(referral);

referral.getUserIdCollection().add(advisor);
advisor.getReferralIdCollection().add(referral);

userFacade.updateUser(me);
userFacade.updateUser(drs);
userFacade.updateUser(counslor);
userFacade.updateUser(advisor);
referralFacade.updateReferral(referral);

//grab fresh copy to make sure everyone was really added
referral = referralFacade.find(new Integer(31));
out.println("
3) users size=" + referral.getUserIdCollection().size());

for(User u : referral.getUserIdCollection()) {
out.println("
" + u.getFirstname());
}

//now remove drs only
drs.getReferralIdCollection().remove(referral);
referral.getUserIdCollection().remove(drs);
userFacade.updateUser(drs);
referralFacade.updateReferral(referral);

//grab fresh copy to make sure only drs was removed
referral = referralFacade.find(new Integer(31));
out.println("
4) users size=" + referral.getUserIdCollection().size());

for(User u : referral.getUserIdCollection()) {
out.println("
" + u.getFirstname());
}

//voila...everything is right in the world and I didn't write any jdbc code
}

}


Just remember to update both ends of the relationship or the cache will think it still has it. That's why I'm calling userFacade.update and referralFacade.update

Wednesday, November 5, 2008

Authentication Phase Listener - JSF

Use Case: trying to secure every page (except for the login page). The user must be logged in. I am using application level authentication and not container managed.

Basically, the blogs I found mostly worked, but I would get a blank screen if there was an authentication failure. It ends up that you need to ensure that the navigation case in the faces-config.xml file has the
tag listed. Otherwise, you are always one page behind.

Here's the faces-config.xml entry:

<navigation-rule>
<navigation-case>
<from-outcome>authFailure</from-outcome>
<to-view-id>/index.jsp</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>


Then in your phase listener, if authentication fails, do this:

context.responseComplete();
context.getApplication().getNavigationHandler().handleNavigation(context, null, "authFailure");


The "authFailure" is the from-outcome in the faces-config.xml file

That's it...

Thursday, October 23, 2008

Netbeans 6.1 EAR Autodeploy with Glassfish

This is a hybrid of the post: http://www.nabble.com/In-NetBeans6.0.1-with-GlassFish-V2-the-web-application-cannot-auto-deploy.-td15853830.html

Basically, when I used eclipse (myeclipse), I could edit a jsp and it would automatically be updated when I refreshed the browser. It wasn't just jsp's, I could edit managed beans, helper classes, anything except the config files and they would magically appear deployed. Sometimes if I saved with an error in the class it would kill the app and I would have to fix the error and redeploy manually.

When I switched to Netbeans, I lost this nice feature. I was forced to "undeploy/redeploy" each time I made a small change. What a pain.

So I googled and came up with this hybrid solution:

1. Turn off deployment in Netbeans to glassfish: Tools -> Servers, then chose GlassFish, then Options. Uncheck "Directory Deployment Enabled"

2. Edit the project's build.xml file and add a target to copy a newly created ear file to glassfish's autodeploy directory:


<target name="post-dist">
<echo>post dist copy ear</echo>
<copy file="dist/[project_name].ear"
todir="/Applications/NetBeans/glassfish-v2/domains/domain1/autodeploy" />
</target>


That's it, now when I chose "Clean and Build" all changes are autodeployed. I know that you can make this target a bit more generic, but I'll leave that to you.

Enjoy!

Wednesday, May 28, 2008

MAC 0SX with Netbeans 6.0 and Java 1.6

If you install the new 1.6 jdk, netbeans pretty much craps on you. Oh, it will run just fine, but try to create something like, let's say, a java class. It will let you name it, give it a package, then ....nothing. But hey, who needs to create a java class anyway?

http://www.netbeans.org/issues/show_bug.cgi?id=129227 describes the bug.

I didn't mess with moving things around, I simply did this:

Alternative (non-destructive) workaround.

Edit the file /Applications/NetBeans/NetBeans\ 6.1\ Beta.app/Contents/Resources/NetBeans/etc/netbeans.conf

add "-J-Djava.ext.dirs=/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/ext/" to the definition of "netbeans_default_options".

and that's it, restart netbeans and it works. mofo's

Here's the stack trace produced before the fix:

java.lang.UnsupportedClassVersionError: Bad version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:280)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at org.netbeans.ProxyClassLoader.loadClass(ProxyClassLoader.java:213)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:242)
at sun.misc.Service$LazyIterator.next(Service.java:271)
at javax.script.ScriptEngineManager.initEngines(ScriptEngineManager.java:127)
at javax.script.ScriptEngineManager.access$000(ScriptEngineManager.java:55)
at javax.script.ScriptEngineManager$1.run(ScriptEngineManager.java:98)
at java.security.AccessController.doPrivileged(Native Method)
at javax.script.ScriptEngineManager.init(ScriptEngineManager.java:96)
at javax.script.ScriptEngineManager.(ScriptEngineManager.java:69)
at org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler.engine(ScriptingCreateFromTemplateHandler.java:125)
at org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler.accept(ScriptingCreateFromTemplateHandler.java:67)
at org.openide.loaders.MultiDataObject.handleCreateFromTemplate(MultiDataObject.java:694)
at org.openide.loaders.DefaultDataObject.handleCreateFromTemplate(DefaultDataObject.java:159)
at org.openide.loaders.DataObject$CreateAction.run(DataObject.java:1247)
at org.openide.loaders.DataObjectPool$1WrapAtomicAction.run(DataObjectPool.java:238)
at org.openide.filesystems.EventControl.runAtomicAction(EventControl.java:120)
at org.openide.filesystems.FileSystem.runAtomicAction(FileSystem.java:499)
at org.openide.loaders.DataObjectPool.runAtomicAction(DataObjectPool.java:250)
at org.openide.loaders.DataObject.invokeAtomicAction(DataObject.java:861)
at org.openide.loaders.DataObject.createFromTemplate(DataObject.java:793)
at org.openide.loaders.DataObject.createFromTemplate(DataObject.java:773)
at org.netbeans.modules.java.j2seproject.J2SEProjectGenerator.createMainClass(J2SEProjectGenerator.java:368)
at org.netbeans.modules.java.j2seproject.J2SEProjectGenerator.access$200(J2SEProjectGenerator.java:78)
at org.netbeans.modules.java.j2seproject.J2SEProjectGenerator$1.run(J2SEProjectGenerator.java:116)
at org.openide.filesystems.EventControl.runAtomicAction(EventControl.java:120)
at org.openide.filesystems.FileSystem.runAtomicAction(FileSystem.java:499)
at org.netbeans.modules.java.j2seproject.J2SEProjectGenerator.createProject(J2SEProjectGenerator.java:97)
at
org.netbeans.modules.java.j2seproject.ui.wizards.NewJ2SEProjectWizardIterator.instantiate(NewJ2SEProjectWizardIterator.java:181)
at org.openide.loaders.TemplateWizard$InstantiatingIteratorBridge.instantiate(TemplateWizard.java:1023)
at org.openide.loaders.TemplateWizard.handleInstantiate(TemplateWizard.java:595)
at org.openide.loaders.TemplateWizard.instantiateNewObjects(TemplateWizard.java:416)
at org.openide.loaders.TemplateWizardIterImpl.instantiate(TemplateWizardIterImpl.java:253)
at org.openide.loaders.TemplateWizardIteratorWrapper.instantiate(TemplateWizardIteratorWrapper.java:165)
at org.openide.WizardDescriptor.callInstantiateOpen(WizardDescriptor.java:1384)
at org.openide.WizardDescriptor.callInstantiate(WizardDescriptor.java:1341)
at org.openide.WizardDescriptor.access$1600(WizardDescriptor.java:119)
at org.openide.WizardDescriptor$Listener$2$1.run(WizardDescriptor.java:1908)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:561)
[catch] at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:986)

I get this exception trying to report the exception within the IDE. Looks like the URL is invalid.

java.io.IOException: Server returned HTTP response code: 403 for URL:
http://testwww.netbeans.org/nonav/uigestures/error.html
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1170)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:367)
at javax.swing.JEditorPane.getStream(JEditorPane.java:689)
Caused: java.io.IOException: Server returned HTTP response code: 403 for URL:
http://testwww.netbeans.org/nonav/uigestures/error.html
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at sun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1223)
at java.security.AccessController.doPrivileged(Native Method)
at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1217)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:906)
at javax.swing.JEditorPane.getStream(JEditorPane.java:719)
at javax.swing.JEditorPane.setPage(JEditorPane.java:406)
at org.netbeans.modules.uihandler.Installer$SubmitInteractive.assignInternalURL(Installer.java:1289)
at org.netbeans.modules.uihandler.Installer$Submit.doShow(Installer.java:888)
at org.netbeans.modules.uihandler.Installer.doDisplaySummary(Installer.java:475)
at org.netbeans.modules.uihandler.Installer.displaySummary(Installer.java:410)
at org.netbeans.modules.uihandler.UIHandler.run(UIHandler.java:138)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:561)
[catch] at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:986)

Running MySQL as Solaris 10 Service

I found some great examples, but there was always a problem and when I enabled the services it would be in "maintenance" mode. blah.

Anyway, here are the steps that I followed:

1. create a manifest file in /var/svc/manifest/network called mysql.xml The manifest file is what solaris looks at start start/stop/etc on services. In it, you define the methods for starting, stopping, etc.

My manifest file looks like this:

service_bundle type='manifest' name='mysql:mysql'>

service
name='network/mysql'
type='service'
version='1'>
create_default_instance enabled='false' />
single_instance />


dependency name='fs'
grouping='require_all'
restart_on='none'
type='service'>
service_fmri value='svc:/system/filesystem/local' />


dependency name='net'
grouping='require_all'
restart_on='none'
type='service'>
service_fmri value='svc:/network/loopback' />


exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-mysql start'
timeout_seconds='-1'>
method_context working_directory='/apps/mysql'>
method_credential user='mysql' group='mysql' />



exec_method
type='method'
name='stop'
exec=':kill'
timeout_seconds='-1'>


exec_method
type='method'
name='restart'
exec='/lib/svc/method/svc-mysql restart'
timeout_seconds='-1'>







make sure root:sys owns this file and that the permissions are 444
chown root:sys mysql.xml
chmod 444 mysql.xml

The main difference between this script and the other samples is when I would start, I got a "svc.startd could not set context for method: chdir: No such file or directory" error. Apparently, when you start the service under the mysql user/group, it looks for a working directory. On Solaris 10, the mysql user/group already exist with no home dir, so I added the "working_directory='/apps/mysql'" to the start method. This solved everything

2. Next, create the method file (script) which looks remarkably like something you'd put in the rc3.d dir. Here's what mine looks like (modified for my dirs)

#!/usr/bin/sh
#
# William Pool (Puddle) 01/05
# SMF Method file for MySQL
# E-mail: puddle@flipmotion.com
#
# This uses Sun's default MySQL packages
# SUNWmysqlu SUNWmysqlr
#
# Modify accordingly!
#
# NOTE: Make sure DB_DIR is owned BY the mysql user and group and chmod
# 700.
#

#.. /lib/svc/share/smf_include.sh
. /lib/svc/share/smf_include.sh

DB_DIR=/apps/mysql
PIDFILE=${DB_DIR}/`/usr/bin/hostname`.pid

case "$1" in
start)
/usr/sbin/mysqld_safe --user=mysql --datadir=${DB_DIR} --pid-file=${PIDFILE} > /dev/null &
;;
stop)
if [ -f ${PIDFILE} ]; then
/usr/bin/pkill mysqld_safe >/dev/null 2>&1
/usr/bin/kill `cat ${PIDFILE}` > /dev/null 2>&1 && echo -n ' mysqld'
fi
;;
'restart')
stop
while pgrep mysqld > /dev/null
do
sleep 1
done
start
;;
*)
echo ""
echo "Usage: `basename $0` { start | stop | restart }"
echo ""
exit 64
;;
esac

#---EOF

make sure root:bin owns it and the permissions are 555
chown root:bin svc-mysql
chmod 555 svc-mysql

make sure the data dir is owned by mysql user/group
chown -R mysql:mysql

3. now verify that the manifest file is good
svccfg validate /var/svc/manifest/network/mysql.xml

4. import the manifest file
svccf import /var/svc/manifest/network/mysql.xml

5. check the status
svcs mysql

The status should be "disabled", so enable it
svcadm enable mysql

6. check the status again
svcs mysql

It should be "online". If it is "maintenance", then there was a problem starting it. Look in /var/svc/log/network-mysql..... log file and look for errors. You can also do a svcs -x mysql command it will be tell you some info. The log file is where I found the error about the working directory. Of course the error wasn't that nice, but whatever.

Now you have mysql running as a service on Solaris 10. yeah.

Monday, April 21, 2008

Commons-el.jar and glassfish

I know, been a long time. If you place the commons_el.jar file from the jakarta project anywhere in the glassfish lib dirs (glassfish/lib glassfish/domain1/domain/lib) glassfish will start just fine, but weird things happen in the web gui. When you try to deploy an ear,war,jar you will get a:

javax.servlet.ServletException: String index out of range: -1

root cause

java.lang.StringIndexOutOfBoundsException: String index out of range: -1


This doesn't always happen, as sometimes it will work and you get to the deploy page.
Other times, you can be misled like it is deploying, then you get the error.
To avoid this, you will need to bundle the commons_el.jar with the web app and not
make it global. At least that is the only way I've found so far...