I'm trying to get my code to load a picture and save it in DB2. I'm not sure what to do next because the code below is failing. Can someone guide me on how to do this. I have generated an entity from the DB. Datatype for documentname(the actual file) is blob but when I generated the entity it appeared as byte[]. The method below are in the EJB.
#Entity
#Table(name = "DOCUMENTS", schema = "PORTAL")
public class Documents {
private int documentid;
private byte[] documentname;
#Id
#Column(name = "DOCUMENTID", nullable = false)
public int getDocumentid() {
return documentid;
}
public void setDocumentid(int documentid) {
this.documentid = documentid;
}
#Lob
#Basic(fetch = FetchType.LAZY)
#Column(name = "DOCUMENTNAME", nullable = true)
public byte[] getDocumentname() {
return documentname;
}
public void setDocumentname(byte[] documentname) {
this.documentname = documentname;
}
Here I'm trying to read or rather load the picture.
private byte[] readImage(String filename) {
byte[] imageData = null;
FileInputStream file = null;
try {
file = new FileInputStream(filename);
int size = file.available();
imageData = new byte[size];
file.read(imageData);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (file != null) file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return imageData;
}
This is basically where I think I'm loosing it.
public Boolean populateProfilePicture(int blobFileID, byte[] blobFIle) {
Connection con = null;
PreparedStatement pstmt = null;
int success = 0;
String empPhotoFile = "/home/mika/Pictures";
Documents fileTable = new Documents();
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement("INSERT INTO Documents VALUES(?,?)");
pstmt.setInt(1, blobFileID);
pstmt.setBytes(2, readImage(empPhotoFile));
success = pstmt.executeUpdate();
} catch (SQLException e) {
try {
con.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
if (success>=1)
{
return true;
}
return true;
}
byte[] is an appropriate type mapping for BLOB data, though you might want to look into your JPA implementation -- it may have details on how you can influence that mapping to be an InputStream etc. so you can use streaming APIs depending on the size of the files at hand.
That said, since you raw read into a byte array, it seems you might not actually care that much given how you've implemented readData().
Since you're using JPA, one might suggest that you just -- use JPA.
public byte[] readImage(Entity entity String filename) throws Exception {
byte[] imageData = null;
try ( FileInputStream file : file = new FileInputStream(filename) ){
int size = file.available();
imageData = new byte[size];
file.read(imageData);
return imageData;
} catch (IOException | FileNotFoundException e) {
throw e;
}
}
This just does the same thing, but it puts the data in the JPA entity instead of trying to mess with the connection. Should serialise to the database fine when your entity manager commits the unit of work.
EDIT: Here is a re-write of your populate* method as requested. Note that I'm manually managing the transaction, and making a lot of assumptions about your entitymanager. that stuff is a bigger/different question.
public void populateProfilePicture(int blobFileID, String employeePhoto) throws Exception {
// this is about you figuring out JPA.
EntityManager entityManager = getEntityManager()
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin()
try {
Documents documents = entityManager.find(Documents.class, blobFileID);
byte[] data readImage( employeePhoto );
documents.setDocumentname( data );
} catch(Exception e) {
transaction.setRollbackOnly();
throw e
}
} finally {
transaction.commit();
}
}
Related
I have multiple BLOBs that I want to concat to one another, in order to get one joined BLOB. In the process, the contents of the BLOBs may not be stored in memory.
My first idea was to merge the streams like that:
long size = blobs.get(0).length();
InputStream res = blobs.get(0).getBinaryStream();
for (int i = 1; i < blobs.size(); i++){
res = Stream.concat(res, blobs.get(i).getBinaryStream());
size += blobs.get(i).length();
}
Blob blob = Hibernate.getLobCreator(session).createBlob(res, size);
However, this obviously only works with Java 8 streams (not normal BinaryStreams) - and we use Java 7 anways.
My second idea then was to join the BLOBs by directly writing into its stream:
public Blob joinBlobsForHibernate(final Session session, final List<Blob> blobs) throws SQLException {
final LobCreator lc = Hibernate.getLobCreator(session);
final Blob resBlob = lc.createBlob(new byte[0]);
try {
OutputStream stream = resBlob.setBinaryStream(1);
for (final Blob blob : blobs) {
pipeInputStream(blob.getBinaryStream(), stream);
}
return resBlob;
} catch (IOException | SQLException e){
logger.error("Creating the blob threw an exception", e);
return null;
}
}
(pipeInputStream merely pipes the content of one stream into the other:
private void pipeInputStream (final InputStream is, final OutputStream os) throws IOException {
final int buffSize = 128000;
int n;
final byte[] buff = new byte[buffSize];
while ((n = is.read(buff)) >= 0){
os.write(buff, 0, n);
}
)
This however yields in the following exception:
java.lang.UnsupportedOperationException: Blob may not be manipulated from creating session
And besides, I have the suspicion that the BLOB would still temporarily store the whole content in memory.
As a third try I tried using a custom InputStream:
/**
* Combines multiple streams into one
*/
public class JoinedInputStream extends InputStream {
private List<InputStream> parts;
private List<InputStream> marked;
public JoinedInputStream(final List<InputStream> parts) {
this.parts = parts;
}
#Override
public int read() throws IOException {
int res = -1;
while (res == -1 && parts.size() > 0) {
try {
if ((res = parts.get(0).read()) == -1) {
// The stream is done, so we won't try to read from it again
parts.remove(0);
}
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
return res;
}
#Override
public synchronized void reset() throws IOException {
parts = new ArrayList<>(marked);
if (parts.size() > 0) {
parts.get(0).reset();
}
}
#Override
public synchronized void mark(final int readlimit) {
marked = new ArrayList<>(parts);
if (marked.size() > 0)
marked.get(0).mark(readlimit);
}
#Override
public boolean markSupported() {
return true;
}
#Override
public void close() throws IOException {
super.close();
for (final InputStream part : parts) {
part.close();
}
parts = new ArrayList<>();
marked = new ArrayList<>();
}
}
The BLOB could then be joined like that (don't mind the unnecessary functions, they have other uses):
#Override
public Blob createBlobForHibernate(final Session session, final InputStream stream, final long length) {
final LobCreator lc = Hibernate.getLobCreator(session);
return lc.createBlob(stream, length);
}
#Override
public Blob createBlobForHibernate(final Session session, final List<InputStream> streams, final long length) {
final InputStream joined = new JoinedInputStream(streams);
return createBlobForHibernate(session, joined, length);
}
#Override
public Blob joinBlobsForHibernate(final Session session, final List<Blob> blobs) throws SQLException {
long length = 0;
List<InputStream> streams = new ArrayList<>(blobs.size());
for (final Blob blob : blobs) {
length += blob.length();
streams.add(blob.getBinaryStream());
}
return createBlobForHibernate(session, streams, length);
}
However, this results in the following error (when persisting the newly created entity with the joined BLOB):
Caused by: java.sql.SQLException: LOB-Lese-/Schreibfunktionen aufgerufen, während ein anderer Lese-/Schreibvorgang ausgeführt wird: getBytes()
at oracle.jdbc.driver.T4CConnection.getBytes(T4CConnection.java:3200)
at oracle.sql.BLOB.getBytes(BLOB.java:391)
at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:166)
... 101 more
Or in English:
Lob read/write functions called while another read/write is in progress: getBytes()
I already tried setting hibernate.temp.use_jdbc_metadata_defaults to false (as suggested in this post) - in fact, we already had this property set beforehand and it didn't help.
So guys i need some help. I have a class Book and i want to save my books object to a Stream and then read this Stream file so i can search my objects from there. I have written my code but it gives me some errors and i can figure out how to print my books values .
So this is my Book class
public class Book {
private Date arr;
private Date depp;
private Type room;
private boolean breakfast = false;
private Person data;
private ObjectOutputStream out;
public Book(String name, String surename, String phone,Date arr, Date depp, Type room, boolean breakfast) {
data = new Person(name,surename,phone);
this.arr = arr;
this.depp = depp;
this.room = room;
this.breakfast = breakfast;
}
public void writeObjToFile(){//here i save my object to stream it gives me error, i call this method after i create my book object to main
try{
out = new ObjectOutputStream(new FileOutputStream("books.txt"));
out.writeObject(this);
}
catch(FileNotFoundException e){
System.err.println("File not Found");
e.printStackTrace();
}catch(IOException e){
System.err.println("IOException");
e.printStackTrace();}
}
}
and this is my Search class :
public class Search {
private FileInputStream fis=null;
private String filename;
public Search(String filename){
this.filename = filename;
File file = new File(filename);
try {
fis = new FileInputStream(file);
System.out.println("Total file size to read (in bytes) : "
+ fis.available());
int content;
while ((content = fis.read()) != -1) {
// convert to char and display it
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Book should implement Serializable
Check the API
https://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html#writeObject%28java.lang.Object%29
Also, remove the out member from Book class because it's not Serializable either.
I use serialization to save some objects into Oracle Blob columns which I then extract and use in the same run or in other runs.
The serialization/deserialization looks like this:
public final class BytesTransformer {
static BytesTransformer btInstance = new BytesTransformer();
private ByteArrayOutputStream bytesOutputStream = new ByteArrayOutputStream();
private ObjectOutputStream objectOutputStream;
private ByteArrayInputStream bytesInputStream;
private ObjectInputStream objectInputStream;
public static BytesTransformer getInstance() {
return btInstance;
}
private void initialiseInputStreams(byte[] bytes) throws IOException {
bytesInputStream = new ByteArrayInputStream(bytes);
objectInputStream = new ObjectInputStream(bytesInputStream);
}
private void initialiseInputStreams(InputStream bytes) throws IOException {
objectInputStream = new ObjectInputStream(bytes);
}
public byte[] getBytes(Serializable sObject) throws IOException {
bytesOutputStream.reset();
objectOutputStream = new ObjectOutputStream(bytesOutputStream);
objectOutputStream.writeObject(sObject);
objectOutputStream.close();
return bytesOutputStream.toByteArray();
}
public Object fromBytes(byte[] dataBytes) throws IOException, ClassNotFoundException {
initialiseInputStreams(dataBytes);
Object sObject = objectInputStream.readObject();
closeInputStreams();
return sObject;
}
public Object fromBytes(InputStream dataBytes) throws IOException, ClassNotFoundException {
initialiseInputStreams(dataBytes);
Object sObject = objectInputStream.readObject();
closeInputStreams();
return sObject;
}
private void closeInputStreams() {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (bytesInputStream != null) {
bytesInputStream.close();
}
} catch (IOException ex) {
}
}
To write data to the blob column I use something like this:
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE CONFIGURATION_DEFINITION SET BYTES_DATA=? WHERE NAME=?", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
preparedStatement.setObject(1, BytesTransformer.getInstance().getBytes(cfgDef));
preparedStatement.setString(2, cfgDef.getName());
preparedStatement.executeUpdate();
To retrieve the data:
public ConfigurationDefinition getConfigurationDefinition(String configName) {
byte[] bytes = null;
String sql = "SELECT BYTES_DATA FROM CONFIGURATION_DEFINITION WHERE NAME = '" + configName + "'";
ResultSet rs = getSQLConnector().executeQueryWithoutNoise(sql);
try {
if (rs == null || !rs.next()) {
return null;
}
Blob blob = rs.getBlob(blobColumnName);
bytes = blob.getBytes(1, (int) blob.length());
} catch (SQLException ex) {
GatewayLogger.error("Unable to extract db records for configuration: " + configName, ex);
return null;
} finally {
getSQLConnector().closeResultSet(rs);
}
ConfigurationDefinition aDefinition = (ConfigurationDefinition) BytesTransformer.getInstance().fromBytes(buffer);
return aDefinition;
}
Most of the time there is no problem, but sometimes (quite rarely) and seemingly with no discernable pattern I get either:
java.io.StreamCorruptedException: invalid type code: <first_byte>
or
java.io.StreamCorruptedException: invalid stream header: <first_four_bytes>
When I get the second error I can usually find the correct header starting a few hundred bytes into the vector.
I should mention that the Oracle schema also holds some AQ JMS Queues which I use to send similarly serialized objects through and on a couple of occasions objects of those types were retrieved from the Oracle table even though there is no way that those two could get mixed up in the code.
I've looked around at discussions about those exceptions and nothing seems to apply to my case. Everything looks to be in order as far as I can tell and the exceptions only pop up very rarely.
Any ideas?
I have to write some dao tests for project where I want to:
create DDL schema from database (MySQL);
create tables in another test database in memory (H2);
insеrt some data to database;
select the just inserted item;
check some data from this item.
This is my test:
public class BridgeDBTest {
private static String JDBC_DRIVER;
private static String JDBC_URL;
private static String USER;
private static String PSWD;
private static final Logger logger = LoggerFactory.getLogger(BridgeDBTest.class);
#BeforeGroups(groups = "bridgeDB")
public void init(){
try {
JDBC_DRIVER = org.h2.Driver.class.getName();
JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";
USER = "root";
PSWD = "";
new HibernateTestUtil().setDialect("org.hibernate.dialect.HSQLDialect")
.translateCreateDllToOutputStream(new FileOutputStream(new File("src/test/resources/createSchema.sql")));
RunScript.execute(JDBC_URL, USER, PSWD, "src/test/resources/createSchema.sql", Charset.forName("UTF8"), false);
insertDataset(readDataSet());
}
catch (Exception expt) {
expt.printStackTrace();
logger.error("!!!" + expt);
throw new RuntimeException(expt.getMessage());
}
}
#Test(groups = "bridgeDB")
public void getItem(){
BridgeDAOImpl dao = new BridgeDAOImpl();
dao.setSessionFactory(new HibernateTestUtil().getSessionFactory());
try {
Bridge bridge = dao.get(1L);
assert(bridge.getName().equals("TEST-CN-DEVBOX01"));
} catch (ServiceException e) {
e.printStackTrace();
}
}
#AfterGroups(groups = "bridgeDB")
public void dropTables(){
try {
new HibernateTestUtil().setDialect("org.hibernate.dialect.HSQLDialect")
.translateDropDllToOutputStream(new FileOutputStream(new File("src/test/resources/dropSchema.sql")));
}
catch (Exception expt) {
expt.printStackTrace();
logger.error("!!!" + expt);
throw new RuntimeException(expt.getMessage());
}
}
private IDataSet readDataSet() throws Exception{
return new FlatXmlDataSetBuilder().build(new File("src/test/resources/datasetForTest.xml"));
}
private void insertDataset(IDataSet dataSet) throws Exception{
IDatabaseTester databaseTester = new JdbcDatabaseTester(JDBC_DRIVER, JDBC_URL, USER, PSWD);
databaseTester.setSetUpOperation(DatabaseOperation.CLEAN_INSERT);
databaseTester.setDataSet(dataSet);
databaseTester.onSetup();
}
}
BridgeDAOImplused class HibernateUtilfrom src/main/..., but I need to use my class HibernateTestUtil from src/test/.... It's modified HibernateUtil fitted for my test (there I set parameters for Configuration class).
BridgeDAOImpl (See 5 line in try block):
public class BridgeDAOImpl extends GenericDAOImpl<Bridge, Long> implements BridgeDAO {
//...
public SearchResult<Bridge> list(int from, int limit, String filter, String order, Long authId) throws ServiceException {
SearchResult<Bridge> results = null;
Search search = new Search(Bridge.class);
Session session = getSessionFactory().getCurrentSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
search.setFirstResult(from);
search.setMaxResults(limit);
HibernateUtil.buildSearch(filter, order, search, aliases);
results = searchAndCount(search);
transaction.commit();
}
catch (Exception expt) {
logger.error("!!!", expt);
if (transaction != null) {
transaction.rollback();
}
throw new ServiceException(expt.getMessage());
}
finally {
// session.close();
}
return results;
}
//...
}
How I can test my dao without modifying it?
i need to retrieve data from sqlite .and retrieved data should be displayed in a gridfieldmanager layout.i have done the below code please help me how to display data from database over the myscreen.
SQLManager screen
public class SQLManager {
static String snapsdata;
private static String DB_NAME = "employee_details.db3";
private Database _db;
public SQLManager() throws Exception {
// Determine if an SDCard is present
boolean sdCardPresent = false;
String root = null;
Enumeration e = FileSystemRegistry.listRoots();
while (e.hasMoreElements()) {
root = (String) e.nextElement();
if (root.equalsIgnoreCase("sdcard/")) {
sdCardPresent = true;
}
}
if (!sdCardPresent) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("This application requires an SD card to be
present.");
System.exit(0);
}
});
} else {
String dbLocation = "/SDCard/databases/sample/";
// Create URI
URI uri = URI.create(dbLocation + DB_NAME);
// Open or create a plain text database. This will create the
// directory and file defined by the URI (if they do not already
// exist).
Database db = DatabaseFactory.openOrCreate(uri,
new DatabaseSecurityOptions(false));
// Close the database in case it is blank and we need to write to
// the file
db.close();
//Dialog.alert("db");
// Open a connection to the database file
FileConnection fileConnection = (FileConnection) Connector
.open("file://" + dbLocation + DB_NAME);
// If the file is blank, copy the pre-defined database from this
// module to the SDCard.
if (fileConnection.exists() && fileConnection.fileSize() == 0) {
readAndWriteDatabaseFile(fileConnection);
//Dialog.alert("db1");
}
// Open the database
db = DatabaseFactory.open(uri);
_db = db;
}
}
/**
* Copies the pre-defined database from this module to the location
* specified by the fileConnection argument.
*
* #param fileConnection
* File connection to the database location
*/
public void readAndWriteDatabaseFile(FileConnection fileConnection)
throws IOException {
OutputStream outputStream = null;
InputStream inputStream = null;
// Open an input stream to the pre-defined encrypted database bundled
// within this module.
inputStream = getClass().getResourceAsStream("/" + DB_NAME);
//Dialog.alert("db" + inputStream);
// Open an output stream to the newly created file
outputStream = (OutputStream) fileConnection.openOutputStream();
// Read data from the input stream and write the data to the
// output stream.
byte[] data = new byte[1024 * 5];
int length = 0;
while (-1 != (length = inputStream.read(data))) {
outputStream.write(data, 0, length);
}
// Close the connections
if (fileConnection != null) {
fileConnection.close();
}
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}
/**
* Constructs a new SQLManager object
*
* #param db
* Database to manage
*/
public SQLManager(Database db) {
_db = db;
}
/**
* Closes the database
*/
void closeDB() {
try {
_db.close();
} catch (DatabaseException dbe) {
}
}
public void SaveEmployeeInformation(int employeeid, String employee_name,
String position, int salary){
//return productinfo;
Statement st;
try {
st = _db.createStatement("INSERT INTO
employee_details(employee_id,employee_name,position,salary) VALUES (?, ?,
?, ?)");
try
{
st.prepare();
Object[] bindParams = {new Integer(employeeid), new
String(employee_name), new String(position), new Integer(salary)};
long rowID = st.executeInsert(bindParams);
// Dialog.alert("ro "+rowID);
}
finally
{
st.close();
closeDB();
}
} catch (DatabaseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Vector getEmployeeInformation(){
Vector productinfo = new Vector();
try {
Statement statement = null;
// Read in all records from the Category table
statement = _db
.createStatement("select MAX(employee_id) as
employeeReportId from employee_details");
// ProjectImagesID Project_id,ImagePath,ImageDescription
statement.prepare();
// statement.setCursorBufferSize(10);
Cursor cursor = statement.getCursor();
Employeelist productdatas;
Row row;
// Iterate through the result set. For each row, create a new
// Category object and add it to the hash table.
while (cursor.next()) {
row = cursor.getRow();
productdatas = new Employeelist(row.getInteger(0));
productinfo.addElement(productdatas);
}
// Dialog.alert(""+productinfo.size());
statement.close();
cursor.close();
} catch (DatabaseException dbe) {
Dialog.alert("SD PRODUCTINFP " + dbe.toString());
} catch (DataTypeException e) {
Dialog.alert("PRODUCTINFP " + e.toString());
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
closeDB();
}
return productinfo;
}
}
myscreen screen
public final class MyScreen extends MainScreen
{
/**
* Creates a new MyScreen object
*/
public MyScreen()
{
// Set the displayed title of the screen
setTitle("MyTitle");
// int reportid = 0;
try {
SQLManager emp = new SQLManager();
emp.SaveEmployeeInformation(7,"farah","developer", 4000);
emp.getEmployeeInformation();
} catch (Exception e)
{// TODO Auto-generated catch block
e.printStackTrace();
}
int row = 5;
GridFieldManager dfm = new GridFieldManager(row,3, 0);
add(dfm);
}
}
First try to acheive the successul set up and retreiving of data from SQlite Db. .Then with retrieved data,try to use it in grid field Manager.
Please write exact problem in code which helps us to solvethe problem.