How receive XML argument from storedProcedudure using spring jdbcTemplate? - java

I use MS-SQL server for my spring application.
I have a store procedure, witch I want to execute from my app.
CREATE PROCEDURE dbo.spCheckPerson (
#inXML XML,
#outXML XML OUTPUT,
#inDebug BIT = 0 )
AS
--do sth
SET #outXML = '<person><name>Piotr</name></person>'
RETURN 0
I try to execute it by this DAO:
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Types;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.support.xml.Jdbc4SqlXmlHandler;
public class PersonDAOImpl implements PersonDAO {
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall spCheckPerson;
public PersonDAOImpl(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
#Override
public String checkPersonData(String personData) {
Jdbc4SqlXmlHandler sqlXmlHandler = new Jdbc4SqlXmlHandler();
spCheckPerson = new SimpleJdbcCall(jdbcTemplate)
.withoutProcedureColumnMetaDataAccess()
.withProcedureName("spCheckPerson")
.declareParameters(new SqlParameter("inXML", Types.SQLXML))
.declareParameters(new SqlOutParameter("outXML", Types.SQLXML));
Map<String, Object> result = spCheckPerson.execute(sqlXmlHandler.newSqlXmlValue("<test>Test</test>"));
return ((SQLXML) result.get("outXML")).getString();
}
}
, but I get error:
SEVERE: Servlet.service() for servlet [SpringDispatcher] in context with path
[/TestSpringProject] threw exception [Request processing failed; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The TDS protocol stream is not valid.] with root cause
com.microsoft.sqlserver.jdbc.SQLServerException: The TDS protocol stream is not valid.
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1667)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1654)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.throwInvalidTDS(SQLServerConnection.java:1635)
at com.microsoft.sqlserver.jdbc.TDSReader.throwInvalidTDS(IOBuffer.java:4747)
at com.microsoft.sqlserver.jdbc.TDSReader.readBytes(IOBuffer.java:5061)
at com.microsoft.sqlserver.jdbc.TDSReader.readWrappedBytes(IOBuffer.java:5082)
at com.microsoft.sqlserver.jdbc.TDSReader.readInt(IOBuffer.java:5023)
at com.microsoft.sqlserver.jdbc.TDSReader.readUnsignedInt(IOBuffer.java:5040)
at com.microsoft.sqlserver.jdbc.PLPInputStream.readBytesInternal(PLPInputStream.java:313)
at com.microsoft.sqlserver.jdbc.PLPInputStream.getBytes(PLPInputStream.java:104)
at com.microsoft.sqlserver.jdbc.PLPXMLInputStream.getBytes(PLPInputStream.java:509)
at com.microsoft.sqlserver.jdbc.SQLServerSQLXML.getString(SQLServerSQLXML.java:290)
at pl.test.dao.PersonDAOImpl.checkPersonData(PersonDAOImpl.java:34)
How should I properly receive this object? Which class should I use to cast value? What is TDS protocol? I tried to used method: getCharacterStream() from SQLXML but it gives the same exception.

Related

Cassandra QueryLogger introduces NoHostAvailableException

I have a spring boot application, where I have used the pattern of extending AbstractCassandraConfiguration to bootstrap Cassandra. It alls works beautifully. I now want to turn on query logging, so i have attempted to implement this pattern:
https://github.com/spring-projects/spring-boot/issues/7312#issuecomment-358448437
I do this by updating my AbstractCassandraConfiguration implementation to:
1. Be a #Configuration class
2. Adding the Bean QueryLogger Bean
But then at runtime, I start getting the NoHostAvailableException.
As the before and after code are v similar, ill just paste it all and indicate the new, breaking code.
I can feel connection is getting corrupted, but also feel my pattern is so standard, not sure what is going on!!! Any tips appreciated. Thanks
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.AbstractCassandraConfiguration;
import org.springframework.data.cassandra.config.SchemaAction;
import com.datastax.driver.core.AuthProvider;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.PlainTextAuthProvider;
import com.datastax.driver.core.QueryLogger;
#Configuration // **** NEW ****
public class CassandraConfig extends AbstractCassandraConfiguration {
#Value("${spring.data.cassandra.contact-points:placeholder}")
private String contactPoints;
#Value("${spring.data.cassandra.port:0000}")
private int port;
#Value("${spring.data.cassandra.keyspace-name:placeholder}")
private String keySpace;
#Value("${spring.data.cassandra.username}")
private String username;
#Value("${spring.data.cassandra.password}")
private String password;
#Value("${spring.data.cassandra.schema-action}")
private String schemaAction;
// removed all the #Override getters for above props
// **** NEW ****
#Bean
public QueryLogger queryLogger(Cluster cluster) {
QueryLogger queryLogger = QueryLogger.builder().build();
cluster.register(queryLogger);
return queryLogger;
}
}
Exception:
[dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.cassandra.CassandraConnectionFailureException: Query; CQL [SELECT * FROM my_table;]; All host(s) tried for query failed (tried: cassandradb01.AAA.test.XXXX.com/10.18.51.15:9042 (com.datastax.driver.core.exceptions.BusyPoolException: [cassandradb01.AAA.test.XXXX.com/10.18.51.15] Pool is busy (no available connection and timed out after 5000 MILLISECONDS))); nested exception is com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: cassandradb01.AAA.test.XXXX.com/10.18.51.15:9042 (com.datastax.driver.core.exceptions.BusyPoolException: [cassandradb01.AAA.test.XXXX.com/10.18.51.15] Pool is busy (no available connection and timed out after 5000 MILLISECONDS)))] with root cause

