TCP client send Message to external server, reply message is not expected - tcp

I am setting up a TCP client by Spring Integration, send Message with String as payload, return is not expected. Perhaps serializer/deserializer is not working correctly? Sorry I am learning Spring integration.
I can connect to an external TCP server by oepnssl:
---
# DC API Test System: microstrategy
sessions.list.
.
response
,status_code,1
,status_message,Unrecognised operation
,time,2019-02-15 07:08:08 (+1000)
.
The command I need to sent is "sessions.list\n.\n".
Now I built a tcp client trying to connect to the server:
spring-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip-5.1.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-5.1.xsd">
<bean id="integrationConversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.microstrategy.example.ByteArrayToStringConverter"/>
</list>
</property>
</bean>
<bean id="customeSerilizerDeserlizer" class="com.microstrategy.example.CustomSerializerDeserializer" />
<int:gateway service-interface="com.microstrategy.example.SimpleGateway"
default-request-channel="output"
default-reply-channel="reply"/>
<int:channel id="output"/>
<int:channel id="reply" datatype="java.lang.String"/>
<int-ip:tcp-connection-factory
id="clientFactory"
type="client"
host="server"
port="15099"
serializer="customeSerilizerDeserlizer"
single-use="true"
so-timeout="10000"/>
<int-ip:tcp-outbound-gateway
request-channel="output"
reply-channel="reply"
connection-factory="clientFactory"
request-timeout="10000"
reply-timeout="10000"/>
</beans>
So following this repo, the string should convert to byte[].
I am using exactly the same converter as the repo, so I just copy here to save your time:
import java.io.UnsupportedEncodingException;
import org.springframework.core.convert.converter.Converter;
public class ByteArrayToStringConverter implements Converter<byte[], String> {
private String charSet = "UTF-8";
public String convert(byte[] bytes) {
try {
return new String(bytes, this.charSet);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.out.println("caught excepton in converter");
return new String(bytes);
}
}
/**
* #return the charSet
*/
public String getCharSet() {
return charSet;
}
/**
* #param charSet the charSet to set
*/
public void setCharSet(String charSet) {
this.charSet = charSet;
}
}
public interface SimpleGateway {
public String send(Message message);
}
I made a custom serializer:
package com.microstrategy.example;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer;
public class CustomSerializerDeserializer extends AbstractByteArraySerializer {
#Override
public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
outputStream.write(bytes);
}
#Override
public byte[] deserialize(InputStream inputStream) throws IOException {
// TODO Auto-generated method stub
return null;
}
}
My main function:
Message<String> message = MessageBuilder.withPayload("sessions.list").build();
String replyMessage = simpleGateway.send(message);
Message<String> message2 = MessageBuilder.withPayload(".").build();
String replyMessage2 = simpleGateway.send(message2);
System.out.println(replyMessage2);
The replyMessage is
# DC API Test System: microstrategy
It seems I successfully connected to the server by sending message, but the message is not correctly recognized by the server. Any useful suggestions will be appreciated, thanks!
Update 1:
I add output to serializer:
public class CustomSerializerDeserializer extends AbstractByteArraySerializer {
#Override
public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
System.out.println("inside serialize");
System.out.println(System.currentTimeMillis());
String string = new String(bytes);
System.out.println("byte[] in serialize is " + string);
outputStream.write(bytes);
}
#Override
public byte[] deserialize(InputStream inputStream) throws IOException {
// TODO Auto-generated method stub
System.out.println("inside deserialize");
System.out.println(System.currentTimeMillis());
return null;
}
}
inside serialize
1550182834431
byte[] in serialize is sessions.list
.
# DC API Test System: microstrategy
2019-02-14 17:21:35.185 INFO 91620 --- [ Thread-1] o.s.i.endpoint.EventDrive
The output shows byte[] seems correct, then why server is not return as expected?
Update 2: I changed the main function (has been updated) because the framework will add "\n" at the end of each message. Is it right?
The output is
inside serialize
1550184564485
byte[] in serialize is sessions.list
inside serialize
1550184565003
byte[] in serialize is .
2019-02-14 17:49:35.013 ERROR 91740 --- [ main] o.s.i.ip.tcp.TcpOutboundGateway : Tcp Gateway exception
org.springframework.integration.MessageTimeoutException: Timed out waiting for response
No response?
Update 3: I am able to open the connection by sending an empty message. But why other message is not working?
Message<String> message = MessageBuilder.withPayload("").build();
String replyMessage = simpleGateway.send(message);
System.out.println(replyMessage);
Any helps thanks?
This is my update before I solved the issue, which is deleted by admin:
I got the response from server now, but it comes with error:
Cannot correlate response - no pending reply for server:15099:49469:0fdce5c4-432f-4ce4-b878-2e08d0e96419
inside serialize
1550189909340
byte[] in serialize is sessions.list
.
GenericMessage [payload=byte[35], headers={ip_tcp_remotePort=15099, ip_connectionId=server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839, ip_localInetAddress=/10.21.66.115, ip_address=217.78.6.17, id=3a6ff696-f12f-6328-da1a-5d613d37a4b2, ip_hostname=server, timestamp=1550189909764}]
2019-02-14 19:18:29.850 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.851 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.851 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.851 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.852 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway : Cannot correlate response - no pending reply for server:15099:49550:a3bc44fa-7d36-483c-a1b8-f91eea62d839
2019-02-14 19:18:29.852 ERROR 92282 --- [pool-1-thread-1] o.s.i.ip.tcp.TcpOutboundGateway
The main function is
message = new GenericMessage<String>("sessions.list\n.\n");
replyMessage = simpleGateway.send(message);
System.out.println(replyMessage);
I tried to remove the last "\n"
message = new GenericMessage<String>("sessions.list\n.");
It does not work, got time-out exception. How can I remove these "Cannot correlate response" errors?
Update 1:
I think the server responses with several lines of message:
sessions.list
.
response
,status_code,0
,status_message,OK
,time,2019-02-16 00:10:49 (+1000)
sessions
.
I need to capture all responses until ".".

