When performing a programmatic login using WSCallbackHandlerImpl and there is no java.naming.provider.url set as a system property or in the jndi.properties file, one needs to call:
Object obj = initialContext.lookup("");
prior to performing the login.
Afterwards the following code works:
LoginContext lc = null;
try {
lc = new LoginContext("WSLogin",
new WSCallbackHandlerImpl("userName", "realm", "password"));
} catch (LoginException le) {
System.out.println("Cannot create LoginContext. " + le.getMessage());
// insert error processing code
} catch(SecurityException se) {
System.out.printlin("Cannot create LoginContext." + se.getMessage();
// Insert error processing
}
See: http://publib.boulder.ibm.com/infocenter/wsdoc400/v6r0/index.jsp?topic=/com.ibm.websphere.iseries.doc/info/ae/ae/xsec_jaas.html
Neither the obj nor the initialContext gets passed to the WSCallbackHandlerImpl or the LoginContext.
According to the Javadoc, InitialContext.lookup("") returns a new instance of the context.
Questions:
Why is this empty string lookup needed in this case?
How does WSCallbackHandlerImpl get the server URL?
Is this WebSphere specific?
Related
We have to implement a logic to write the unique code generation in Java. The concept is when we generate the code the system will check if the code is already generate or not. If already generate the system create new code and check again. But this logic fails in some case and we cannot able to identify what is the issue is
Here is the code to create the unique code
Integer code = null;
try {
int max = 999999;
int min = 100000;
code = (int) Math.round(Math.random() * (max - min + 1) + min);
PreOrders preObj = null;
preObj = WebServiceDao.getInstance().preOrderObj(code.toString());
if (preObj != null) {
createCode();
}
} catch (Exception e) {
exceptionCaught();
e.printStackTrace();
log.error("Exception in method createCode() - " + e.toString());
}
return code;
}
The function preOrderObj is calling a function to check the code exists in the database if exists return the object. We are using Hibernate to map the database functions and Mysql on the backend.
Here is the function preOrderObj
PreOrders preOrderObj = null;
List<PreOrders> preOrderList = null;
SessionFactory sessionFactory =
(SessionFactory) ServletActionContext.getServletContext().getAttribute(HibernateListener.KEY_NAME);
Session Hibernatesession = sessionFactory.openSession();
try {
Hibernatesession.beginTransaction();
preOrderList = Hibernatesession.createCriteria(PreOrders.class).add(Restrictions.eq("code", code)).list(); // removed .add(Restrictions.eq("status", true))
if (!preOrderList.isEmpty()) {
preOrderObj = (PreOrders) preOrderList.iterator().next();
}
Hibernatesession.getTransaction().commit();
Hibernatesession.flush();
} catch (Exception e) {
Hibernatesession.getTransaction().rollback();
log.debug("This is my debug message.");
log.info("This is my info message.");
log.warn("This is my warn message.");
log.error("This is my error message.");
log.fatal("Fatal error " + e.getStackTrace().toString());
} finally {
Hibernatesession.close();
}
return preOrderObj;
}
Please guide us to identify the issue.
In createCode method, when the random code generated already exist in database, you try to call createCode again. However, the return value from the recursive call is not updated to the code variable, hence the colliding code is still returned and cause error.
To fix the problem, update the method as
...
if (preObj != null) {
//createCode();
code = createCode();
}
...
Such that the code is updated.
By the way, using random number to generate unique value and test uniqueness through query is a bit strange. You may try Auto Increment if you want unique value.
I need to programmatically create a Neo4j DB and then change the initial password. Creating the DB works, but I don't know how to change the password.
String graphDBFilePath = Config.getNeo4jFilesPath_Absolute() + "/" + schemaName; // This is an absolute path. Do not let Neo4j see it.
GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase( new File(graphDBFilePath) ); // See http://neo4j.com/docs/java-reference/current/javadocs/org/neo4j/graphdb/GraphDatabaseService.html
// This transaction works
try (Transaction tx = graphDb.beginTx()) {
Node myNode = graphDb.createNode();
myNode.setProperty( "name", "my node");
tx.success();
}
// This transaction throws an error
Transaction tx = graphDb.beginTx();
try {
graphDb.execute("CALL dbms.changePassword(\'Spoon_XL\')"); // "Invalid attempt to change the password" error
tx.success();
} catch (Exception ex) {
Log.logError("createNewGraphDB() Change Initial Password: " + ex.getLocalizedMessage());
} finally {tx.close(); graphDb.shutdown();}
This may be version dependent (and I don't know what version you are running), but I think the procedure is actually dbms.security.changePassword
Hope this helps,
Tom
This is my first time trying to read and write to a VSAM file. What I did was:
Created a Map for the File using VSE Navigator
Added the Java beans VSE Connector library to my eclipse Java project
Use the code show below to Write and Read to the KSDS file.
Reading the file is not a problem but when I tried to write to the file it only works if I go on the mainframe and close the File before running my java program but it locks the file for like an hour. You cannot open the file on the mainframe or do anything to it.
Anybody can help with this problem. Is there a special setting that I need to set up for the file on the mainframe ? Why do you first need to close the file on CICS to be able to write to it ? And why does it locks the file after writing to it ?
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.*;
public class testVSAM {
public static void main(String argv[]){
Integer test = Integer.valueOf(2893);
String vsamCatalog = "VSESP.USER.CATALOG";
String FlightCluster = "FLIGHT.ORDERING.FLIGHTS";
String FlightMapName = "FLIGHT.TEST2.MAP";
try{
String ipAddr = "10.1.1.1";
String userID = "USER1";
String password = "PASSWORD";
java.sql.Connection jdbcCon;
java.sql.Driver jdbcDriver = (java.sql.Driver) Class.forName(
"com.ibm.vse.jdbc.VsamJdbcDriver").newInstance();
// Build the URL to use to connect
String url = "jdbc:vsam:"+ipAddr;
// Assign properties for the driver
java.util.Properties prop = new java.util.Properties();
prop.put("port", test);
prop.put("user", userID);
prop.put("password", password);
// Connect to the driver
jdbcCon = DriverManager.getConnection(url,prop);
try {
java.sql.PreparedStatement pstmt = jdbcCon.prepareStatement(
"INSERT INTO "+vsamCatalog+"\\"+FlightCluster+"\\"+FlightMapName+
" (RS_SERIAL1,RS_SERIAL2,RS_QTY1,RS_QTY2,RS_UPDATE,RS_UPTIME,RS_EMPNO,RS_PRINTFLAG,"+
"RS_PART_S,RS_PART_IN_A_P,RS_FILLER)"+" VALUES(?,?,?,?,?,?,?,?,?,?,?)");
//pstmt.setString(1, "12345678901234567890123003");
pstmt.setString(1, "1234567890");
pstmt.setString(2,"1234567890123");
pstmt.setInt(3,00);
pstmt.setInt(4,003);
pstmt.setString(5,"151209");
pstmt.setString(6, "094435");
pstmt.setString(7,"09932");
pstmt.setString(8,"P");
pstmt.setString(9,"Y");
pstmt.setString(10,"Y");
pstmt.setString(11," ");
// Execute the query
int num = pstmt.executeUpdate();
System.out.println(num);
pstmt.close();
}
catch (SQLException t)
{
System.out.println(t.toString());
}
try
{
// Get a statement
java.sql.Statement stmt = jdbcCon.createStatement();
// Execute the query ...
java.sql.ResultSet rs = stmt.executeQuery(
"SELECT * FROM "+vsamCatalog+"\\"+FlightCluster+"\\"+FlightMapName);
while (rs.next())
{
System.out.println(rs.getString("RS_SERIAL1") + " " + rs.getString("RS_SERIAL2")+ " " + rs.getString("RS_UPTIME")+ " " + rs.getString("RS_UPDATE"));
}
rs.close();
stmt.close();
}
catch (SQLException t)
{
}
}
catch (Exception e)
{
// do something appropriate with the exception, *at least*:
e.printStackTrace();
}
}
}
Note: the OS is z/VSE
The short answer to your original question is that KSDS VSAM is not a DBMS.
As you have discovered, you can define the VSAM file such that you can update it both from batch and from CICS, but as #BillWoodger points out, you must serialize your updates yourself.
Another approach would be to do all updates from the CICS region, and have your Java application send a REST or SOAP or MQ message to CICS to request its updates. This does require there be a CICS program to catch the requests from the Java application and perform the updates.
The IBM Mainframe under z/VSE has different partitions that run different jobs. For example partition F7 CICS, partition F8 Batch Jobs, ETC.
When you define a new VSAM file you have to set the SHAREOPTIONS of the file. When I define the file I set the SHAREOPTIONS (2 3). 2 Means that only one partition can write to the file.
So when the batch program (in a different partition to the CICS partition) which is called from Java was trying to write to the file it was not able to write to the file unless I close the file in CICS first.
To fix it I REDEFINE the CICS file with SHAREOPTIONS (4 3). 4 Means that multiple partitions of the Mainframe can write to it. Fixing the problem
Below is a part of the definition code where you set the SHAREOPTION:
* $$ JOB JNM=DEFFI,CLASS=9,DISP=D,PRI=9
* $$ LST CLASS=X,DISP=H,PRI=2,REMOTE=0,USER=JAVI
// JOB DEFFI
// EXEC IDCAMS,SIZE=AUTO
DEFINE CLUSTER -
( -
NAME (FLIGHT.ORDERING.FLIGHTS) -
RECORDS (2000 1000) -
INDEXED -
KEYS (26 0) -
RECORDSIZE (128 128) -
SHAREOPTIONS (4 3) -
VOLUMES (SYSWKE) -
) -
.
.
.
I'm trying to connect to SAP ECC 6.0 using JCo. I'm following this tutorial. However, there is a Note saying:
For this example the destination configuration is stored in a file that is called by the program. In practice you should avoid this for security reasons.
And that is reasonable and understood. But, there is no explenation how to set up secure destination provider.
I found solution in this thread that created custom implementation of DestinationDataProvider and that works on my local machine. But when I deploy it on Portal I get an error saying that there is already registered DestinationDataProvider.
So my question is:
How to store destination data in SAP Java EE application?
Here is my code to further clarify what I'm trying to do.
public static void main(String... args) throws JCoException {
CustomDestinationProviderMap provider = new CustomDestinationProviderMap();
com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(provider);
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "host.sap.my.domain.com");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "00");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "100");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "user");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "password");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "en");
provider.addDestination(DESTINATION_NAME1, connectProperties);
connect();
}
public static void connect() throws JCoException {
String FUNCTION_NAME = "BAPI_EMPLOYEE_GETDATA";
JCoDestination destination = JCoDestinationManager.getDestination(DESTINATION_NAME1);
JCoContext.begin(destination);
JCoFunction function = destination.getRepository().getFunction(FUNCTION_NAME);
if (function == null) {
throw new RuntimeException(FUNCTION_NAME + " not found in SAP.");
}
//function.getImportParameterList().setValue("EMPLOYEE_ID", "48");
function.getImportParameterList().setValue("FSTNAME_M", "ANAKIN");
function.getImportParameterList().setValue("LASTNAME_M", "SKYWALKER");
try {
function.execute(destination);
} catch (AbapException e) {
System.out.println(e.toString());
return;
}
JCoTable table = function.getTableParameterList().getTable("PERSONAL_DATA");
for (int i = 0; i < table.getNumRows(); i++) {
table.setRow(i);
System.out.println(table.getString("PERNO") + '\t' + table.getString("FIRSTNAME") + '\t' + table.getString("LAST_NAME")
+'\t' + table.getString("BIRTHDATE")+'\t' + table.getString("GENDER"));
}
JCoContext.end(destination);
}
Ok, so I got this up and going and thought I'd share my research.
You need to add your own destination in Portal. To achieve that you need to go to NetWeaver Administrator, located at: host:port/nwa. So it'll be something like sapportal.your.domain.com:50000/nwa.
Then you go to Configuration-> Infrastructure-> Destinations and add your destination there. You can leave empty most of the fields like Message Server. The important part is Destination name as it is how you will retrieve it and destination type which should be set to RFC Destination in my case. Try pinging your newly created destination to check if its up and going.
Finally you should be able to get destination by simply calling: JCoDestination destination = JCoDestinationManager.getDestination(DESTINATION_NAME); as it is added to your Portal environment and managed from there.
Take a look at the CustomDestinationDataProvider in the JCo examples of the Jco connector download. The important parts are:
static class MyDestinationDataProvider implements DestinationDataProvider
...
com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(new MyDestinationDataProvider());
Then you can simply do:
instance = JCoDestinationManager.getDestination(DESTINATION_NAME);
Btw. you may also want to check out http://hibersap.org/ as they provide nice ways to store the config as well.
I'm new to Birt.
I'm trying to pass the connection to the report from my java application, but I get an error:
The following items have errors:
ReportDesign (id = 1):
+ There are errors evaluating script "importPackage(Packages.it.lfiammetta.birt); var conn = new
ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection",
conn);": Fail to execute script in function __bm_beforeOpen(). Source:
" + importPackage(Packages.it.lfiammetta.birt); var conn = new
ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection",
conn); + "
A BIRT exception occurred. See next exception for more information.
Error evaluating Javascript expression. Script engine error:
ReferenceError: "ReportRenderer" is not defined.
(/report/data-sources/oda-data-source[#id="43"]/method[#name="beforeOpen"]#2)
Script source:
/report/data-sources/oda-data-source[#id="43"]/method[#name="beforeOpen"],
line: 0, text:
__bm_beforeOpen(). (Element ID:1)
This is my java code that creates and launches report:
package it.lfiammetta.birt;
public class ReportRenderer {
public void executeReport() {
code...
Map<String, Object> appContext = task.getAppContext();
appContext.put("OdaJDBCDriverPassInConnection", myConnection);
appContext.put("OdaJDBCDriverPassInConnectionCloseAfterUse", false);
task.setAppContext(appContext);
task.run();
code...
}
}
This is the code I wrote in the script 'beforeOpen' the datasource:
importPackage(Packages.it.lfiammetta.birt);
var conn = new ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection", conn);
I set the classpath.
Birt version I'm using is 4.2.1.
Thanks in advance for your help and I apologize for my English.
I'm doing that from Java code (IJDBCParameters - actually parameters for JDBC connections, I'm looking connection by name - OdaDataSourceHandle.getName()):
#SuppressWarnings("rawtypes")
private static void substituteJDBCConnections(IReportRunnable pReportRunnable) {
final Map<String, IJDBCParameters> jdbcConnections = reportParameters.getJdbcConnections();
if (jdbcConnections != null ){
for (Iterator iter = pReportRunnable.getDesignHandle().getModuleHandle().getDataSources().iterator(); iter.hasNext();){
// http://wiki.eclipse.org/Java_-_Execute_Modified_Report_(BIRT)
Object element = iter.next();
if (element instanceof OdaDataSourceHandle){
OdaDataSourceHandle dsHandle = (OdaDataSourceHandle) element;
String key = dsHandle.getName();
if (key == null){
continue;
}
IJDBCParameters jdbcParams = jdbcConnections.get(key);
if (jdbcParams == null){
continue;
}
try {
dsHandle.setProperty( "odaDriverClass", jdbcParams.getDriverName());
dsHandle.setProperty( "odaURL", jdbcParams.getConnectionString());
dsHandle.setProperty( "odaUser", jdbcParams.getUserName());
dsHandle.setProperty( "odaPassword", jdbcParams.getPassword());
} catch (SemanticException e) {
throw new UncheckedException(e);
}
}
}
}
Probably you fixed your issue already, but maybe someone will be looking for this in the future. First of all 4.2.x versions had problems with passed connections. I did not observed the same errors in 4.4.2.
Other thing, I do not get why you are trying to pass ReportRenderer as a connection in lines:
var conn = new ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection", conn);
The passed object in here should be a java.sql.Connection object.
Therefore,
Map<String, Object> appContext = task.getAppContext();
appContext.put("OdaJDBCDriverPassInConnection", myConnection);
appContext.put("OdaJDBCDriverPassInConnectionCloseAfterUse", false);
task.setAppContext(appContext);
looks correct as long as myConnection is an implementation of java.sql.Connection