How to launch CommandLineRunner from Spring Controller

I have a main Spring Boot application in the top-level package that I launch, with different controllers in the children packages:
i.e.
ca.example.batch.MainBatchApplication
ca.example.batch.job1.Job1Controller (/batch/startJob1)
ca.example.batch.job2.Job2Controller (/batch/startJob2)
I am able to start the Spring Batches by going to the URL: http://localhost:8080/batch/startJob1 or http://localhost:8080/batch/startJob2.
However, in another package I have:
ca.example.batch.job3.Job3Controller
ca.example.batch.job3.Job3Application
... which is not a Spring Batch, but a Spring CommandLineRunner. I want to know if there is a way to launch MainBatchApplication without starting that CommandLineRunner automatically, but run it through the controller, i.e. http://localhost:8080/batch/startJob3.
The controller code I am looking at is:
package ca.example.batch.job3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class Job3Controller {
#RequestMapping("/batch/startJob3")
public String handle() throws Exception {
Job3Application app = new Job3Application();
Logger logger = LoggerFactory.getLogger(this.getClass());
logger.info("app: " + app);
String args = "";
app.run(args);
return "COMPLETE";
}
}
Job3Application is:
package ca.example.batch.job3;
import static java.lang.System.exit;
import java.util.List;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Import;
import ca.example.batch.common.CommonLibraryReference;
import ca.example.batch.common.domain.WasHost;
import ca.example.batch.common.svc.WasHostService;
#SpringBootApplication
#Import(CommonLibraryReference.class)
public class Job3Application implements CommandLineRunner {
private final Logger logger = LoggerFactory.getLogger(Job3Application.class);
#Autowired
public DataSource dataSource;
#Autowired
public WasHostService wasHostService;
public Job3Application() {
}
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Job3Application.class)
.web(WebApplicationType.NONE)
.bannerMode(Banner.Mode.OFF)
.run(args);
}
#Override
public void run(String... strings) throws Exception {
logger.info("Loading data...");
logger.info("wasHostService: " + wasHostService);
List<WasHost> hostList = wasHostService.findAll();
if (!hostList.isEmpty()) {
for (WasHost host : hostList) {
logger.info("hostname: " + host.getHostname());
}
} else {
logger.info("No hosts found in database. Aborting data collection.");
exit(0);
}
}
}
The error I get in the log is:
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring FrameworkServlet 'dispatcherServlet'
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO c.e.b.job3.Job3Controller - app: ca.example.batch.job3.Job3Application#472d7ac
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO c.e.b.job3.Job3Application - Loading data...
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO c.e.b.job3.Job3Application - wasHostService: null
""2018-07-07 12:56:09 [http-nio-9191-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
"java.lang.NullPointerException: null
at ca.example.batch.job3.Job3Application.run(Job3Application.java:47)
at ca.example.batch.job3.Job3Controller.handle(Job3Controller.java:21)
... when I launch the controller request.
If this isn't the right way, please advise.
Basically, what I am trying to do is launch a main() from within a controller but use the MainBatchApplication runtime to run it (if that makes sense?). When the program is done, it send the return code back to the controller and shows in the browser.
Thank you,
Joey
ca.example.batch.MainBatchApplication is the main appliction you start.
So it scans all Components in package ca.example.batch. That means it should detect ca.example.batch.job3.Job3Application so you should be able to #Autowireit in the Job3Controller
this should work:
#Controller
public class Job3Controller {
private final Job3Application job3Application;
public Job3Controller (Job3Application job3Application){
this.job3Application = job3Application;
}
#RequestMapping("/batch/startJob3")
public String handle() throws Exception {
String[] args = ...
this.job3Application.run(args);
return "COMPLETE";
}
....
}

AttributeNotFoundException through JMX in Startup bean on Wildfly

Hello everyone!
I'm trying to load wildfly server's system properties through JMX in Startup bean's #PostConstruct method. It works fine on the already started server instance when deployment starts, but fails while starting with server instance bootstrapping.
Wildfly 11.0.0.CR1
Startup bean code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.startup;
import ru.wildfly.test.ejb.wildflyconsulregistrar.api.ConsulRegistrar;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;
#Startup
#Singleton
public class WildflyConsulRegistrarStartupBean {
#Inject
private ConsulRegistrar consulRegistrar;
#PostConstruct
public void initialize() {
registerServices();
}
private void registerServices() {
consulRegistrar.registerService("WildflyTestCluster");
}
.............
}
ConsulRegistrar code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.impl;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.agent.model.NewService;
import ru.test.ejb.wildflyconsulregistrar.api.ConsulRegistrar;
import ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.api.CurrentServerNodeSettings;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
#Dependent
public class ConsulRegistrarImpl implements ConsulRegistrar {
...............
#Inject
private CurrentServerNodeSettings currentServerNodeSettings;
.............
#Override
public void registerService(String serviceName) {
String currentNodeName = currentServerNodeSettings.getCurrentNodeName();
........................
}
.......................
}
CurrentServerNodeSettings code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.impl;
import ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.api.CurrentServerNodeSettings;
import javax.enterprise.context.Dependent;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
#Dependent
public class CurrentServerNodeSettingsWildflyImpl implements CurrentServerNodeSettings {
....................
#Override
public String getCurrentNodeName() {
String currentNodeName = getPlatformMBeanServerAttributeValue(String.class, "jboss.as:system-property=server.name", "value");
return currentNodeName;
}
private <T> T getPlatformMBeanServerAttributeValue(Class<T> valueType, String objectName, String attributeName) {
T attributeValue = null;
try {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
Object attributeObject = mBeanServer.getAttribute(new ObjectName(objectName), attributeName);
attributeValue = attributeObject != null ? (valueType.cast(attributeObject)) : null;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return attributeValue;
}
}
Error message:
Caused by: java.lang.IllegalStateException:
javax.management.AttributeNotFoundException:
"WFLYCTL0216: Management resource '[(\"system-property\" => \"server.name\")]' not found"
at ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.impl.CurrentServerNodeSettingsWildflyImpl
.getPlatformMBeanServerAttributeValue(CurrentServerNodeSettingsWildflyImpl.java:41)
I have found the same issue on jboss forum https://developer.jboss.org/message/971717#971717 , but it was unanswered.
Any suggestions?
This is a dependency problem during startup, i.e. the server name is set after your #PostConstruct method gets executed. Try to load the server name lazy when it is accessed from the application for the first time.
In Wildfly there is no generic way to enforce the sequence of deployments from the application despite the definition of module dependencies. But this won't help in your case.

How to use #Startup Annotation for Service that Pushes Data to Websocket?

This is the Java EE7 #Startup annotation for reference. I am using the latest GlassFish server and IntelliJ to run the server.
I need to instantiate this service so that it can send packets of data periodically to a websocket for processing, but the fact that I use
session.getBasicRemote().sendObject(message);
in the end forces me to throw IOException and EncodeException.
This is bad as #Startup or #Singleton disallows usage of Exceptions when instantiating:
war exploded: java.io.IOException: com.sun.enterprise.admin.remote.RemoteFailureException: Error occurred during deployment: Exception while deploying the app [keyBoard_war_exploded] : The lifecycle method [printSchedule] must not throw a checked exception.
Here is my code:
package site.xxxx.models;
import site.xxxx.message.Message;
import site.xxxx.message.TextMessage;
import site.xxxx.modules.Packet;
import site.xxxx.websocket.MainServerEndpoint;
import javax.annotation.PostConstruct;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.json.Json;
import javax.json.JsonObject;
import javax.websocket.EncodeException;
import javax.websocket.Session;
import java.io.IOException;
import java.util.Set;
#Startup
#Singleton
public class Service {
private static Service service;
Set<Session> peers = MainServerEndpoint.peers;
#PostConstruct
public void mainLoop() throws IOException, EncodeException, InterruptedException {
sendSpamPacket();
}
private void sendSpamPacket() throws IOException, EncodeException {
JsonObject ret = Json.createObjectBuilder()
.add("type", "textMessage")
.add("text", "ayyyy")
.build();
Packet packet = new Packet(new TextMessage(ret));
MainServerEndpoint.sendPacket(packet);
//results in calling session.getBasicRemote().sendObject(message);
}
}

Connection getting closed while executing oracle.sql.ARRAY.getArray() in spring stored procedure implementation

I am facing a problem while trying to read OUT parameter of a stored procedure using Spring's stored procedure implementation. The OUT parameter is a custom/user defined ORACLE type. Find below the implementation detail. Please let me know how to get around the problem.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import oracle.jdbc.OracleTypes;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import org.apache.log4j.Logger;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.SqlTypeValue;
import org.springframework.jdbc.object.StoredProcedure;
import com.***.****.bean.ExcelListenerBean;
import com.***.****.bean.RevAppViewBean;
public class RevPrdBrkDwnSP extends StoredProcedure{
private final Logger log = Logger.getLogger(this.getClass().getName());
public RevPrdBrkDwnSP(DataSource dataSource, String storeProcName) throws SQLException {
// Run the Parent
super(dataSource, storeProcName);
if (log.isInfoEnabled()) {
log.info("PBAREV product breakdown processes Stored Procedure Name : "+ storeProcName);
}
// Declare the Parameter Details
declareParameter(new SqlParameter("IN_ARRAY", OracleTypes.ARRAY, "PBAREV.PROD_PRCT_BRKDWN_TYPE_ARRAY"));
declareParameter(new SqlOutParameter("OUT_ARRAY", OracleTypes.ARRAY, "PBAREV.PROD_PRCT_BRKDWN_TYPE_ARRAY"));
// Compile the SP
compile();
}
public boolean execute(final RevAppViewBean appViewBean$Session, final DataSource dataSource) throws Exception {
boolean returnVal = false;
Map<String, Object> inParams = new HashMap<String, Object>();
log.info("Setting up the Store Procedure Params");
inParams.put("IN_ARRAY", new SqlTypeValue() {
public void setTypeValue(PreparedStatement cs, int index, int sqlType, String typeName) throws SQLException {
Connection con = cs.getConnection();
ArrayDescriptor des = ArrayDescriptor.createDescriptor("PBAREV.PROD_PRCT_BRKDWN_TYPE_ARRAY", con);
ARRAY a = new ARRAY(des, con, appViewBean$Session.getExcelRecLst().toArray());
cs.setObject(1, (Object)a);
}
});
if (log.isDebugEnabled()) {
log.debug("Executing the PBAREV Store Procedure ");
}
final Map out = super.execute(inParams);
log.info("output size is --------------------->>>>>>>>>> "+out.size()); //prints the actual value
ARRAY returnValue = (ARRAY)out.get("OUT_ARRAY");
log.info("size of returnValue is "+returnValue.length()); //prints th right number of results
Object[] idOutArraz = (Object[])returnValue.getArray(); // Error is thrown from this location
for(int i= 0; i<idOutArraz.length;i++){
ExcelListenerBean bean = (ExcelListenerBean) idOutArraz[i];
}
log.info(returnValue);
if (log.isDebugEnabled()) {
log.info("Output from PBAREV Store Procedure :" + out);
}
return returnVal;
}
}
The stack trace of the exception is as follows.
Caused by: java.lang.NullPointerException
at oracle.jdbc.driver.OracleConnection.safelyGetClassForName(OracleConnection.java:5074)
at oracle.jdbc.driver.OracleConnection.addClassMapEntry(OracleConnection.java:2852)
at oracle.jdbc.driver.OracleConnection.addDefaultClassMapEntriesTo(OracleConnection.java:2843)
at oracle.jdbc.driver.OracleConnection.initializeClassMap(OracleConnection.java:2529)
at oracle.jdbc.driver.OracleConnection.ensureClassMapExists(OracleConnection.java:2523)
at oracle.jdbc.driver.OracleConnection.getTypeMap(OracleConnection.java:2829)
at oracle.sql.ARRAY.getMap(ARRAY.java:863)
at oracle.sql.ARRAY.getArray(ARRAY.java:370)
at com.****.****.****.RevPrdBrkDwnSP.execute(RevPrdBrkDwnSP.java:68)
at com.*****.****.*****.****.IBatisRevPrdBrkDwnDao.runPrdBrkDwnProcess(IBatisRevPrdBrkDwnDao.java:24)
The only way to avoid this error when deployed on an Application server is to increase the minimum connections pool to have more than one active connections.

Categories

Resources