If you are not expecting a reply you should use an outbound-channel-adapter instead of a gateway.

Finally it got solved. I will post my solution for others' reference.
My TCP client send multiple line commands which ends with ".", and expects multiple line response which also ends with "." from the external server. So I need to write custom serializer and deserializer. The default CRLF serializer/deserializer does not meet my case.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.springframework.core.serializer.Deserializer;
import org.springframework.core.serializer.Serializer;
public class CustomSerializerDeserializer implements Serializer<String>, Deserializer<String> {
#Override
public String deserialize(InputStream inputStream) throws IOException {
// TODO Auto-generated method stub
StringBuilder builder = new StringBuilder();
int c;
while (true) {
c = inputStream.read();
builder.append((char)c);
if ((char)c == '.') {
break;
}
}
return builder.toString();
}
#Override
public void serialize(String object, OutputStream outputStream) throws IOException {
// TODO Auto-generated method stub
outputStream.write(object.getBytes());
outputStream.flush();
}
}
The xml configuration is
<int-ip:tcp-connection-factory
id="clientFactory"
type="client"
host="server"
port="15099"
ssl-context-support="sslContext"
serializer="customeSerilizerDeserlizer"
deserializer="customeSerilizerDeserlizer"
single-use="true"
so-timeout="10000"/>

Related

After accidentally deleting Data Dictionary (app:dictionary) Alfresco doesn't start

