I'm investigating concurrency when doing multiple queries in different threads.
I am using Apache DBCP and DBUtils not because I want to complicate my life but because they should guarantee that the queries are handled correctly and so the concurrency.
However even with the above cool tools I get a:
Error : org.h2.jdbc.JdbcSQLException: Das Objekt wurde bereits geschlossen
The object is already closed [90007-148]
Error : java.lang.NullPointerException
Which is the same kind of error I got also when using Database and Connection objects by hand.
It happens one time every 5-6 runs of the program, but this is just a toy program, in a real world application this kind of errors would pop up continuously.
Below my example code
DatatTransaction.java
import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;
public class DataTransaction
{
private final static String username = "";
private final static String password = "";
private final static String url = "db" + File.separator + "persondb;create=true";
public static Connection connection = null;
public static BasicDataSource dataSource;
public DataTransaction(boolean setCon)
{
try
{
setConnectionTest();
}
catch (Exception e)
{
System.out.println("Error in Connection:" + e.toString());
}
}
public final void setConnectionTest() throws SQLException
{
try
{
if (dataSource == null)
{
dataSource = new BasicDataSource();
String driver = "org.h2.Driver";
try
{
dataSource.setDriverClassName(driver);
dataSource.setUrl("jdbc:h2:"+url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaxActive(100);
dataSource.setMaxWait(10000);
dataSource.setMaxIdle(10);
if (connection == null || connection.isClosed())
{
connection = dataSource.getConnection();
}
}
catch (SQLException e)
{
System.out.println("Could not connect to the database msg :" + e.getMessage());
}
}
else
{
connection = dataSource.getConnection();
}
}
catch (Exception e)
{
System.out.println("open connection exception" + e);
}
}
}
and DBTest2.java
package dbtest;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class DBTest2
{
public static void main(String[] args)
{
try
{
new Thread(db1).start();
new Thread(db2).start();
}
catch (Exception e)
{
System.out.println("MM : Error : " + e);
}
}
private static Runnable db1 = new Runnable()
{
public void run()
{
try
{
for (int i = 0; i < 50; i++)
{
DBTest2 dBTest = new DBTest2();
List<Object[]> list1 = dBTest.DB1();
for (Object[] object : list1)
{
System.out.println("DB1 : FirstName : " + object[0] + " Lastname: " + object[1]);
}
}
}
catch (Exception e)
{
System.out.println("Error : " + e);
}
}
};
private static Runnable db2 = new Runnable()
{
public void run()
{
try
{
for (int i = 0; i < 50; i++)
{
DBTest2 dBTest = new DBTest2();
List<Object[]> list = dBTest.DB2();
for (Object[] object : list)
{
System.out.println("DB2 : FirstName : " + object[0] + " Lastname: " + object[1]);
}
}
}
catch (Exception e)
{
System.out.println("Error : " + e);
}
}
};
public List<Object[]> DB1()
{
try
{
DataTransaction dt = new DataTransaction(true);
Connection conn = dt.connection;
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("select NAME,SURNAME from PERSON");
ResultSetMetaData rsmd = rs.getMetaData();
int dataCnt = rsmd.getColumnCount();
List<Object[]> list = new ArrayList<Object[]>();
while (rs.next())
{
Object[] data = new Object[dataCnt];
for (int i = 0; i < dataCnt; i++)
{
data[i] = rs.getString(i + 1);
}
list.add(data);
}
conn.close();
return list;
}
catch (Exception e)
{
System.out.println("Error : " + e);
return null;
}
}
public List<Object[]> DB2()
{
try
{
DataTransaction dt = new DataTransaction(true);
Connection conn = dt.connection;
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("select NAME,SURNAME from PERSON");
ResultSetMetaData rsmd = rs.getMetaData();
int dataCnt = rsmd.getColumnCount();
List<Object[]> list = new ArrayList<Object[]>();
while (rs.next())
{
Object[] data = new Object[dataCnt];
for (int i = 0; i < dataCnt; i++)
{
data[i] = rs.getString(i + 1);
}
list.add(data);
}
conn.close();
return list;
}
catch (Exception e)
{
System.out.println("Error : " + e);
return null;
}
}
}
You should have a read of derby pitfalls in it there are some common pitfalls, the one you are interested in is:
"Executing a Statement automatically closes any existing open ResultSet generated by an earlier execution of that Statement. If threads share Statements, one thread could close another's ResultSet. In many cases, it is easier to assign each thread to a distinct Connection. "
Ok so the problem with your code is DatatTransaction.java, change the code by removing the static variable connection and add this method:
public final Connection getConnection()
{
Connection conn = null;
try
{
conn = dataSource.getConnection();
}
catch (SQLException e)
{
System.out.println("Could not connect to the database msg :" + e.getMessage());
}
return conn;
}
Now it will no longer give any problem (by the way, if you comment the System.out.println() in your example you will see more quickly and more often the concurrency errors which are otherwise mitigated by the time needed to print to the console).
As for the "exceptionorg.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object " that's because you are not closing the resources correctly by commenting the close() methods, so you quickly run out of connections in the pool.
Related
In the below Java code, I am trying to create a synchronized List from normal ArrayList and then performing the multithreading operation but still it gives ConcurrentModificationException. Can someone tell me what is wrong here?
package Concurrent_Collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
*
* #author Nitesh Agrawal
*
*/
public class DemoForConcurrentModificationException extends Thread {
static List<Integer> myList = new ArrayList<Integer>();
static List<Integer> synchronizedList;
public static void main(String[] args) {
System.out.println("Main Thread");
synchronizedList = Collections.synchronizedList(myList);
for (int i = 0; i < 10; i++) {
synchronizedList.add(i);
}
DemoForConcurrentModificationException t = new DemoForConcurrentModificationException();
t.start();
for (Integer k : synchronizedList) {
System.out.println("Main");
System.out.println(k);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
System.out.println("Child Thread");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronizedList.add(100);
}
}
public class testUtil {
static Sheet sheet;
static Workbook book;
public static String TESTDATA_SHEET_PATH = "C:\Users\Admin\eclipse-workspace\ExcellReader\src\main\java\testData\LoginTest.xlsx";
public static Object[][] getTestData(String Sheetname) {
FileInputStream file = null;
try {
file = new FileInputStream(TESTDATA_SHEET_PATH);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
book = WorkbookFactory.create(file);
} catch (EncryptedDocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sheet = book.getSheet(Sheetname);
Object[][] data = new Object[sheet.getLastRowNum()][sheet.getRow(0).getLastCellNum()];
for (int i = 0; i < sheet.getLastRowNum(); i++) {
for (int k = 0; k < sheet.getRow(0).getLastCellNum(); k++) {
data[i][k] = sheet.getRow(i + 1).getCell(k).toString();
System.out.println(data[i][k]);
}
}
return data;
} }
List item
I have a web application that stores documents on the server. In some cases I need to place certain permissions per the user groups as they are stored in Active Directory.
I've setup a web service hosted in a Windows service on the server, and the server is making contact with this web service to get the data.
When I call the methods from a regular console application, everything works great, and also if I call the web service when hosted locally on my computer in a Windows service, everything works great as well.
The problem only occurs when on the server - my guess is that when no one is logged on to the server.
Edit: The user is found (I think) and I get "No groups found" as a result.
===========
Another Edit: I updated the code with further work I'm trying.
After many experiments method2 does not fit at all.
Method2 requires me to do logon to the system with the user I want to check in order to get his groups. This is something that cannot be done as I don't have that user password.
I believe the two other methods (1 & 3) are not working due to something with the network structure and will have to talk to my boss about it. I will update again if I have some progress.
===========
Here is a link to a C# code I use to get the groups, 3 different methods - none of them work.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class ActiveDirectoryService : System.Web.Services.WebService
{
[WebMethod]
public string GetGroups1(string endUsername)
{
string result;
try
{
var list = new List<string>();
var domain = ConfigurationManager.AppSettings["Domain"];
var serviceUsername = ConfigurationManager.AppSettings["Username"];
var password = ConfigurationManager.AppSettings["Password"];
var context = new PrincipalContext(ContextType.Domain, domain, serviceUsername, password);
var userPrincipal = UserPrincipal.FindByIdentity(context, endUsername);
if (userPrincipal == null)
{
return "Failed to find user: " + endUsername;
}
var authorizationGroups = userPrincipal.GetAuthorizationGroups();
WriteToLogDebug("GetGroups1.authorizationGroups.Count: " + authorizationGroups.Count());
foreach (var current in authorizationGroups)
{
if (current is GroupPrincipal)
{
var groupPrincipal = current as GroupPrincipal;
var groupPrincipalName = groupPrincipal?.Name;
if (!string.IsNullOrWhiteSpace(groupPrincipalName))
{
list.Add(groupPrincipalName);
}
}
}
if (!list.Any())
{
result = "No groups found for user " + endUsername;
}
else
{
result = string.Join(" & ", list);
}
}
catch (Exception ex)
{
result = "Failed to get groups for user " + endUsername + ": " + ex.Message;
WriteToLogException("GetGroups1." + ex.Message);
}
return result;
}
[WebMethod]
public string GetGroups2(string endUsername)
{
string result;
var serviceUsername = ConfigurationManager.AppSettings["Username"];
try
{
var list = new List<string>();
IntPtr token = GetLogonUserToken();
if (token == default(IntPtr))
{
return "Failed to logon user: " + serviceUsername;
}
var windowsIdentity = new WindowsIdentity(token);
WriteToLogDebug("GetGroups2.windowsIdentity.Groups.Count: " + windowsIdentity.Groups.Count());
foreach (var current in windowsIdentity.Groups)
{
try
{
list.Add(current.Translate(typeof(NTAccount)).ToString());
}
catch (Exception ex)
{
WriteToLogException("GetGroups2." + ex.Message);
}
}
if (!list.Any())
{
result = "No groups found for user " + serviceUsername;
}
else
{
result = string.Join(" & ", list);
}
}
catch (Exception ex)
{
result = "Failed to get groups for user " + serviceUsername + ": " + ex.Message;
WriteToLogException("GetGroups2." + ex.Message);
}
return result;
}
[WebMethod]
public string GetGroups3(string endUsername)
{
var result = "No groups found";
try
{
var directoryEntry = GetDirectoryEntry();
if (directoryEntry == null)
{
result = "DirectoryEntry returned null";
}
else
{
var list = new List<string>();
var directorySearcher = new DirectorySearcher(directoryEntry)
{
Filter = "(&(sAMAccountName=" + endUsername + "))"
};
if (directorySearcher == null)
{
WriteToLogDebug("GetGroups3.(directorySearcher == null): " + (directorySearcher == null));
return "Failed to initiate directorySearcher";
}
SearchResultCollection searchResultCollection = null;
try
{
searchResultCollection = directorySearcher.FindAll();
if (searchResultCollection == null)
{
WriteToLogDebug("GetGroups3.(searchResultCollection == null): " + (searchResultCollection == null));
return "Failed to find user: " + endUsername;
}
}
catch (Exception ex)
{
WriteToLogException("GetGroups3.Failed: " + ex.Message);
return "Failed to find user " + endUsername + ": " + ex.Message;
}
if (searchResultCollection.Count == 0)
{
result = "No groups found for user " + endUsername;
}
else
{
WriteToLogDebug("GetGroups3.searchResultCollection.Count: " + searchResultCollection.Count);
foreach (var current in searchResultCollection)
{
var searchResult = current as SearchResult;
foreach (var group in searchResult?.Properties["memberOf"])
{
if (group != null)
list.Add(group.ToString());
}
}
result = string.Join(" & ", list);
}
}
}
catch (Exception ex)
{
result = "Failed to get groups for user " + endUsername + ": " + ex.Message;
WriteToLogException("GetGroups3.Failed: " + ex.Message);
}
return result;
}
private IntPtr GetLogonUserToken()
{
try
{
var LOGON32_LOGON_INTERACTIVE = 2;
//var LOGON32_LOGON_NETWORK = 3;
//var LOGON32_LOGON_BATCH = 4;
//var LOGON32_LOGON_SERVICE = 5;
//var LOGON32_LOGON_UNLOCK = 7;
//var LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
//var LOGON32_LOGON_NEW_CREDENTIALS = 9;
var LOGON32_PROVIDER_DEFAULT = 0;
var domain = ConfigurationManager.AppSettings["Domain"];
WriteToLogDebug("GetLogonUserToken.domain: " + domain);
var serviceUsername = ConfigurationManager.AppSettings["Username"];
WriteToLogDebug("GetLogonUserToken.serviceUsername: " + serviceUsername);
var password = ConfigurationManager.AppSettings["Password"];
WriteToLogDebug("GetLogonUserToken.password: " + password);
LogonUser(serviceUsername, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out IntPtr token);
return token;
}
catch (Exception ex)
{
WriteToLogException("GetLogonUserToken.Failed" + ex.Message);
}
return default(IntPtr);
}
private DirectoryEntry GetDirectoryEntry()
{
DirectoryEntry result;
try
{
var domain = ConfigurationManager.AppSettings["Domain"];
WriteToLogDebug("GetDirectoryEntry.domain: " + domain);
var serviceUsername = ConfigurationManager.AppSettings["Username"];
WriteToLogDebug("GetDirectoryEntry.serviceUsername: " + serviceUsername);
var password = ConfigurationManager.AppSettings["Password"];
WriteToLogDebug("GetDirectoryEntry.password: " + password);
result = new DirectoryEntry
{
Username = serviceUsername,
Password = password,
Path = "LDAP://" + domain
};
}
catch (Exception ex)
{
result = null;
WriteToLogException("GetDirectoryEntry.Failed: " + ex.Message);
}
return result;
}
Any suggestions how to get a user groups from a web service hosted by a windows service?
Thanks
At the end it was indeed a network block, after changing the domain used I managed to get the end users and their groups.
Thank you all for the help.
I try to re - transmit sse from an osgi plugin . I have this code and at the moment i can only read the sse from event source and print it out in the console correctly. The sse write part is not working properly and buffering instead. Is there any way to fix it and read and write from the same function?
Thanks in advance!
#ApplicationPath("MySensor")
public class MySensor extends ResourceConfig {
private static String sensorA = "smotion";
// private static String sensorB = "sdist";
// private static String sensorC = "slight";
private int id = 0;
private String idn = "";
public MySensor() {
super(MySensor.class, SseFeature.class);
}
// creates new broadcaster
private static SseBroadcaster BROADCASTER = new SseBroadcaster();
#MethodDescription(value = "sse")
#GET
#Consumes(SseFeature.SERVER_SENT_EVENTS)
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getServerSentEvents() {
id = id + 1;
idn = sensorA + " " + id;
BROADCASTER.broadcast(new OutboundEvent.Builder().data(String.class, idn).build());
// System.out.println(BROADCASTER.);
String LocalNetworkIP = "192.168.1.134";
EventOutput eventOutput = new EventOutput();
Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
WebTarget target = client.target("http://" + LocalNetworkIP + "/" + sensorA);
EventInput eventInput = target.request().get(EventInput.class);
while (!eventInput.isClosed()) {
InboundEvent inboundEvent = eventInput.read();
if (inboundEvent == null) {
break; // connection has been closed
}
try {
// handleevent
// inboundEvent.readData(String.class);
System.out.println(inboundEvent.readData(String.class));
OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
eventBuilder.name(inboundEvent.getName());
eventBuilder.data(inboundEvent.readData(String.class));
OutboundEvent event = eventBuilder.build();
eventOutput.write(event);
BROADCASTER.add(eventOutput);
} catch (IOException e) {
throw new RuntimeException("Error when writing the event.", e);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
try {
eventOutput.close();
} catch (IOException ioClose) {
throw new RuntimeException("Error when closing the event output.", ioClose);
}
return eventOutput;
}
I Finally find it out!
#MethodDescription(value = "Return the Server Sent Event")
#GET
#Consumes(SseFeature.SERVER_SENT_EVENTS)
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getServerSentEvents() {
id = id + 1;
idn = sensorA + " " + id;
final EventOutput eventOutput = new EventOutput();
Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
WebTarget target = client.target("http://" + LocalNetworkIP + "/" + sensorA);
final EventInput eventInput = target.request().get(EventInput.class);
new Thread(new Runnable() {
#Override
public synchronized void run() {
try {
while (!eventInput.isClosed()) {
// Thread.sleep(500);
InboundEvent inboundEvent = eventInput.read();
if (inboundEvent == null) {
break; // connection has been closed
}
try {
// handleevent
// inboundEvent.readData(String.class);
System.out.println(inboundEvent.readData(String.class));
OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
eventBuilder.name(inboundEvent.getName());
eventBuilder.data(inboundEvent.readData(String.class));
OutboundEvent event = eventBuilder.build();
eventOutput.write(event);
} catch (IOException e) {
try { //extra
eventOutput.close(); //extra
eventInput.close(); //extra
} catch (IOException ioClose) { //extra
throw new RuntimeException("Error when closing the event output internal.", ioClose); //extra
} //extra
throw new RuntimeException("Error when writing or reading the event.", e);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (!eventOutput.isClosed()) { //extra
eventOutput.close(); //extra
} //extra
if (!eventInput.isClosed()) { //extra
eventInput.close();
} //extra
} catch (IOException ioClose) {
throw new RuntimeException("Error when closing the event output.", ioClose);
}
}
}
}).start();
return eventOutput;
}
}
I am using Apache Thrift TSimpleServer in my C++ projects. Once started, the server will be listening to clients connection and handling requests. All are fine, but occasionally the server stopped without any sign.
I follow the source of thrift library and can see the GlobalOutput(error_message) being created when TTransportException or TException are caught. I need to understand this so that I can create a recovery mechanism when the server dies.
Here is the source code I am talking about:
void TSimpleServer::serve() {
shared_ptr<TTransport> client;
shared_ptr<TTransport> inputTransport;
shared_ptr<TTransport> outputTransport;
shared_ptr<TProtocol> inputProtocol;
shared_ptr<TProtocol> outputProtocol;
// Start the server listening
serverTransport_->listen();
// Run the preServe event
if (eventHandler_) {
eventHandler_->preServe();
}
// Fetch client from server
while (!stop_) {
try {
client = serverTransport_->accept();
inputTransport = inputTransportFactory_->getTransport(client);
outputTransport = outputTransportFactory_->getTransport(client);
inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
} catch (TTransportException& ttx) {
if (inputTransport) { inputTransport->close(); }
if (outputTransport) { outputTransport->close(); }
if (client) { client->close(); }
if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
string errStr = string("TServerTransport died on accept: ") + ttx.what();
GlobalOutput(errStr.c_str());
}
continue;
} catch (TException& tx) {
if (inputTransport) { inputTransport->close(); }
if (outputTransport) { outputTransport->close(); }
if (client) { client->close(); }
string errStr = string("Some kind of accept exception: ") + tx.what();
GlobalOutput(errStr.c_str());
continue;
} catch (string s) {
if (inputTransport) { inputTransport->close(); }
if (outputTransport) { outputTransport->close(); }
if (client) { client->close(); }
string errStr = string("Some kind of accept exception: ") + s;
GlobalOutput(errStr.c_str());
break;
}
// Get the processor
shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
outputProtocol, client);
void* connectionContext = NULL;
if (eventHandler_) {
connectionContext = eventHandler_->createContext(inputProtocol, outputProtocol);
}
try {
for (;;) {
if (eventHandler_) {
eventHandler_->processContext(connectionContext, client);
}
if (!processor->process(inputProtocol, outputProtocol,
connectionContext) ||
// Peek ahead, is the remote side closed?
!inputProtocol->getTransport()->peek()) {
break;
}
}
} catch (const TTransportException& ttx) {
string errStr = string("TSimpleServer client died: ") + ttx.what();
GlobalOutput(errStr.c_str());
} catch (const std::exception& x) {
GlobalOutput.printf("TSimpleServer exception: %s: %s",
typeid(x).name(), x.what());
} catch (...) {
GlobalOutput("TSimpleServer uncaught exception.");
}
if (eventHandler_) {
eventHandler_->deleteContext(connectionContext, inputProtocol, outputProtocol);
}
try {
inputTransport->close();
} catch (const TTransportException& ttx) {
string errStr = string("TSimpleServer input close failed: ")
+ ttx.what();
GlobalOutput(errStr.c_str());
}
try {
outputTransport->close();
} catch (const TTransportException& ttx) {
string errStr = string("TSimpleServer output close failed: ")
+ ttx.what();
GlobalOutput(errStr.c_str());
}
try {
client->close();
} catch (const TTransportException& ttx) {
string errStr = string("TSimpleServer client close failed: ")
+ ttx.what();
GlobalOutput(errStr.c_str());
}
}
if (stop_) {
try {
serverTransport_->close();
} catch (TTransportException &ttx) {
string errStr = string("TServerTransport failed on close: ") + ttx.what();
GlobalOutput(errStr.c_str());
}
stop_ = false;
}
}
Deep inside TOutput.cpp there's line fprintf(stderr, "Thrift: %s %s\n", dbgtime, msg); (source here) and that's where by default all Thrift GlobalOutput messages end up (in standard error).
But you can change it (if for any reason you can't use stderr) by providing own handler to GlobalOutput in form of function pointer:
void myOutputFunction(const char* x)
{
fprintf(myLogFile, "Thrift internal message: %s\n", x);
}
// Inside some init function or main
GlobalOutput.setOutputFunction(myOutputFunction);