Monday, January 17, 2011

JMS lifecycle and Searching Filters (Message Selector)

The JMS message lifecycle can be summarized as below with respect to the following two states:

1. A message sent by a JMS producer
* Without any associated transaction:
It is immediately current.
* Within a JTA transaction or transacted JMS session:
It remains pending until the transaction is committed or rolled back. If the transaction is committed, the message becomes available, and if the transaction is rolled back, the message is removed from the destination.
* With a specified TimeToDeliver property:
It remains pending until the TimeToDeliver period expires. This is expected because the purpose of the TimeToDeliver property is to keep the message unavailable to consumers until the specified time period.

2. A message received by a JMS consumer
* Without any associated JTA transaction and in a non-transacted JMS session with an acknowledgement mode of NO_ACKNOWLEDGE or MULTICAST_NO_ACKNOWLEDGE:
It is immediately removed from the destination.
* Within a JTA transaction or transacted JMS session:
It becomes pending until the transaction or session is committed or rolled back. On commit, the message is removed from the destination, and on rollback, the message becomes available again, unless a Redelivery delay is specified, in which case it continues to remain pending until the Redelivery delay.
* Within a non-transacted JMS session with the acknowledgement mode of AUTO_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE, or CLIENT_ACKNOWLEDGE:
It becomes pending until the acknowledgement is received.

Message Selector

When searching for messages in JMS queue. There is an expression language for specifying parameters. This is known as Message Selector

This is the format. This is an example from weblogic that I was using.
JMSMessageId = 'ID:<982769.1294675696539.0>'

What confused me was the ID section. I assumed that was the variable name, so I was changing the format to ID=<> etc.

Note can also do logical operations, see http://download.oracle.com/javaee/6/api/javax/jms/Message.html
e.g.
"JMSType = 'car' AND color = 'blue' AND weight > 2500"

State String
The current state of a message, which could be one of DELAYED, EXPIRED, ORDERED, PAUSED, RECEIVE, REDELIVERY_COUNT_EXCEEDED, SEND, TRANSACTION, or VISIBLE.

Note with Weblogic Unit of Order
We were having problems. A standalone utility program is used to display Jms message see this post . It was having problems displaying some messages. One common theme appeared to be that they were in the Ordered state, as opposed to the visible state. This is due to the message using the Unit of Order to ensure ordered delivery.