One operator deleted Data Dictionary and restarted Alfresco 3.4.12 Enterprise Edition. The context /alfresco doesn't start with the following exception:
17:43:11,100 INFO [STDOUT] 17:43:11,097 ERROR [web.context.ContextLoader] Context initialization failed
org.alfresco.error.AlfrescoRuntimeException: 08050000 Failed to find 'app:dictionary' node
at org.alfresco.repo.action.scheduled.ScheduledPersistedActionServiceImpl.locatePersistanceFolder(ScheduledPersistedActionServiceImpl.java:132)
Looking at the source code in org.alfresco.repo.action.scheduled.ScheduledPersistedActionServiceImpl.java, the path is hardwired.
Then we followed the tip from https://community.alfresco.com/thread/202859-error-failed-to-find-appdictionary-node, editing bootstrap-context.xml, comment out the class.
After the change the error went over, now the RenditionService couldn't start.
We're looking for a way to recover the deleted node, since we can obtain the nodeid from the database. So we created a small class and invoke it through spring in bootstrap-context.xml, but it's failing due to permissions. Could you take a look at the code and tell us what's wrong. The code is:
package com.impulseit.test;
import javax.transaction.UserTransaction;
import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.node.archive.RestoreNodeReport;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
public class RestoreNode {
private NodeArchiveService nodeArchiveService;
private ServiceRegistry serviceRegistry;
private String nodeName ="archive://SpacesStore/adfc0cfe-e20b-467f-ad71-253aea8f9ac9";
public void setNodeArchiveService(NodeArchiveService value)
{
this.nodeArchiveService = value;
}
public void setServiceRegistry(ServiceRegistry value)
{
this.serviceRegistry = value;
}
public void doRestore() {
RunAsWork<Void> runAsWork = new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
NodeRef nodeRef = new NodeRef(nodeName);
//RestoreNodeReport restoreNodeReport =
UserTransaction trx_A = serviceRegistry.getTransactionService().getUserTransaction();
trx_A.begin();
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
RestoreNodeReport restored = nodeArchiveService.restoreArchivedNode(nodeRef);
trx_A.commit();
return null;
}
};
AuthenticationUtil.runAs(runAsWork,AuthenticationUtil.getSystemUserName());
}
public RestoreNode() {
}
}
The exception is:
19:31:21,747 User:admin ERROR [node.archive.NodeArchiveServiceImpl] An unhandled exception stopped the restore
java.lang.NullPointerException
at org.alfresco.repo.security.permissions.impl.model.PermissionModel.getPermissionReference(PermissionModel.java:1315)
at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.getPermissionReference(PermissionServiceImpl.java:956)
at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.hasPermission(PermissionServiceImpl.java:976)
Thank you in advance.
Luis

Why do I get a CannotAcquireResourceException while trying to connect, when I extend AbstractComboPooledDataSource?

