Wednesday, August 30, 2006

sending/receiving files with JAX-RPC & Axis 1.3

Use javax.activication.DataHandler
because it can stream: reduces memory usage (don't have to hold file in core), and is faster (can start to send/receive before whole object is created/read).

MIME TYPE: versus MIME Type
MIME is our standard for encoding DataHandler streams. The actual over-the-wire XML is a multipart MIME message, but unlike one might have thought, the SOAP response is one attachment and the attachment is another attachment, rather than the file being an attachment to the SOAP message.

In any event, Axis 1.3 doesn't handle it, invents its own DataHandler type instead. No good for non-Axis clients.

The Transferable interface, spot the difference:
1.new DataHandler(new String("foo"), "text/csv"))
new DataHandler(new String("foo"), "text/plain"))

This is silly. The client code chooses the object to decode the data handler based on its MIME type, not the type of the object that it was created with. These are both Strings and could be de-serialized in exactly the same way. But noooo, a built-in handler exists for text/plain (String), but not for text/csv.

I ended up using
new DataHandler(new org.apache.commons.mail.ByteArrayDataSource(os.toByteArray(), "text/csv"));

even though this doesn't really take advantage of the streaming capability or reduce the memory requirements. Should really make an inputstream out of the outputstream, and stream the stream.

WebLogic listens on one interface

Setting the listen-address attribute it a Bad Idea. Hosts are multi-homed, and if you want to restrict access, don't stick your application on a machine that has an interface to the network you don't want it accessed from.

The WebLogic documents describe very accurately the considerations (except their last point about Windows NT machines is a bit whacked):

Listen Address Considerations

The following table describes important considerations related to setting the listen address value.

If the Listen Address is set to . . .

Then, the following is true . . .

IP address or DNS name

  • Processes must specify the IP address or DNS name to connect to the server instance.

  • Clients that specify localhost will fail to connect.

  • You must update existing processes that use localhost to connect to the server instance.

Note: To resolve a DNS name to an IP address, WebLogic Server must be able to contact an appropriate DNS server or obtain the IP address mapping locally. Therefore, if you specify a DNS name for the listen address, you must either leave a port open long enough for the WebLogic Server instance to connect to a DNS server and cache its mapping or you must specify the IP address mapping in a local file. If you specify an IP address for the listen address and then a client request specifies a DNS name, WebLogic Server will attempt to resolve the DNS name, but if it cannot access DNS name mapping, the request will fail.

localhost

  • Processes must specify localhost to connect to the server instance.

  • Only processes that reside on the machine that hosts the server instance (local processes) will be able to connect to the server instance.

  • Remote (non-local) processes will not be able to connect to the server instance.

Undefined or Blank ("")

  • Processes can specify the IP address, DNS name, or localhost to connect to the server instance.

  • Processes that specify localhost must reside on the machine that hosts the server instance.

  • If the server instance must be accessible as localhost (for instance, if you have administrative scripts that connect to localhost), and must also be accessible by remote processes, leave the listen address blank.

Note: For WebLogic servers running on multi-homed Windows NT machines, you should not leave the listen address value undefined or blank. (Multi-homed machines are configured with multiple IP addresses.) Otherwise, the WebLogic Server reserves and listens on its port for each of the machine IP addresses. This precludes other servers from using the same port on the machine.


I should really stop regurgitating information that is readily available on the web. The original point of this blog was to document findings that were not documented elsewhere.

Back to basics...

datetime becomes date only

This one surfaced again today:

java code says:
object.setEventTime(new Date());

java.util.Date "Allocates a Date object and initializes it so that it represents the time at which it was allocated, measured to the nearest millisecond."

calls to
object.getEventTime();
give a date that has no time: 2006.08.30 00:00:00

Look at DB, contents are: 2006.08.30, type is an Oracle "Date" which is stored to seconds granularity
http://www-db.stanford.edu/~ullman/fcdb/oracle/or-time.html

Culprit: Hibernate mapping. Use:
<property name="eventTime" column="EVENT_TIME" type="timestamp"/>
instead of
<property name="eventTime" column="EVENT_TIME" type="date">

See
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/type/TimestampType.html

loosely coupled software engineering artefacts

What happens?

Your requirements document says one thing, your design documents say another, the code implements the buggy version, your test cases tests the behaviour QA thinks the product ought to have. If you're lucky enough to have use cases you probably aren't lucky enough to have someone update them when the implementor found a more brilliant way of handling some case, and your documentation refers to functionality present in the last version.

Traceability is a start. Tools that provide the links are better. What tools are those?

Tuesday, August 29, 2006

WLST exceptions

Property “Name” of Server with original name “_sample” is invalid. The property value is duplicated

Actually means that when you read the domain, the existing server in config.xml had not been started with AdminServer running (which creates the server directory for the domain).

Similarly, you must give a JDBC System Resource a name explicitly:

jdbcSR=create(dsName, 'JDBCSystemResource')
jdbcSR.setName(dsName)

WLSTException: 'Error occured while performing deploy : Error deploying the applicationError occured while performing deploy : Unexpected Error.Error occured while performing deploy : Could not find Targets that match mdm-weblogic-8089 in null Use dumpStack() to view the full stacktrace Use dumpStack() to view the full stacktrace'

The “null” is the list of available servers to deploy to. Can look at {domain}\config\config.xml and see that new server did get written, but deploy is not viewing that server as an acceptable target to deploy to.

This is because the AdminServer was (already) running. The offline script updated the config.xml, but the already running AdminServer did not pick up the change, so it did not see any target it could deploy to.

Monday, August 28, 2006

getting thread dumps out of WebLogic 9.1

I've solved far too many technical issues that remain undocumented. This blog is my attempt to log useful solutions to issues I have run across, as they happen. Our first entry is not of my authoring.

Here’s some useful information on getting thread dumps out of WebLogic 9.1 (good luck looking for the thread dumps if you ‘kill –QUIT’ on the JVM pid):

Add the following variables to your environment:

1. Set the following environment variables in your shell:

CLASSPATH=${BEA_HOME}/patch_weblogic910/profiles/default/sys_manifest_classpath/weblogic_patch.jar:${BEA_HOME}/jdk150_04/lib/tools.jar:${BEA_HOME}/weblogic91/server/lib/weblogic_sp.jar:${BEA_HOME}/weblogic91/server/lib/weblogic.jar:${BEA_HOME}/weblogic91/server/lib/webservices.jar

PATH=${BEA_HOME}/weblogic91/server/bin:${BEA_HOME}/jdk150_04/jre/bin:${BEA_HOME}/jdk150_04/bin:${PATH}

2. Use the WebLogic WebLogic Scripting Tool (WLST) and connect to the server of interest:

# java weblogic.WLST

Initializing WebLogic Scripting Tool (WLST) ...

Welcome to WebLogic Server Administration Scripting Shell

Type help() for help on available commands

wls:/offline> connect('weblogic', 'weblogic', 't3://sunmdm7:8095')

Connecting to weblogic server instance running at t3://sunmdm7:8095 as username weblogic ...

Successfully connected to Admin Server 'mdm-8095' that belongs to domain 'mdm_mdm-8095'.

Warning: An insecure protocol was used to connect to the server.

To ensure on-the-wire security, the SSL port or Admin port

should be used instead.

3. Use the WLST command threadDump()

Syntax

threadDump([writeToFile], [fileName], [serverName])

Argument

Definition

writeToFile

Optional. Boolean value specifying whether to save the output to a file. This argument defaults to true, indicating that output is saved to a file.

fileName

Optional. Name of the file to which the output is written. The filename can be absolute or relative to the directory where WLST is running. This argument defaults to Thread_Dump_serverName file, where serverName indicates the name of the server. This argument is valid only if writeToFile is set to true.

serverName

Optional. Server name for which the thread dump is requested. This argument defaults to the server to which WLST is connected.

If you are connected to an Administration Server, you can display a thread dump for the Administration Server and any Managed Server that is running in the domain. If you are connected to a Managed Server, you can only display a thread dump for that Managed Server.

wls:/mdm_mdm-8095/serverConfig> threadDump()

Thread dump for the running server: mdm-8095

"[STANDBY] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)'" waiting for lock weblogic.work.ExecuteThread@af71f0 WAITING

java.lang.Object.wait(Native Method)

java.lang.Object.wait(Object.java:474)

weblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:163)

weblogic.work.ExecuteThread.run(ExecuteThread.java:184)

"[STANDBY] ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)'" waiting for lock weblogic.work.ExecuteThread@61806f WAITING

java.lang.Object.wait(Native Method)

java.lang.Object.wait(Object.java:474)

weblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:163)

weblogic.work.ExecuteThread.run(ExecuteThread.java:184)

"[STANDBY] ExecuteThread: '6' for queue: 'weblogic.kernel.Default (self-tuning)'" waiting for lock weblogic.work.ExecuteThread@1373527 WAITING

java.lang.Object.wait(Native Method)

java.lang.Object.wait(Object.java:474)

weblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:163)

weblogic.work.ExecuteThread.run(ExecuteThread.java:184)

"Timer-11" waiting for lock java.util.TaskQueue@182b8fe TIMED_WAITING

java.lang.Object.wait(Native Method)

java.util.TimerThread.mainLoop(Timer.java:509)

java.util.TimerThread.run(Timer.java:462)

"DynamicListenThread[Default]" RUNNABLE native

java.net.PlainSocketImpl.socketAccept(Native Method)

java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)

java.net.ServerSocket.implAccept(ServerSocket.java:450)

java.net.ServerSocket.accept(ServerSocket.java:421)

weblogic.socket.WeblogicServerSocket.accept(WeblogicServerSocket.java:34

. . . .