Another blog post noted (http://forum.springsource.org/showthread.php?t=69398 )that if the message is in the Receive State, then it may be caused by having 2 Weblogic servers with the same name, where one weblogic server is consuming from a queue serverd from another Weblogic server.

Note also the Xml manipulation required on the JMSMessage







private static final Integer JMS_ALL_STATES = new Integer(0x7fffffff);

public JmsMessage[] getMEssages(){
try {
jmxCon = getJMXConnector(server, username, password);
jmxCon.connect();
MBeanServerConnection con = jmxCon.getMBeanServerConnection();
ObjectName destination = findQueueObjectName(con, jmsModuleName, queueName);
String newCursor = (String) con.invoke(destination, "getMessages", new Object[] { "JMSMessageID='"+msgId+"'", QueuePersistenceJmxImpl.BROWSE_TIMEOUT, JMS_ALL_STATES}, OP_GET_MESSAGES_ALL_SIGNATURE);
result.setCursor(newCursor);
// Should only be one value so no need to sort
//con.invoke(destination, "sort", new Object[] { newCursor, POSITION_UNDEFINED, DEFAULT_ORDERING_ATTRS, DEFAULT_ORDER }, OP_SORT_SIGNATURE);
result.setNumMessages((Long) con.invoke(destination, "getCursorSize", new Object[] { newCursor }, OP_GET_CURSOR_SIZE_SIGNATURE));
Long initialPosition =new Long(0);
Integer pageSize=new Integer(100);
data = (CompositeData[]) con.invoke(destination, "getItems", new Object[] { newCursor, initialPosition, pageSize }, OP_GET_ITEMS_SIGNATURE);
if (data != null) {
JmsMessage[] ret = toJmsMessages(data, new CursorParam(destination, con, newCursor));
if(ret!=null){
if(ret.length>1)
logger.warn("findMessage (by messageId) returned more than one result"+JavaUtil.toString(ret));
return ret[0];
}
return null;
}
} catch (Exception e) {
// throw new RuntimeException("Error while browsing messages",
// e);
// ignore the error and try the next node
logger.error("Error searching for message " + msgId + " on server " + server, e);
}

private static JMXConnector getJMXConnector(Server server, String username, String password) throws IOException {
String fullServerURL = "service:jmx:iiop://" + server.getUrl() + "/jndi/weblogic.management.mbeanservers.runtime";
JMXConnector jmxCon = null;

JMXServiceURL serviceUrl = new JMXServiceURL(fullServerURL);

Hashtable env = new Hashtable();
env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");
env.put(javax.naming.Context.SECURITY_PRINCIPAL, username);
env.put(javax.naming.Context.SECURITY_CREDENTIALS, CryptoUtilWrapper.decrypt(password));

jmxCon = JMXConnectorFactory.newJMXConnector(serviceUrl, env);

return jmxCon;
}

private JmsMessage[] toJmsMessages(CompositeData[] data, CursorParam params) {
XPathUtils xpathUtils = null;
Document d;
JmsMessage[] ret = new JmsMessage[data.length];
int i=0;
MBeanServerConnection con = params.getConnection();
ObjectName destination = params.getDestination();
try {
for (CompositeData resItem : data) {
JmsMessage msg = new JmsMessage();
d = XMLUtils.stringToDocument((String) resItem.get("MessageXMLText"));
xpathUtils = new XPathUtils(d, QueuePersistenceJmxImpl.JMS_MESSAGE_NS_CTX);
xpathUtils.setDocument(d);
msg.setId(xpathUtils.findValue("/mes:WLJMSMessage/mes:Header/mes:JMSMessageID"));
msg.setTimestamp(new Date(Long.parseLong(xpathUtils.findValue("/mes:WLJMSMessage/mes:Header/mes:JMSTimestamp"))));
// Get BOdy
CompositeData body = (CompositeData) con.invoke(destination, "getMessage", new Object[] { params.getCursor(), msg.getId() }, OP_CURSOR_GET_MESSAGE_SIGNATURE);
d = XMLUtils.stringToDocument((String)body.get("MessageXMLText"));
xpathUtils = new XPathUtils(d, QueuePersistenceJmxImpl.JMS_MESSAGE_NS_CTX);
xpathUtils.setDocument(d);
msg.setBody(xpathUtils.findValue("/mes:WLJMSMessage/mes:Body/mes:Text"));
ret[i++]=msg;
}
return ret;
} catch (Exception e) {
throw new RuntimeException("Error while transforming CompositeData to JmsMessage", e);
}
}

Oracle partitioning table

Just a note on how we partitioned a large table (Transaction) in Oracle into monthly partitions/. It involves creating a swap table to store existing data, then placing it into seperate partitions.


Just a note on how we partitioned a large table (Transaction) in Oracle into monthly partitions/.

DROP TABLE TRANSACTION_SWAP
/
ALTER TABLE TRANSACTION DROP CONSTRAINT TRANSACTION_PK
/
DROP INDEX TRANSACTION_IDX1
/
DROP INDEX TRANSACTION_IDX2
/
RENAME TRANSACTION TO TRANSACTION_SWAP
/
REM
REM Now create new version of table, partitioned and with a different primary key
REM

CREATE TABLE TRANSACTION (
"ID" NUMBER NOT NULL ENABLE,
"ORIGINATOR" VARCHAR2(4 BYTE),
"ORIGINATOR_INSTANCE_ID" VARCHAR2(100 BYTE),
"MESSAGE_REF" VARCHAR2(512 BYTE),
"ENTITY_REF" VARCHAR2(512 BYTE),
"TIME" TIMESTAMP(6),
"STATUS" VARCHAR2(5 BYTE),
"JMS_MESSAGE_ID" VARCHAR2(30 BYTE),
"PROJECT_NAME" VARCHAR2(384 BYTE),
"OPERATION" VARCHAR2(150 BYTE),
"INTERFACE" VARCHAR2(20 BYTE))
Partition By Range(Time)
(Partition P_2010_10_31 Values Less Than (To_Timestamp('2010-11-01','YYYY-MM-DD')),
Partition P_2010_11_30 Values Less Than (To_Timestamp('2010-12-01','YYYY-MM-DD')),
Partition P_2010_12_31 Values Less Than (To_Timestamp('2011-01-01','YYYY-MM-DD')),
Partition P_2011_01_31 Values Less Than (To_Timestamp('2011-02-01','YYYY-MM-DD')),
Partition P_High Values Less Than(Maxvalue));
/*
REM
REM Copy over all data before creating indexes - for efficiency reasons
REM Note in some environments, the time can be null on some entries in the table.
REM
REM These rows will be placed in a distinct table
REM

INSERT INTO TRANSACTION
(ID
,ORIGINATOR
,ORIGINATOR_INSTANCE_ID
,MESSAGE_REF
,ENTITY_REF
,TIME
,STATUS
,JMS_MESSAGE_ID
,PROJECT_NAME
,OPERATION
,INTERFACE)
SELECT
ID
,ORIGINATOR
,ORIGINATOR_INSTANCE_ID
,MESSAGE_REF
,ENTITY_REF
,TIME
,STATUS
,JMS_MESSAGE_ID
,PROJECT_NAME
,OPERATION
,INTERFACE
FROM TRANSACTION_SWAP
WHERE TIME IS NOT NULL
/
DROP TABLE TRANSACTION_ARC_NOTIME
/
CREATE TABLE TRANSACTION_ARC_NOTIME
AS
SELECT *
FROM TRANSACTION_SWAP
WHERE TIME IS NULL
/
/*
REM
REM Now create indexes
REM
*/
rem ALTER TABLE TRANSACTION ADD (CONSTRAINT "TRANSACTION_PK" PRIMARY KEY (TIME,ID));
CREATE UNIQUE INDEX TRANSACTION_UID1 ON TRANSACTION(TIME,ID) LOCAL;

ALTER TABLE TRANSACTION ADD (CONSTRAINT TRANSACTION_PK PRIMARY KEY (TIME, ID) USING INDEX TRANSACTION_UID1);

CREATE INDEX TRANSACTION_IDX1 On TRANSACTION (ORIGINATOR_INSTANCE_ID, STATUS) LOCAL;
REM
REM And re-create a grant which is present on production. This may fail elsewhere
REM
GRANT SELECT ON TRANSACTION TO READONLY
/

REM
REM Create the archive table at the same time
REM
CREATE TABLE TRANSACTION_ARC (
"ID" NUMBER NOT NULL ENABLE,
"ORIGINATOR" VARCHAR2(4 BYTE),
"ORIGINATOR_INSTANCE_ID" VARCHAR2(100 BYTE),
"MESSAGE_REF" VARCHAR2(512 BYTE),
"ENTITY_REF" VARCHAR2(512 BYTE),
"TIME" TIMESTAMP(6),
"STATUS" VARCHAR2(5 BYTE),
"JMS_MESSAGE_ID" VARCHAR2(30 BYTE),
"PROJECT_NAME" VARCHAR2(384 BYTE),
"OPERATION" VARCHAR2(150 BYTE),
"INTERFACE" VARCHAR2(20 BYTE))
Partition By Range(Time)
(Partition P_2010_10_31 Values Less Than (To_Timestamp('2010-11-01','YYYY-MM-DD')),
Partition P_2010_11_30 Values Less Than (To_Timestamp('2010-12-01','YYYY-MM-DD')),
Partition P_2010_12_31 Values Less Than (To_Timestamp('2011-01-01','YYYY-MM-DD')),
Partition P_2011_01_31 Values Less Than (To_Timestamp('2011-02-01','YYYY-MM-DD')),
Partition P_High Values Less Than(Maxvalue));

REM
REM recreate any package body with a new version which defaults the time in the table,
REM to make sure there is always a value there
REM
@TrackingProcedureBody

PROMPT *** OPERATION COMPLETE ***
PROMPT
PROMPT *** WHEN HAPPY WITH RESULTS, TRUNCATE THE TABLE TRANSACTION_SWAP

Thursday, December 23, 2010

Web Security (and Weblogic)

Web Security (and Weblogic)

When defining security roles for a web app.

1/ In your web.xml
Declare how and where the authentication should occur.

<login-config>
<auth-method>FORM</auth-method>
<realm-name>myrealm</realm-name>
<form-login-config>
<form-login-page>/action/auth/login</form-login-page>
<form-error-page>/jsp/security/login-error.jsp</form-error-page>
</form-login-config>
</login-config>

2/ In your web.xml
Declare your authorization roles

<security-role>
<role-name>MessagePoster</role-name>
</security-role>
<security-role>
<role-name>MessageViewer</role-name>
</security-role>
<security-role>
<role-name>QueuePauser</role-name>
</security-role>
<security-role>
<role-name>ServiceEnabler</role-name>
</security-role>
<security-role>
<role-name>LogLevelManipulator</role-name>
</security-role>
<security-role>
<role-name>Resequencer</role-name>
</security-role>
<security-role>
<role-name>MessageRetrier</role-name>
</security-role>
<security-role>
<role-name>ErrorReportCloser</role-name>
</security-role>
<security-role>
<role-name>SystemSwitcher</role-name>
</security-role>
<security-role>
<role-name>OptionsSetter</role-name>
</security-role>


For Weblogic.
In the security realm different security models are possible. This is set from the
Security Model Default: setting
Options are `DD (Deployment Discriptor), Custom Roles, Custom Roles and Policies, Advanced..
When deploying you can set mode
Security
What security model do you want to use with this application?
DD Only: Use only roles and policies that are defined in the deployment descriptors. Custom Roles: Use roles that are defined in the Administration Console; use policies that are defined in the deployment descriptor. Custom Roles and Policies: Use only roles and policies that are defined in the Administration Console. Advanced: Use a custom model that you have configured on the realm's configuration page.

In your Weblogic.xml you can perform the role/ group/ user mappings
(one entry per role)

<wls:security-role-assignment>
<wls:role-name>ErrorReportCloser</wls:role-name>
<wls:principal-name>WATSupportGroup</wls:principal-name>
</wls:security-role-assignment>



Or you can delegate the mapping back to the Weblogic admin console (better).. See my earlier post on defining Weblogic Roles
(one entry per role)

<wls:security-role-assignment>
<wls:role-name>MessageViewer</wls:role-name>
<externally-defined/>
</wls:security-role-assignment>

Oracke Soa Suite

(work in progress) I will fill this in as I progress


Instructions for Soa Suite

Best place to start is a tutorial

http://download.oracle.com/docs/cd/E12839_01/integration.1111/e10275/intro.htm

This tells you what you need to download

· Task 1: Install Oracle JDeveloper Studio

· Task 2: Install the Fusion Order Demo Application

· Task 3: Install Oracle SOA Suite

· Task 4: Create a Connection to an Oracle WebLogic Server

Task1/

Download from

http://www.oracle.com/technetwork/developer-tools/jdev/overview/index.html

Then you need to download Extensions from (http://www.oracle.com/ocom/groups/public/@otn/documents/webcontent/156082.xml)

Oracle SOA Composite Editor

Pretty print Xml

If you want to format your Xml..theres lots of ways

This url uses Xerces

http://stackoverflow.com/questions/139076/how-to-pretty-print-xml-from-java

(it also uses jtidy which I could not get to work with pure XML.. (kept adding HTML tags).

If you want to avoid xerces and just stick to standard java then you need to use the Transformer.

Just to note that top rated answer requires the use of xerces.

If you don't want to add this dependency then you can simply use the standard jdk libraries.

(Note if an error occurs this will return the original text)

package ie.bge.middleware.tools;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.xml.sax.InputSource;

public class Test {
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.formatXml("text D"));
}

public String formatXml(String xml){
try{
Transformer serializer= SAXTransformerFactory.newInstance().newTransformer();
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
Source xmlSource=new SAXSource(new InputSource(new ByteArrayInputStream(xml.getBytes())));
StreamResult res = new StreamResult(new ByteArrayOutputStream());
serializer.transform(xmlSource, res);
return new String(((ByteArrayOutputStream)res.getOutputStream()).toByteArray());
}catch(Exception e){
//TODO log error
return xml;
}
}

}

Weblogic DB issue

Found on Weblogic 11g

I have a few DataSources defined. Some of which are on the same DB server just different SID’s (Oracle DB’s).

One of the DB instances was removed. Then all instances of DB’s on that server failed to start, (Even though the other DB was still running. When I untargeted the problem server and re-started, then the 2nd DB started fine.)

Debugging Log4j issues

Log4j

Handy for log4j issues

Set the following switch when you start the JVM to see what log4j is upto.

-Dlog4j.debug

Check for log4j output. This will tell where it is loading its configuration from.

Note be careful with multiple webapps having multiple log4j.xml or log4j.properties. These can override your settings.

This next section is not true.. Its was actually caused by log4j delayed write to log file.. However I'm still including it because the detection techniques are useful.


(My actual problem was incredibly simple, and I shoudl have checked this first, but I made an assumption, and as we all know assumption is the mother of all F£$k ups.. The tool I was working on was using Simple Logging Facade for Java (SLF4J).. The developpers had simply included the slf4j-jdk.jar fil in the classpath instead of the slf4j-log4j.jar. Fixing my problem was simply a case of replacing the wrong jar. USing the log4j debugger was useful however in pinpointing what configuration files were ben picked up.




Monday, November 08, 2010

Weblogic’s many jar files...

Heres some problems I encountered trying to run some applications using Weblogic.

1/

java.lang.NoClassDefFoundError: weblogic/kernel/KernelStatus

I was banging my head against a wall with a

Exception in thread "Main Thread" java.lang.NoClassDefFoundError: weblogic/kernel/KernelStatus

While trying to write a simple standalone program to connect to a Weblogic instance via JNDI, and manipulate some JMX values. The solution was provided via this posting

http://blogs.oracle.com/jamesbayer/2008/08/workshop_for_weblogic_103_jee.html

To actually run the Main method class in Workshop, I right click on the class in the Project Explorer and select Run As->Open Run Dialog. In the classpath tab, be sure to add the wlclient.jar file located here \wlserver_10.3\server\lib to the User Entries section and remove the WebLogic System Libraries from the Bootstrap Entries section. If you forget to remove the WebLogic System Libraries, you will get a stack like this: Exception in thread "Main Thread" java.lang.NoClassDefFoundError: weblogic/kernel/KernelStatus

There is also a wlFullCLient.jar file that may be useful in other scenarios

2/

Just when you thought it was safe however, you get the following

ClassCastException: weblogic.jdbc.common.internal.ConnectionEnv

Here http://forums.oracle.com/forums/thread.jspa?threadID=1048084&tstart=118

the advice is as follows

I would suggest you to remove the wlClient.jar from the classpath.
Also make sure that there are no other jar files related to weblogic in the classpath.
Add weblogic.jar in the classpath and make sure that this weblogic.jar is the same jar that is in the weblogic server classpath.

This happens because of the difference in the jar used by the Client JVM and server JVM.

In fairness this does fix the problem.

Depending on what your client does, it may be necessary to include the Weblogic.jar (if its doing some funky stuff), to ensure it has all the correct classes. Be careful from oracle workshop (eclipse) however of attached bootstrap class loaders.


3/ Missing servlet jars/ JEE standard jars.

You may run into problems with missing J2EE standard jars. I for example was getting errors about HttpServletRequest etc from the Servlet Api. In previous versions of weblogic, the weblogic.jar file would contian all of these, but since 10.3.x they have stopped including it.


When looking up missing jars, try the following, check the following...

$WL_HOME/server/lib/api.jar

In there the MANIFEST.MF contains a list of jars that include the usual J2EE jars etc. These have been removed from Weblogic.jar so may be needed.


Finally... I've mentioned this before but it is important when working with Ears and Wars on weblogic.


If you start seeing exceptions such as

java.lang.ClassCastException: weblogic.xml.jaxp.RegistrySAXParserFactory cannot be cast to javax.xml.parsers.SAXParserFactory


deep in the Weblogic code, you have more than likely run into a dreaded classpath incompatibility.


To avoid this use the following in your weblogic.xml

<wls:container-descriptor>

<wls:prefer-web-inf-classes>true</wls:prefer-web-inf-classes>

</wls:container-descriptor>

This will then result in a lot of ClassNotFoudn exceptions which may mean a hunt through your libs to add missing files

For instance heres the issues I ran into

java.lang.ClassCastException: weblogic.xml.jaxp.RegistrySAXParserFactory cannot be cast to javax.xml.parsers.SAXParserFactory

This means that we need a newer version of the SAXParserFactory than provided by Weblogic (we are using Bea jdk 1.6, so thast is picking up the lastest version of javax.xml.parsers.SAXParserFactory, but then weblogic.xml.jaxp.RegistrySAXParserFactory is been instantiated and this refers to an older version of SAXParserFactory)

The problem in my case was un-resolvable. The incompatible jar was needed to perform translation of a binary Xml format, but unfortunately it also included a newer version of xmlparser. This newer version then started causing problems with taglibs in Jsps. Our fix was to move of deployment from 10.3.1 to 10.3.3

4/ java.lang.NoClassDefFoundError: weblogic/utils/NestedException

After trawling the web there are a lot of references to wlFullClient.jar

This refers to rolling your own version of all wl client jars.

What might be simpler is to simply add the required jars.

This is the list of client jars.

webserviceclient+ssl.jar

webserviceclient.jar

wl-j2ee-client.jar

wlclient.jar

wljmsclient.jar

wljmxclient.jar

wlnmclient.jar

wlsafclient.jar

wlstestclient.ear

wseeclient.jar

For NestedException the required jar is wljmsclient.jar

Thursday, November 04, 2010

Tomcat deploy arbitrary dir

To deploy a webapp from a directory not in the appBase (the webapps directory by default) of Tomcat /Catalina, then its simple.

At its most simple you simply create a file in the $CATALINA_BASE/conf/[enginename]/[hostname] directory.

The name of the file is the webapp Context name you want.

The contents must include the docBase attribute. This points the location of the webapp.

This is very useful for development, so every change can be immediately realised on the webapp without restarting, or undeploying/ deploying (which is necessary if you deploy it using Tomcats manager, since it copies the apps into the webapp directory.)

e.g. save SpringSchedule.xml in the $CATALINA_BASE/conf/[enginename]/[hostname]


<Context docBase="F:/eclipse_workspace/SpringSchedule/www">

</Context>

Note: If you add properties files, or update the web.xml you will need to reload the webapp from the tomcat manager console.

Ref

http://tomcat.apache.org/tomcat-7.0-doc/config/context.html

Eclipse java command line

1/ You can generate the java command used by eclipse to run/ or debug an application, with all included classpaths etc. This can be useful if you want to later script the execution of the application.

It is visible by debugging the application (debug as application). From the debug perspective, right click on the debug view, to get the context menu. Select properties. The command line is visible and can be copied.


2/Also, its possible to run eclipse itself from the command line in headless mode.


eclipsec.exe -noSplash -data "D:\Source\MyProject\workspace" -application org.eclipse.jdt.apt.core.aptBuild

It uses the jdt apt plugin to build your workspace automatically. This is also known as a 'Headless Build'. If you're not using a win32 exe, try this:

java -cp startup.jar -noSplash -data "D:\Source\MyProject\workspace" -application org.eclipse.jdt.apt.core.aptBuild

Saturday, October 30, 2010

Quartz

I’ve been setting up a Quartz scheduler recently. We wanted it to store the jobs in a Database. Quartz helpfully comes with a set of sql scripts for virtually all DB’s to create and manage all jobs, triggers, schedules etc via a transaction and cluster aware scheduler, so there is no need to think about that aspect of it. The scripts are all stored in the Quartz distribution under docs/dbTables folder.

Once the tables are all set up you can use the example application provided with Quartz to test out the DB persistence (Example 13). Configure it to point to your database by updating the instance1.properties file

We then wanted to Spring-ify it. This was straightforward

e.g.

public class RunSchedule {

static Logger _log = LoggerFactory.getLogger(RunSchedule.class);

public static void main(String[] args) throws Exception {

BeanFactory springContext = new ClassPathXmlApplicationContext("Spring-Quartz.xml");

cleanUp((Scheduler)springContext.getBean("plannedDowntimeScheduler"));

}

public static void cleanUp(Scheduler inScheduler) throws Exception {

_log.warn("***** Deleting existing jobs/triggers *****");

// unschedule jobs

String[] groups = inScheduler.getTriggerGroupNames();

for (int i = 0; i <>

String[] names = inScheduler.getTriggerNames(groups[i]);

for (int j = 0; j <>

inScheduler.unscheduleJob(names[j], groups[i]);

}

}

// delete jobs

groups = inScheduler.getJobGroupNames();

for (int i = 0; i <>

String[] names = inScheduler.getJobNames(groups[i]);

for (int j = 0; j <>

inScheduler.deleteJob(names[j], groups[i]);

}

}

}

}

And

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:jee="http://www.springframework.org/schema/jee"

xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:jms="http://www.springframework.org/schema/jms"xmlns:util="http://www.springframework.org/schema/util"

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-2.5.xsd

http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="runMeTask" class="ie.bge.middleware.RunMeTask" />

<bean name="runMeJob"

class="org.springframework.scheduling.quartz.JobDetailBean">

<property name="jobClass" value="ie.bge.middleware.RunMeJob" />

<property name="jobDataAsMap">

<map>

<entry key="runMeTask" value-ref="runMeTask" />

<map>

<property>

<bean>

<bean id="simpleTrigger"

class="org.springframework.scheduling.quartz.SimpleTriggerBean">

<property name="jobDetail" ref="runMeJob" />

<property name="repeatInterval" value="5000" />

<property name="startDelay" value="1000" />

<bean>

<bean id="cronTrigger"

class="org.springframework.scheduling.quartz.CronTriggerBean">

<property name="jobDetail" ref="runMeJob" />

<property name="cronExpression" value="0/5 * * * * ?" />

<bean>

<bean name="plannedDowntimeScheduler"

class="org.springframework.scheduling.quartz.SchedulerFactoryBean" init-method=”start”>

<property name="quartzProperties">

<util:properties location="/quartz.properties" />

property>

<property name="applicationContextSchedulerContextKey"

value="applicationContext" />

<property name="waitForJobsToCompleteOnShutdown" value="true" />

<bean>

<beans>

All works as expected.

N.B. Note the init-method attribute for SchedulerFactoryBean. This is to automate the starting of the scheduler after it is instantiated. It is better than having a code based startup, (which would implement the Spring InitializingBean)

When we integrated it into our main application however we started having issues.

Code:

Caused by: org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: ORA-00942: table or view does not exist

[See nested exception: java.sql.SQLException: ORA-00942: table or view does not exist

]]

The problem was due to autowiring. We had a datasource defined for a different purpose that was getting autowired into our SchedulerFactoryBean. (We were defining the datasource via the quartz.properties, and not injecting the datasource).


Manually wiring the correct dataSource fixed the problem. (or turninng off autowiring should also work as suggested by jrsisson)

http://forum.springsource.org/showthread.php?p=326612&posted=1#post326612

Spring

BeanFactory or ApplicationContext?


Taken from Spring website

Users are sometimes unsure whether a BeanFactory or an ApplicationContext is best suited for use in a particular situation. A BeanFactory pretty much just instantiates and configures beans. AnApplicationContext also does that, and it provides the supporting infrastructure to enable lots of enterprise-specific features such as transactions and AOP.

In short, favor the use of an ApplicationContext.

(For the specific details behind this recommendation, see this section.)

CSS Javascript quickie

Center (Centre) a div

Its easy, but its not necessarily obvious. To centre a div you need to set the width, and the margin-left and right to auto,

e.g.

#div{

width: 500px; margin-left: auto ; margin-right: auto ;

}

To center text within a div use.

text-align: center ;

http://www.thesitewizard.com/css/center-div-block.shtml

Javascript

Useful links explaining with nice and simple explanations of objects in javascript (I wonder how I never “got it” before considering how simply its described here)

http://javascriptkit.com/javatutors/object3.shtml

Also the prototype modifier. Basically it allows properties, and methods to be added to objects. Effectively making javascript OO, instead of purely functional.

http://www.javascriptkit.com/javatutors/proto4.shtml

Saturday, October 16, 2010

Recording a desktop demo video/ viewlet


Just a quick note about recording a desktop demo (viewlet). These are very handy for demo’s on using software etc. They allow you to record the screen activity, while adding voice over commentary, and popup overlays.

One of the best freeware recorders is Wink

http://www.debugmode.com/wink/

Also some image compression stuff on here.

Svn identity/ login

If subversion in eclipse is pestering you for login credentials every few seconds, then your credentials may have got corrupted.

You can reset the stored credentials by deleting the auth directory.

This is usually located at

Unix (linux/ Osx)
~/.subversion/auth

Windows:

USER_HOME/Application Data/Subversion/auth

Taken from http://osdir.com/ml/version-control.subversion.subclipse.user/2006-08/msg00029.html


.keyring file only used when JavaSVN adapter is selected.

Also, your repository may allow anonymous read access, so browsing and
update operation doesn't require you to log in. Supclipse only prompts for
credentials when credentials are requested by Subversion server.

Weblogic JMS

Link for looking up all jms queues using jmx

http://weblogic-zone.blogspot.com/2010/01/jms-resources-using-jmx.html

You can use a JMX program, WLST, JConsole, or the console.

See the documentation on using WLST

http://download.oracle.com/docs/cd/E15523_01/web.1111/e13715/toc.htm

See the documentation on writing JMX clients

http://download.oracle.com/docs/cd/E15523_01/web.1111/e13729/toc.htm

See the MBean reference documentation

http://download.oracle.com/docs/cd/E15523_01/apirefs.1111/e13951/core/index.html

The JMX distributed queue mbeans have type = weblogic.j2ee.descriptor.wl.DistributedQueueBean

You can either walk down the hierarchy starting at the Domain MBean and into the JMSSystemResource MBean or you can query for specific MBean types.


JMS and OSB

One issue that I’ve seen on a client site.

An OSB proxy is set up to consume from a JMS queue. Data is injected into the queue but the Proxy does not consume it.

(Only seen when custom dispatch policies were used)

This is a weblogic bug. The workaround is to go through the configuration of the proxy, and assign it a different Dispatch Policy. This would enable consuming of the queue. Then you can simply rollback the change in OSB, and consuming will continue.


JMS Unit of Order

http://download.oracle.com/docs/cd/E12840_01/wls/docs103/jms/uoo.html

Message Unit-of-Order is a WebLogic Server value-added feature that enables a stand-alone message producer, or a group of producers acting as one, to group messages into a single unit with respect to the processing order.
Note that it appears to cause problems with the JMS Api's for viewing message payloads.

Editied Note.. We found an MBean API for discovering these. It involves using the MBean operation getMessages (specifying a flag). I will blog about it later

Weblogic Roles

Just a quick reminder for myself. This is easy but on initial inspection it seems like there is something missing. In fact it is easy, but appearance can be confusing.

The high level is. You are using weblogic server to host your apps. You want some security policies for your apps. It therefore makes sence to use the weblogic security realm, and its roles, groups, users and policies to manage the entity.

-. Create new Role(s).

From weblogic console, goto Security Realm, Select realm, select Roles and Policies.

Now expand the global Roles, and click on the Roles link. This will allow you to create custom roles.

-. Create/ edit Groups to include new Roles

Assign users to groups

JSTL snippets

Simple when you know how. Frustrating and time consuming when you don’t
If/ else
Because of the xml format we can’t have a
<c:if test=”${actionBean.test}”>
</c:if>
<c:else>
</c:else>
Instead we have to use choose, when and otherwise.
e.g.
<c:choose>
<c:when test="${actionBean.test}”>
</c:when>
<c:otherwise>
</c:otherwise>
</c:choose>

Looping through lists
Realated to above, I was trying to test if a list was populated.
First attempt was
<c:choose>
<c:when test="${actionBean.result.size>0}">
javax.el.PropertyNotFoundException: The class 'java.util.Collections$Synchronize
dCollection' does not have the property 'size'.
at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:547)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:249)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:143)
at com.sun.el.parser.AstValue.getValue(AstValue.java:118)
at com.sun.el.parser.AstGreaterThan.getValue(AstGreaterThan.java:41)
Truncated. see log file for complete stacktrace
Solution is to use Not Empty
<c:when test="${not empty actionBean.result}">

Monday, October 11, 2010

Weblogic (Oracle) JMX

Example code for interacting with Weblogic Server/ OSB , via JMX.

http://blogs.oracle.com/jeffdavies/ProxyServiceUtilJMX.html

Tuesday, August 17, 2010

Getting version of Oracle WebLogic Portal Server

How to determine the exact version of Oracle Portal Server you are using?

You can determine the Portal version with the following query executed in the Portal MR database as a dba user.
Substitute your schema name where you see


select VERSION from
.wwc_version$;