In a Tomcat 8.5.15 environment using an Oracle 11 database, I want to implement a data source that handles encrypted passwords in the context.xml. For example, instead of having:
<Resource
auth="Container"
description="MyDataSource"
driverClass="oracle.jdbc.OracleDriver"
maxPoolSize="100"
minPoolSize="10"
acquireIncrement="1"
name="jdbc/MyDataSource"
user="me"
password="mypassword"
factory="org.apache.naming.factory.BeanFactory"
type="com.mchange.v2.c3p0.ComboPooledDataSource"
jdbcUrl="jdbc:oracle:thin:#mydb:1521:dev12c"
/>
I'd like to have something like the following, where only the password and type have changed:
<Resource
auth="Container"
description="MyDataSource"
driverClass="oracle.jdbc.OracleDriver"
maxPoolSize="100"
minPoolSize="10"
acquireIncrement="1"
name="jdbc/MyDataSource"
user="me"
password="D364FEC1CBC1DAEB91A1D8997D4A2482B"
factory="org.apache.naming.factory.BeanFactory"
type="com.mycompany.EncryptedC3p0WrappingDataSource"
jdbcUrl="jdbc:oracle:thin:#mydb:1521:dev12c"
/>
The main change is my implementation of the EncryptedC3p0WrappingDataSource. C3p0's ComboPooledDataSource is final, so I can't extend it. Instead, I extend it's superclass, AbstractComboPooledDataSource, and implement some additional methods. This class contains a ComboPooledDataSource, which is the wrappedDataSource, and is used for the actual work via delegation.
public class EncryptedC3p0WrappingDataSource
extends AbstractComboPooledDataSource
implements PooledDataSource, Serializable, Referenceable
{
/** The actual C3P0 data source that will be used to connect to the database. */
private ComboPooledDataSource wrappedDataSource = new ComboPooledDataSource();
// TODO Should this be retrieved from a pool? How?
/** The object that does the encryting/decrypting. */
private Encryptor encryptor;
/**Construct the data source, with the necessary Encryptor. */
public EncryptedC3p0WrappingDataSource() {
try {
encryptor = new Encryptor();
} catch (InvalidKeyException | NoSuchAlgorithmException
| NoSuchPaddingException | UnsupportedEncodingException e) {
log.fatal("Error instantiating decryption class.", e);
throw new RuntimeException(e);
}
}
/**
* Set the in-memory password of the wrapped data source to the decrypted password.
* #param encryptedPassword the encrypted password, as read from a file.
*/
public void setPassword(String encryptedPassword) {
try {
String decryptedPassword
= encryptor.decrypt(encryptedPassword, Encryptor.AES_ALGORITHM);
log.info("***************** Successfully decrypted "
+ encryptedPassword + " to " + decryptedPassword);
wrappedDataSource.setPassword(decryptedPassword);
} catch (Exception e) { e.printStackTrace(); }
}
public void setDriverClass(String driverClass) throws PropertyVetoException {
wrappedDataSource.setDriverClass(driverClass);
}
public void setJdbcUrl(String jdbcUrl) {
wrappedDataSource.setJdbcUrl(jdbcUrl);
}
public void setDescription(String description) {
wrappedDataSource.setDescription(description);
}
public void setMaxPoolSize(int maxPoolSize) {
wrappedDataSource.setMaxPoolSize(maxPoolSize);
}
public void setMinPoolSize(int minPoolSize) {
wrappedDataSource.setMinPoolSize(minPoolSize);
}
public void setAcquireIncrement(int acquireIncrement) {
wrappedDataSource.setAcquireIncrement(acquireIncrement);
}
public Connection getConnection() throws SQLException {
return wrappedDataSource.getConnection();
}
public Connection getConnection(String name, String password) throws SQLException {
return wrappedDataSource.getConnection(name, password);
}
}
When I run our application under Tomcat with the first configuration (ComboPooledDataSource), it runs fine. When I try the second configuration (EncryptedC3p0WrappingDataSource), I get the following exception:
2017-07-21 07:57:29,962 FATAL [XXX.DataSourceFactory] Connections could not be acquired from the underlying database!
java.sql.SQLException: Connections could not be acquired from the underlying database!
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:690)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at com.mycompany.EncryptedC3p0WrappingDataSource.getConnection(EncryptedC3p0WrappingDataSource.java:116)
...
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1463)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:639)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:549)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:756)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:683)
... 69 more
I have looked at this extensively in the debugger. The encryption and decryption part appears to be happening correctly. My EncryptedC3p0WrappingDataSource.getConnection() method results in a call to the ComboPooledDataSource.getConnection() method (the inherited AbstractPoolBackedDataSource.getConnection() method, so why am I getting the exception?
UPDATE:
If I modify my get setPassword method to also use setOverrideDefaultPassword:
public void setPassword(String encryptedPassword) {
try {
String decryptedPassword
= encryptor.decrypt(encryptedPassword, Encryptor.AES_ALGORITHM);
log.info("***************** Successfully decrypted "
+ encryptedPassword + " to " + decryptedPassword);
wrappedDataSource.setPassword(decryptedPassword);
wrappedDataSource.setOverrideDefaultPassword(decryptedPassword);
} catch (Exception e) { e.printStackTrace(); }
}
I get a different exception:
Caused by: java.sql.SQLException: com.mchange.v2.c3p0.impl.NewProxyConnection#7e30531e
[wrapping: oracle.jdbc.driver.T4CConnection#51dba714]
is not a wrapper for or implementation of oracle.jdbc.OracleConnection
at com.mchange.v2.c3p0.impl.NewProxyConnection.unwrap(NewProxyConnection.java:1744)
at org.jaffa.security.JDBCSecurityPlugin.executeStoredProcedure(JDBCSecurityPlugin.java:117)
... 67 more
UPDATE 2:
I've posted a closely related, and hopefully simpler, question here.
The error was a result of a class loading problem, where the Oracle classes were being loaded from multiple jars (%CATALINA_HOME%\lib\ojdbc7-12.1.0.2.0.jar and %CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7-12.1.0.2.0.jar) by different class loaders. When I deleted %CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7-12.1.0.2.0.jar, my problem went away.
These sources (1, 2, 3) discuss this in more detail.

uploading file with a form from Flex Air to Java Servlet 3.0

I have been searching for days... I have a a Flex Air application that needs to upload a form to a java servlet. The form is extremely basic:
First name:
Last name:
Picture:
It is the most basic application... I have been trying to use this on client side:
http://blog.inspirit.ru/?p=139
import flash.utils.ByteArray;
import ru.inspirit.net.MultipartURLLoader;
var data1:ByteArray = new ByteArray();
data1.writeUTFBytes("This is a test 1");
data1.position = 0;
var data2:ByteArray = new ByteArray();
data2.writeUTFBytes("This is a test 2");
data2.position = 0;
var ml:MultipartURLLoader = new MultipartURLLoader();
ml.addEventListener(Event.COMPLETE, onReady);
function onReady(e:Event):void
{
// Upload Complete
}
// simple string data
ml.addVariable('test', 'test variable');
// file data: ByteArray, File name, Name of the file field, content MIME type (default application/octet-stream)
// use [] if you need identical file field name
// specify MIME type for your file part
ml.addFile(data1, 'test1.txt', 'Filedata[]');
ml.addFile(data2, 'test2.txt', 'Filedata[]', 'text/plain');
ml.load('test.php');
On server side all I want to do is save the pic.jpg as lastname.jpg in a c:/uploads/
could someone show me the most basic working example between air and java servlet 3.0
This may be somewhat outdated but it works - might give you a start:
public function buildForm() : void
{
var requestObj : Object = new Object();
requestObj.javavalue0 = value0;
requestObj.javavalue1 = value1;
flexform.request = requestObj;
flexform.send();
}
<mx:HTTPService id="flexform" url="https://someurl.org/Form/servletPage"
method="POST" result="resultHandlerSubmitForm(event)"
fault="faultHandler(event)" />
On the java side: use request.getParameter to get the POST values.
public class servletPage extends HttpServlet
{
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try
{
String str_javavalue0 = request.getParameter( "javavalue0" );
and so on....

servlet has to be reloaded everyday

I have created a servlet to access a database and giving response to a BB application...it was running fine during development...but after loading it on a tomcat server 6.0 after goining live the servlet has to be reloaded every morning on the tomcat server....after that it works fine during the whole day..but the next morning when i request something it gives a blank page as response and my server admin tells the servlet has to be reloaded ...
other application hosted on the server are working fine and do not need a restart...
what might be the problem....
adding the code ..if it helps
package com.ams.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.*;
import com.cms.dbaccess.DataAccess;
import com.cms.utils.ApplicationConstants;
import com.cms.utils.ApplicationHelper;
import java.sql.ResultSet;
public class BBRequestProcessorServlet extends HttpServlet {
/**
*
*/String userString;
private static final long serialVersionUID = 1L;
String jsonString = "";
ResultSet rs = null;
Connection connection = null;
Statement statement=null;
public enum db_name
{
//Test
resource_management_db,osms_inventory_db;
}
public void init(ServletConfig config)throws ServletException
{
super.init(config);
System.out.println("Inside init");
}
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException
{
try{
connection = DataAccess.connectToDatabase("xxx", connection);
statement = DataAccess.createStatement(connection);
statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
rs = statement.executeQuery("query is here");
}
catch(SQLException e)
{
e.printStackTrace();
}
String db =request.getParameter("db");
System.out.println("DATABASE NAME :"+ db);
if(db.equalsIgnoreCase("xxx")){
//Call to populate JSONArray with the fetch ResultSet data
jsonString = ApplicationHelper.populateJSONArray(rs);
}
response.setContentType(ApplicationConstants.JSON_CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.print(jsonString);
out.flush();
out.close();
System.out.println("json object sent");
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
the only errors i could find was
Jul 20, 2012 9:57:24 AM org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(/usr/local/tomcat/apache-tomcat-6.0.20/webapps/MobileServlet /WEB-INF/lib/servlet-api.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class
The culprit is most likely the way how you handle external DB resources like the Connection. This problem can happen when you keep a DB Connection open all the time without closing it. When a DB Connection is been opened for a too long time, then the DB will timeout and reclaim it. This is most likely what was happening overnight.
You should redesign your DataAccess and BBRequestProcessorServlet that way so that you are nowhere keeping hold of Connection, Statement and ResultSet as an instance variable, or worse, a static variable of the class. The Connection should be created in the very same scope as where you're executing the SQL query/queries and it should be closed in the finally block of the very same try block as where you've created it.
By the way your jsonString should absolutely also not be declared as an instance variable of the servlet, it's not threadsafe this way.
See also:
Is it safe to use a static java.sql.Connection instance in a multithreaded system?
How do servlets work? Instantiation, sessions, shared variables and multithreading
As to the error which you're seeing in the log, you should definitely remove the offending JAR. See also How do I import the javax.servlet API in my Eclipse project?
I am guessing and will be more clear after seeing your logs.
Its seems like you have putted your servlet-api.jar in the WEB-INF lib but its already in tomcat's lib.

Why Java servlet can't get Paypal IPN messages everytime?

I have a Java servlet running on my notebook with Windows Vista, I set up a static IP, did port forwarding and registered for a free DDNS service, now my servlet is running, I gave the url to Paypal to send me IPN messages, I went on to it's sandbox site got to the test tools page, tried to send test messages by clicking the "Send IPN" button, most of the time it would fail, the error is : "IPN delivery failed. Unable to connect to the specified URL. Please verify the URL and try again."
But maybe 1 in 10 times, it might be successful and my servlet would get the message, and I looked at the messages I got, they are in correct format. So I called Paypal asking why, he said I shouldn't run the servlet on my notebook, in stead I should run it on the web server, but I told him my ISP doesn't support Java on their server, and since I did all the above steps, shouldn't it be the same to run the servlet on my notebook ? He said his test showed he couldn't get to my servlet, but I asked why maybe 1 in 10 times it could get through ? If there is something wrong with running it on my notebook, then 100% times it should fail, am I correct on this point ? But anyway he said that's all he could do, and I should troubleshoot it myself. The servlet looks like this :
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class PayPal_Servlet extends HttpServlet
{
static boolean Debug=true;
static String PayPal_Url="https://www.paypal.com/cgi-bin/webscr",Sandbox_Url="https://www.sandbox.paypal.com/cgi-bin/webscr",
Dir_License_Messages="C:/Dir_License_Messages/";
static TransparencyExample Transparency_Example;
static PayPal_Message_To_License_File_Worker PayPal_message_to_license_file_worker;
// Initializes the servlet.
public void init(ServletConfig config) throws ServletException
{
super.init(config);
if (!new File(Dir_License_Messages).exists()) new File(Dir_License_Messages).mkdirs();
System.gc();
}
/** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* #param request servlet request
* #param response servlet response
*/
protected void processRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException
{
// Read post from PayPal system and add 'cmd'
Enumeration en=request.getParameterNames();
String str="cmd=_notify-validate";
while (en.hasMoreElements())
{
String paramName=(String)en.nextElement();
String paramValue=request.getParameter(paramName);
str=str+"&"+paramName+"="+URLEncoder.encode(paramValue);
}
// Post back to PayPal system to validate
// NOTE: change http: to https: in the following URL to verify using SSL (for increased security).
// using HTTPS requires either Java 1.4 or greater, or Java Secure Socket Extension (JSSE) and configured for older versions.
URL u=new URL(Debug?Sandbox_Url:PayPal_Url);
URLConnection uc=u.openConnection();
uc.setDoOutput(true);
uc.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
PrintWriter pw=new PrintWriter(uc.getOutputStream());
pw.println(str);
pw.close();
BufferedReader in=new BufferedReader(new InputStreamReader(uc.getInputStream()));
String res=in.readLine();
in.close();
// Assign posted variables to local variables
String itemName=request.getParameter("item_name");
String itemNumber=request.getParameter("item_number");
String paymentStatus=request.getParameter("payment_status");
String paymentAmount=request.getParameter("mc_gross");
String paymentCurrency=request.getParameter("mc_currency");
String txnId=request.getParameter("txn_id");
String receiverEmail=request.getParameter("receiver_email");
String payerEmail=request.getParameter("payer_email");
if (res.equals("VERIFIED")) // Check notification validation
{
// check that paymentStatus=Completed
// check that txnId has not been previously processed
// check that receiverEmail is your Primary PayPal email
// check that paymentAmount/paymentCurrency are correct
// process payment
}
else if (res.equals("INVALID")) // Log for investigation
{
}
else // Log for error
{
}
// ===========================================================================
if (txnId!=null)
{
Write_File_Safe_Fast(Dir_License_Messages+txnId+".txt",new StringBuffer(str.replace("&","\n")),false);
}
// ===========================================================================
String Message_File_List[]=Tool_Lib.Get_File_List_From_Dir(Dir_License_Messages);
response.setContentType("text/html");
PrintWriter out=response.getWriter();
String title="Reading All Request Parameters",Name="",Value;
out.println("<Html><Head><Title>"+title+"</Title></Head>\n<Body Bgcolor=\"#FDF5E6\">\n<H1 Align=Center>"+title+"</H1>\n"+
"<Table Border=1 Align=Center>\n"+"<Tr Bgcolor=\"#FFAD00\"><Th>Parameter Name</Th><Th>Parameter Value(s) Messages = "+Message_File_List.length+"</Th></Tr>");
Enumeration paramNames=request.getParameterNames();
while(paramNames.hasMoreElements())
{
String paramName=(String)paramNames.nextElement();
out.print("<Tr><Td>"+paramName+"</Td><Td>");
String[] paramValues=request.getParameterValues(paramName);
if (paramValues.length == 1)
{
String paramValue=paramValues[0];
if (paramValue.length() == 0) out.print("<I>No Value</I>");
else
{
out.println(paramValue+"</Td></Tr>");
// Out("paramName = "+paramName+" paramValue = "+paramValue);
// if (paramName.startsWith("Name")) Name=paramValue;
// else if (paramName.startsWith("Value")) Write_File_Safe_Fast("C:/Dir_Data/"+Name,new StringBuffer(paramValue),false);
}
}
else
{
out.println("<Ul>");
for (int i=0;i<paramValues.length;i++) out.println("<Li>"+paramValues[i]);
out.println("</Ul></Td</Tr>");
}
}
out.println("</Table>\n</Body></Html>");
}
/** Handles the HTTP <code>GET</code> method.
* #param request servlet request
* #param response servlet response
*/
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { processRequest(request,response); }
/** Handles the HTTP <code>POST</code> method.
* #param request servlet request
* #param response servlet response
*/
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { processRequest(request,response); }
// Returns a short description of the servlet.
public String getServletInfo() { return "Short description"; }
// Destroys the servlet.
public void destroy() { System.gc(); }
public static void Write_File_Safe_Fast(String File_Path,StringBuffer Str_Buf,boolean Append)
{
FileOutputStream fos=null;
BufferedOutputStream bos=null;
try
{
fos=new FileOutputStream(File_Path,Append);
bos=new BufferedOutputStream(fos);
for (int j=0;j<Str_Buf.length();j++) bos.write(Str_Buf.charAt(j));
}
catch (Exception e) { e.printStackTrace(); }
finally
{
try
{
if (bos!=null)
{
bos.close();
bos=null;
}
if (fos!=null)
{
fos.close();
fos=null;
}
}
catch (Exception ex) { ex.printStackTrace(); }
}
System.gc();
}
}
I use Netbean6.7 to develop the servlet, and the code was from Paypal's JSP sample code, what can I do to debug the problem ?
HI, try to use my library:
http://paypal-nvp.sourceforge.net/index.htm
I hope it will help you. If you have any questions, improvements you can contact me. You find my email in the comments of the source.

Resources