Wednesday, October 19, 2011

Can not remote desktop - no Terminal Server License Servers available

Keywords:
remote desktop console disconnected terminal server license "no Terminal Server License Servers available"

Problem:
On trying to remote desktop to a machine get the popup message:
The remote session was disconnected because there are no Terminal Server License Servers available to provide a license.
Please contact the server administrator.

A quick search suggests:
  1. Restarting the "Terminal Server" can help
    but lets say (hypothetically) that we don't know where this is and/or how to do it.
  2. Installing a Microsoft 'Hotfix'
    but after accepting the terms; filling in the hotfix request form; getting the email with the link to the hotfix executable - we (at the moment anyway) get a 500 Internal Server Error on the MS hotfix download site.

If you just need to access the machine is there another option?

Solution:
You can remote desktop to the "console" - this is effectively like 'physically' logging into the machine rather than a remote session.
mstsc /console

or on Vista / Windows Server 2008:
mstsc /admin

mstsc allows specifying the machine on the command line itself to avoid the computer selection popup (use /help option for other options):
mstsc /v:remote-server /admin

Be aware that - if someone else had a console session on this machine they'd be kicked off. If you're logged on in console/admin mode anyone with access to the terminal - if it's plugged into a monitor for example - will see what you're doing.

Wednesday, September 21, 2011

Get the generated source code for JSPs in WebLogic

Keywords:
generated JSP java class source Oracle WebLogic line numbers

Problem:
Given a stack trace such as the following:
java.lang.NullPointerException
 at jsp_servlet._web_45_inf._jsp._demo.__example._jspService(__example.java:117)
 at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
 at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
 at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
 at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
 at weblogic.servlet.internal.ServletStubImpl.onAddToMapException(ServletStubImpl.java:416)
 at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:326)
 at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:183)
 at weblogic.servlet.internal.RequestDispatcherImpl.invokeServlet(RequestDispatcherImpl.java:526)
 at weblogic.servlet.internal.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:253)

It won't always be obvious what the issue in example.jsp corresponds to in the generated __example.java. How do you get at the generated source code for the JSPs?

Solution:
The solution involves configuring a [app_name]/WEB-INF/weblogic.xml file in your web-app. The documentation is in the WebLogic 10.3 docs - see weblogic.xml Deployment Descriptor Elements but keep in mind the file will be validated against the schema so the elements must be in the correct spot.

Below is an example - defining the jsp-descriptor with keepgenerated and working-dir elements:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app
    xmlns="http://www.bea.com/ns/weblogic/90"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd">
    <jsp-descriptor>
        <keepgenerated>true</keepgenerated>
        <working-dir>c:/my_folder/temp</working-dir>
    </jsp-descriptor>
    <container-descriptor>
        <prefer-web-inf-classes>true</prefer-web-inf-classes>
    </container-descriptor>
</weblogic-web-app>

Thursday, August 25, 2011

Beware: an empty string in Oracle is NULL

Keywords:
empty string '' CLOB varchar varchar2 text null isnull nvl NullPointerException JDBC

Problem:
There's code that is (seemingly) working with writing strings to CLOB columns and with the code from a previous post (Convert Oracle CLOBs to String) the reading of strings from the CLOB columns is working ok too ... until we get to empty strings - could it be that something is converting '' to NULL?

Here's a test case:
create table test_clobtext(

id number
, text clob
);
insert into test_clobtext values (1, 'some clob text');
insert into test_clobtext values (2, '');
select id, text from test_clobtext;

You get:
        ID TEXT

---------- ----------------
1 some clob text
2

What's the value in the 2nd row? You can use the NVL() (which is just like ISNULL()):

select id, NVL(text,'IT IS A NULL') as text from test_clobtext;

Shock, horror, this is the result:
        ID TEXT

---------- ----------------
1 some clob text
2 IT IS A NULL

... and because I'm still in disbelief:

select id, NVL(text,'IT IS A NULL') as text from test_clobtext
where text IS NULL;

This is definitely the result:
        ID TEXT

---------- ----------------
2 IT IS A NULL


So it's something to do with CLOBs? No, changing the text column to a varchar or varchar2 and you will get the same result! Is this right?

Solution:
This is apparently a well known issue (that I've only just stumbled across). A discussion is on stackoverflow: Why does Oracle treat empty string as NULL which links to more details information on ask-tom: Strings of Zero Length Not Equivalent To NULL.

It would seem that there are some scenarios where it won't be NULL but I can't reproduce this - changing the test case to have text as a char(1) still gives me NULL for the column.

The bottom line is if you're working with strings/text in a Oracle database you must expect and handle NULL values coming back - there will be no way to distinguish between whether what was originally stored was actually a NULL or an empty string ('').

Notes:
If you're dealing with CLOB columns you do have the option of storing (vendor specific) empty_clob() where you do want to distinguish between the cell being set to empty from it not being set at all (ie NULL). This post "An Empty Clob is not NULL" is a good discussion.



Monday, June 20, 2011

Convert Oracle CLOBs to String in JSTL and tag file

Keywords:
java.lang.ClassCastException oracle.sql.CLOB cast java.lang.String CLOB jstl tag requestScope requestContext pageContext jspContext

Problem:
It's annoying when SQL that works for other vendors fails for a specific one ... in this case a "text" column in a schema is defined as "clob" in the corresponding oracle schema. Problem is that this is not necessarily equivalent - especially when querying the data. This is even more complex when the SQL is in JSTL. So with the JSTL code (where textValue is a CLOB):

<sql:query var="data" >
select id,
textValue
from example
where id=?
<sql:param value="${param['id']}"/>
</sql:query>
<c:forEach items="${data.rows}" var="row">
<c:out value="${row.textValue}"/><br/>
</c:forEach>


You get the result:

oracle.sql.CLOB@e645e0
oracle.sql.CLOB@1f58913
oracle.sql.CLOB@fa6b82
...


Or if you try to use the textValue in something expecting a string, you'll get:
java.lang.ClassCastException: oracle.sql.CLOB cannot be cast to java.lang.String


How do you turn a Clob to a String without filling the JSP with vendor-specific code (leaving out the argument for not having SQL in the JSP for now)?

Solution:
Great discussion of this very issue is on the OTN Forum: JSP and CLOB. It essentially involves putting the Clob to String code in a scriptlet. To keep this vendor-neutral and take some of the "ugliness" out of the JSP I'd opt for putting this code in a tag file and stick to referencing just the java.sql.* interfaces.

Step 1: create a /WEB-INF/tags/to-string.tag tag file


(Or in a subfolder - the path must start with /WEB-INF/tags/.. if using the tagdir approach).

This takes the CLOB (or other) column value and sets it back in the request context as a String.

<%--
Can turn a CLOB to String for Oracle schema
--%>
<%@ tag body-content="empty" %>
<%@ attribute name="var" required="true" type="java.lang.String" %>
<%@ attribute name="value" required="true" type="java.lang.Object" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ tag import="java.sql.*" %>
<%@ tag import="javax.servlet.jsp.*" %>
<%
String strValue = null;
if (value == null) {
strValue = ""; // NB: oracle empty string is null
} else if (value instanceof Clob) {
Clob clob = (Clob)value;
long size = clob.length();
strValue = clob.getSubString(1, (int)size);
} else {
strValue = value.toString();
}
jspContext.setAttribute(var, strValue, PageContext.REQUEST_SCOPE);
%>


In this tag file, var is the name of the variable to define in the requestScope. Note how this is done by referencing the jspContext variable.

Step 2: Use the to-string tag for your text, clob or Other columns


This involves first defining the new taglib (putting all .tag files in tagdir in the JSP scope using the "eg" prefix in this example) and then simply using the eg:to-string tag to put the string-value of the column in a "local" requestScope variable.

<%@ taglib prefix="eg" tagdir="/WEB-INF/tags" %>
<sql:query var="data" >
select id,
textValue
from example
where id=?
<sql:param value="${param['id']}"/>
</sql:query>
<c:forEach items="${data.rows}" var="row">
<eg:to-string var="textValue" value="${row.textValue}"/>
<c:out value="${textValue}"/><br/>
</c:forEach>


Tuesday, April 05, 2011

IIS7 hiding tomcat webapp error pages

Keywords:
IIS IIS7 custom error pages hiding masking tomcat 500 webapp error page jk connector AJP

Problem:
With tomcat integrated into IIS7 using the jk connector error pages from the webapp that have the http-response status set (eg to 500) get "replaced" with a generic IIS custom error page:
500 - Internal server error. 
There is a problem with the resource you are looking for, and it cannot be displayed


A quick web-search reveals it's a common issue for ASP.NET developers and the solution is simply to make changes to the ASP.NET application config or in code setting a special HttpResponse.TrySkipIisCustomErrors property(!) ... but what are the options for when the pages are being supplied by an ISAPI redirector/plugin (i.e. the JK connector in this case)?

Solution:
Based on the detailed notes on the IIS Blog (What to expect from IIS7 custom error module) the minimal steps required seem to be the following:

Step 1: create a Web.config file in the root folder of the Web Site


This is the Web Site where you've configured the "jakarta" virtual directory. If it's "Default Web Site" this may be C:\inetpub\wwwroot but check the properties to be sure (Right click Web Site > Manage Web Site > Advanced Settings ... and note the setting for 'Physical Path').

Step 2: add configuration to the Web.config file


<configuration>
   <system.webServer>
      <httpErrors errorMode="Detailed" existingResponse="Auto" />
   </system.webServer>
</configuration>


Step 3: restart the web site


Eg Right click Web Site > Manage Web Site > Restart


Be sure to to test this on the local machine (where IIS7 is installed) and from another machine in the network as IIS may give different error-page behaviour for local and 'remote' requests.

Tuesday, March 08, 2011

NTLM from an Axis (SOAP) service client - in 3 steps

Keywords:
NTLM authentication Negotiate Apache axis SOAP IIS Windows Integrated Authentication CommonsHTTPSender NTCredentials

Problem:
Authenticating a service request with BASIC authentication is (relatively) straightforward:

import java.net.URL;
import org.apache.axis.client.Stub;
import com.example.service.Example;
import com.example.service.ExampleServiceLocator;
import com.example.service.ExampleRequest;
import com.example.service.ExampleResponse;

// get access to the web service
ExampleServiceLocator locator = new ExampleServiceLocator();
String serviceURL = "http://server/application/services/example";
Example example = locator.getexample(new URL(serviceURL));
// set credentials
((Stub)example).setUsername("myusername");
((Stub)example).setPassword("mypassword");


// setup request
ExampleRequest request = new ExampleRequest();
request.setProperty("SomeProperty");

ExampleResponse response = example.example(request);


What if the (SOAP) service being called required NTLM authentication (e.g. the service is running in IIS and security is set as "Windows Integrated Authentication")?

Solution:
The following three steps are assuming Axis 1.x. The Apache Axis Client Tips and Tricks is a good reference, in particular for step 2, but also for other "tips".

Step 1: Add Apache commons-httpclient (3.1) and commons-codec libraries


Note you must add the commons httpclient jar file and not the (latest/refactored) apache httpclient to the project - or you will get ClassNotFound exceptions.

Step 2: Define custom client-config with CommonsHTTPSender


It's mentioned in the "Tips and Tricks" article mentioned above, but you can either: (a) define a custom client-config.wsdd file in the classpath before axis.jar; (b) edit the generated ...ServiceLocator.java generated class and make it override getEngine...; or (c) at runtime simply feed the customised config XML to your ...ServiceLocator object.

I prefer the latter - for example, define a static method with the config XML as a string:

protected static org.apache.axis.EngineConfiguration getEngineConfiguration() {
java.lang.StringBuffer sb = new java.lang.StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
sb.append("<deployment name=\"defaultClientConfig\"\r\n");
sb.append("xmlns=\"http://xml.apache.org/axis/wsdd/\"\r\n");
sb.append("xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\">\r\n");
// sb.append("<transport name=\"http\" pivot=\"java:org.apache.axis.transport.http.HTTPSender\" />\r\n");
sb.append("<transport name=\"http\" pivot=\"java:org.apache.axis.transport.http.CommonsHTTPSender\" />\r\n");
sb.append("<transport name=\"local\" pivot=\"java:org.apache.axis.transport.local.LocalSender\" />\r\n");
sb.append("<transport name=\"java\" pivot=\"java:org.apache.axis.transport.java.JavaSender\" />\r\n");
sb.append("</deployment>\r\n");
org.apache.axis.configuration.XMLStringProvider config =
new org.apache.axis.configuration.XMLStringProvider(sb.toString());
return config;
}


Then the call to the locator would become:

// get access to the web service
ExampleServiceLocator locator = new ExampleServiceLocator(getEngineConfiguration());


Step 3: Set the username as DOMAIN\username


Set the username as you did with BASIC authentication but you must ensure is set in the form DOMAIN\username (keeping in mind that if expressing this in java code - as a string - or as a property value in a properties file this would be set as "DOMAIN\\username" - \\ being the escape sequence for \):

((Stub)example).setUsername("MY_NT_DOMAIN\\myusername");
((Stub)example).setPassword("mypassword");


With the above 3 steps covered you're using NTLM.

Notes:
Avoid setting the system property -Djava.ext.dirs as the above relies on the sunjce_provider.jar library which is in JRE_HOME\lib\ext by default. Ext-path problems may give you errors such as:
"Cannot find any provider supporting DES/ECB/NoPadding"


Failing to set the username in the form DOMAIN\username will result in the error:
org.apache.commons.httpclient.auth.InvalidCredentialsException: 

Credentials cannot be used for NTLM authentication:
org.apache.commons.httpclient.UsernamePasswordCredentials
at org.apache.commons.httpclient.auth.NTLMScheme.authenticate(NTLMScheme.java:332)
at org.apache.commons.httpclient.HttpMethodDirector.authenticateHost(HttpMethodDirector.java:282)
at org.apache.commons.httpclient.HttpMethodDirector.authenticate(HttpMethodDirector.java:234)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.axis.transport.http.CommonsHTTPSender.invoke(CommonsHTTPSender.java:186)
This is because the format of the username determines the Credentials instance created. With the DOMAIN\... prefix on the username you get an instance of org.apache.commons.httpclient.NTCredentials rather than org.apache.commons.httpclient.UsernamePasswordCredentials - which as the message explains can't be used for NTLM.

Friday, January 28, 2011

Is the IBM DB2 UDB service not running? Can't make JDBC Type 4 connections

Keywords:
IBM DB2 v8 UDB Universal Driver TCP/IP which port windows service JDBC Type 4

Problem:
Attempting to make a JDBC Type 4 connection (ie pure java talking TCP/IP, no native code) to the DB2 server gives me:

com.ibm.db2.jcc.b.SqlException: IO Exception opening socket to server <myservername> on port 50000.
The DB2 Server may be down.


The DB2 server (running on Windows) is definitely running. In DB2 "Control Center" the "instance" ("DB2" the default name?) is definitely started. Looking at the local TCP ports being listened via netstat -abno there's no 50000 or anything close. So either the service that accepts the Type-4 JDBC connections (UDB) is not running or it's listening on a different port. How do you check?

Solution:
I couldn't find any mention of this in searching (though I did find "DB2 Version 8 Connectivity Cheat Sheet" which is good reference for DB2 generally), but by accident I stumbled on "Setup communications..." on right clicking the "DB2" instance in DB2 Control Center. From here the rest is straight forward:

  1. so, right click the "DB2" instance and select "Setup communications..."

  2. check TCP/IP

  3. click the Properties button and then just click the Default button to get default values

    • Note the port number: 50000 by default

  4. after clicking OK from the Properties and the communications dialog you'll have to restart the instance

    • right click the "DB2" instance and select Stop and then Start



Now when you check the open ports via netstat -abno you should hopefully see:

TCP 0.0.0.0:50000 0.0.0.0:0 LISTENING 3012
[db2syscs.exe]


To recap the IBM DB2 Universal Driver Type 4 (thin) connection details:
Driver Class:com.ibm.db2.jcc.DB2Driver
URL:jdbc:db2://<host>[:<port>]/<database_name>
eg:jdbc:db2://myservername:50000/MYDATABASE
Driver Class:com.ibm.db2.jcc.DB2Driver
Jar file(s):db2jcc.jar & db2jcc_license_cu.jar