I am trying to delete a node in Alfresco(CE, v. 2.1) permanently(without moving it to trash can first) using web service.
My use case is this: create a standalone job that queries the repo for files older than 2 years and delete them permanently using web service. Then the cleanup job moves the deleted files to content.deleted which I can safely delete.
Below is my code
import org.alfresco.webservice.repository.RepositoryServiceSoapBindingStub;
import org.alfresco.webservice.types.CML;
import org.alfresco.webservice.types.CMLAddAspect;
import org.alfresco.webservice.types.CMLDelete;
import org.alfresco.webservice.types.Node;
import org.alfresco.webservice.types.Predicate;
import org.alfresco.webservice.types.Reference;
import org.alfresco.webservice.types.Store;
import org.alfresco.webservice.util.AuthenticationUtils;
import org.alfresco.webservice.util.Constants;
import org.alfresco.webservice.util.ContentUtils;
import org.alfresco.webservice.util.WebServiceFactory;
public class NodeDeletionService {
protected static final Store STORE = new Store(Constants.WORKSPACE_STORE,
"SpacesStore");
public static void main(String[] args) {
try {
AuthenticationUtils.startSession("admin", "admin");
RepositoryServiceSoapBindingStub repositoryService = WebServiceFactory
.getRepositoryService();
Reference reference = new Reference(STORE,
"8abb6223-11bb-11e4-a335-65e3a9c8626a", null);
Predicate predicate = new Predicate(new Reference[] { reference },
null, null);
Node[] nodes = repositoryService.get(predicate);
CMLDelete delete = new CMLDelete(predicate);
CML cml = new CML();
cml.setDelete(new CMLDelete[] { delete });
CMLAddAspect addAspect = new CMLAddAspect("temporary", null, predicate, null);
cml.setAddAspect(new CMLAddAspect[]{addAspect});
// Execute the CMLDelete statement
try {
WebServiceFactory.getRepositoryService().update(cml);
System.out.println("Deleted succesfully");
} catch (Exception e2) {
System.err.println("Can not delete the space.");
throw e2;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
AuthenticationUtils.endSession();
}
}
}
But I get an exception
{http://www.alfresco.org/ws/service/repository/1.0}RepositoryFault:<ns1:errorCode>0</ns1:errorCode><ns1:message>org.alfresco.service.cmr.dictionary.InvalidAspectException: The aspect is invalid: {}temporary</ns1:message>
{http://xml.apache.org/axis/}exceptionName:org.alfresco.repo.webservice.repository.RepositoryFault
I tried different aspects like temporary, cm:temporary, sys:temporary - but all in vain. Any idea?
Related
I have a problem connecting to the postgres database using PgPool and ResulSet, then the Statement of sql. Here is my class of service.
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.ApplicationScope;
//import io.vertx.reactivex.pgclient.PgPool;
import io.vertx.axle.pgclient.PgPool;
import ml.kalansow.domain.StudentFees;
import ml.kalansow.service.KalansowService;
#Service
#ApplicationScope
public class StudentFeesService implements KalansowService {
private static final Logger LOG = LoggerFactory.getLogger(StudentFeesService.class);
PgPool client;
// ----Constructor------------------------------------------
public StudentFeesService() {
// TODO Auto-generated constructor stub
};
// ------------------------------Method---------------------------------
#Override
public String getServiceName() {
return this.getClass().getName();
}
public void processGetFeesDetails(HttpSession session) {
String strStudentId = (String) session.getAttribute("StudentId");
StudentFees studentFees = new StudentFees();
if (strStudentId != null) {
// This is mandatory before calling the next method
studentFees.setStudentId(strStudentId);
populateFeesInfo(studentFees);
session.setAttribute("studentFees", studentFees);
} else {
LOG.error("Student Id is null");
}
}
private void populateFeesInfo(StudentFees studentFees) {
String strStudentI = studentFees.getStudentId();
io.vertx.sqlclient.impl.Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
StringBuffer sbQuery = new StringBuffer();
sbQuery.append("SELECT * FROM STUDENT_FEES WHERE STUDENT_I=");
sbQuery.append("" + strStudentI + "''");
if (strStudentI != null) {
//connection = DatabaseService.getDBConnection();
connection=(io.vertx.sqlclient.impl.Connection) client.getConnection();
try {
statement = ((Connection) connection).createStatement();
resultSet = statement.executeQuery(sbQuery.toString());
resultSet.next();
studentFees.setJanAcad(resultSet.getString("JAN_ACAD"));
studentFees.setFebAcad(resultSet.getString("FEB_ACAD"));
studentFees.setMarAcad(resultSet.getString("MAR_ACAD"));
studentFees.setAprAcad(resultSet.getString("APR_ACAD"));
studentFees.setMayAcad(resultSet.getString("MAY_ACAD"));
studentFees.setJunAcad(resultSet.getString("JUN_ACAD"));
studentFees.setJulAcad(resultSet.getString("JUL_ACAD"));
studentFees.setAugAcad(resultSet.getString("AUG_ACAD"));
studentFees.setSepAcad(resultSet.getString("SEP_ACAD"));
studentFees.setOctAcad(resultSet.getString("OCT_ACAD"));
studentFees.setNovAcad(resultSet.getString("NOV_ACAD"));
studentFees.setDecAcad(resultSet.getString("DEC_ACAD"));
} catch (SQLException e) {
LOG.error(e.getMessage());
} finally {
/*DatabaseService.closeDBConnection(statement, resultSet);
DatabaseService.realeaseDBConnection();*/
client.close();
}
} else {
LOG.error("Student id is null");
}
}
}
My application properties file contain datasource properties
quarkus.datasource.driver=org.postgresql.Driver
quarkus.reactive-datasource.url=vertx-reactive:postgresql://localhost:5432/test
quarkus.reactive-datasource.username=test
quarkus.reactive-datasource.password=test
And console is here
ERROR [io.qua.dev.DevModeMain] Failed to start Quarkus: java.lang.IllegalArgumentException: Multiple matching properties for name "datasource.url" property was matched by both public java.util.Optional io.quarkus.agroal.runtime.DataSourceRuntimeConfig.url and public java.util.Optional io.quarkus.reactive.pg.client.runtime.DataSourceConfig.url. This is likely because you have an incompatible combination of extensions that both define the same properties (e.g. including both reactive and blocking database extensions)
at io.quarkus.deployment.configuration.matching.PatternMapBuilder.addMember(PatternMapBuilder.java:71)
at io.quarkus.deployment.configuration.matching.PatternMapBuilder.addGroup(PatternMapBuilder.java:60)
at io.quarkus.deployment.configuration.matching.PatternMapBuilder.addMember(PatternMapBuilder.java:85)
at io.quarkus.deployment.configuration.matching.PatternMapBuilder.addGroup(PatternMapBuilder.java:60)
at io.quarkus.deployment.configuration.matching.PatternMapBuilder.makePatterns(PatternMapBuilder.java:35)
at io.quarkus.deployment.configuration.BuildTimeConfigurationReader.(BuildTimeConfigurationReader.java:107)
at io.quarkus.deployment.ExtensionLoader.loadStepsFrom(ExtensionLoader.java:174)
at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:85)
at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:114)
at io.quarkus.dev.DevModeMain.doStart(DevModeMain.java:178)
at io.quarkus.dev.DevModeMain.start(DevModeMain.java:96)
You cannot use both the Agroal extension and the Reactive datasources together for the time being.
We are discussing possible ways to fix that here: https://groups.google.com/d/msg/quarkus-dev/3r0lquVsUsc/DVxX7SvQAQAJ .
But for now, your only choice is to use either one or the other.
I am working on drool dtable xls file with spring.
i have implemented the business rules in xls file using external location and then with the help of kie services i am executing rules.
Following is the code snippet that's how i am loading rules in engine.
at the start of spring initialization i am calling init() method
see below spring configuration.
<bean id="droolsService" class="com.example.drools.DroolsServiceImpl" init-method="init">
Java Code
public void init() {
LOG.info("inside init");
KieSession kieSession;
for (RequestType type : droolsMap.keySet()) {
try {
kieSession = getKieSession(this.getDroolsMap().get(type));
droolsRules.put(type, kieSession);
} catch (Exception e) {
LOG.error("Failed to load kiesession:", e);
throw new RuntimeException(e);
}
}
}
private KieSession getKieSession(final String file) throws DroolsParserException, IOException, BiffException {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
InputStream stream = null;
String drl = null;
String RULE_PATH = "src/main/resources/";
SpreadsheetCompiler converter = new SpreadsheetCompiler();
//Workbook workbook = Workbook.getWorkbook(DroolsServiceImpl.class.getResourceAsStream(file));
Workbook workbook = Workbook.getWorkbook(new FileInputStream(file));
LOG.info("Loading rule file " + file);
for (Sheet sheet : workbook.getSheets()) {
LOG.info("Loading Sheet " + sheet.getName());
stream = new FileInputStream(file);
drl = converter.compile(stream, sheet.getName());
//StringReader reader = new StringReader(drl);
String DRL_FILE = RULE_PATH + sheet.getName() + ".drl";
System.out.println("Drool file added ::: " + DRL_FILE);
kfs.write(DRL_FILE, ResourceFactory.newReaderResource(new StringReader(drl)));
stream.close();
}
KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
KieSessionConfiguration conf = SessionConfiguration.newInstance();
KieSession ksession = kieContainer.newKieSession(conf);
if (kieBuilder.getResults().hasMessages(Message.Level.ERROR)) {
List<Message> errors = kieBuilder.getResults().getMessages(Message.Level.ERROR);
StringBuilder sb = new StringBuilder("Errors:");
for (Message msg : errors) {
sb.append("\n " + msg);
}
try {
throw new Exception(sb.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null)
stream.close();
if (workbook != null)
workbook.close();
}
}
return ksession;
}
Everything working perfect but the problem is i am not able to scan the file changes. If files is modified then i have to restart the server in order to sync the changes.
I have tried listener to load specific init() method after xls dtable has any changes but its not working , same old result is coming.
I have tried kiescanner but i am not able to get the concept.
KieScanner is loading maven kjar so how do i suppose to create kjar.
I just wanted to kie api scan if any changes in the drool file and try to reload whole changes in kiecontainer without server restarting.
Found the answer myself, Posting because it will help someone who needed.
What I did , I have used apache VFS File Monitor-
DefaultFileMonitor fm = new DefaultFileMonitor(new CustomFileListener());
When file will modified , create or get deleted it will call CustomFileListener.
Following is the implementation of CustomFileListener.
import org.apache.commons.vfs2.FileChangeEvent;
import org.apache.commons.vfs2.FileListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class CustomFileListener implements FileListener {
private static final Logger LOG = LoggerFactory.getLogger(CustomFileListener.class);
#Override
public void fileCreated(FileChangeEvent fileChangeEvent) throws Exception {
}
#Override
public void fileDeleted(FileChangeEvent fileChangeEvent) throws Exception {
}
#Override
public void fileChanged(FileChangeEvent fileChangeEvent) throws Exception {
LOG.debug(" Under FileChanged Method");
LOG.debug(" File has been changed hence reinitializing init method = " + fileChangeEvent.getFile().getName().getPath());
XmlWebApplicationContext xmlWebApplicationContext =
(XmlWebApplicationContext) ContextLoader.getCurrentWebApplicationContext();
DefaultListableBeanFactory defaultListableBeanFactory =
(DefaultListableBeanFactory) xmlWebApplicationContext.getBeanFactory();
DroolsServiceImpl droolsService = (DroolsServiceImpl) defaultListableBeanFactory.getBean("droolsService");
droolsService.init();
}
}
What i did when the file will change, It will call fileChanged method.
In that i have fetched cached bean(DroolServiceImpl) from ContextLoader.getCurrentWebApplicationContext(); and called its init() method.
So this it will reload whole process and reinitialize the KieModule,KieRepository.
How can I retrieve and display images from a database in a JSP page?
Let's see in steps what should happen:
JSP is basically a view technology which is supposed to generate HTML output.
To display an image in HTML, you need the HTML <img> element.
To let it locate an image, you need to specify its src attribute.
The src attribute needs to point to a valid http:// URL and thus not a local disk file system path file:// as that would never work when the server and client run at physically different machines.
The image URL needs to have the image identifier in either the request path (e.g. http://example.com/context/images/foo.png) or as request parameter (e.g. http://example.com/context/images?id=1).
In JSP/Servlet world, you can let a Servlet listen on a certain URL pattern like /images/*, so that you can just execute some Java code on specific URL's.
Images are binary data and are to be obtained as either a byte[] or InputStream from the DB, the JDBC API offers the ResultSet#getBytes() and ResultSet#getBinaryStream() for this, and JPA API offers #Lob for this.
In the Servlet you can just write this byte[] or InputStream to the OutputStream of the response the usual Java IO way.
The client side needs to be instructed that the data should be handled as an image, thus at least the Content-Type response header needs to be set as well. You can obtain the right one via ServletContext#getMimeType() based on image file extension which you can extend and/or override via <mime-mapping> in web.xml.
That should be it. It almost writes code itself. Let's start with HTML (in JSP):
<img src="${pageContext.request.contextPath}/images/foo.png">
<img src="${pageContext.request.contextPath}/images/bar.png">
<img src="${pageContext.request.contextPath}/images/baz.png">
You can if necessary also dynamically set src with EL while iterating using JSTL:
<c:forEach items="${imagenames}" var="imagename">
<img src="${pageContext.request.contextPath}/images/${imagename}">
</c:forEach>
Then define/create a servlet which listens on GET requests on URL pattern of /images/*, the below example uses plain vanilla JDBC for the job:
#WebServlet("/images/*")
public class ImageServlet extends HttpServlet {
// content=blob, name=varchar(255) UNIQUE.
private static final String SQL_FIND = "SELECT content FROM Image WHERE name = ?";
#Resource(name="jdbc/yourDB") // For Tomcat, define as <Resource> in context.xml and declare as <resource-ref> in web.xml.
private DataSource dataSource;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String imageName = request.getPathInfo().substring(1); // Returns "foo.png".
try (Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL_FIND)) {
statement.setString(1, imageName);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
byte[] content = resultSet.getBytes("content");
response.setContentType(getServletContext().getMimeType(imageName));
response.setContentLength(content.length);
response.getOutputStream().write(content);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
}
}
} catch (SQLException e) {
throw new ServletException("Something failed at SQL/DB level.", e);
}
}
}
That's it. In case you worry about HEAD and caching headers and properly responding on those requests, use this abstract template for static resource servlet.
See also:
How should I connect to JDBC database / datasource in a servlet based application?
How to upload an image and save it in database?
Simplest way to serve static data from outside the application server in a Java web application
I suggest you address that as two problems. There are several questions and answer related to both.
How to load blob from MySQL
See for instance Retrieve image stored as blob
How to display image dynamically
See for instance Show thumbnail dynamically
I've written and configured the code in JSP using Oracle database.
Hope it will help.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class displayfetchimage
*/
#WebServlet("/displayfetchimage")
public class displayfetchimage extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public displayfetchimage() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
Statement stmt = null;
String sql = null;
BufferedInputStream bin = null;
BufferedOutputStream bout = null;
InputStream in = null;
response.setContentType("image/jpeg");
ServletOutputStream out;
out = response.getOutputStream();
Connection conn = employee.DbConnection.getDatabaseConnection();
HttpSession session = (HttpSession) request.getSession();
String ID = session.getAttribute("userId").toString().toLowerCase();
try {
stmt = conn.createStatement();
sql = "select user_image from employee_data WHERE username='" + ID + "' and rownum<=1";
ResultSet result = stmt.executeQuery(sql);
if (result.next()) {
in = result.getBinaryStream(1);// Since my data was in first column of table.
}
bin = new BufferedInputStream(in);
bout = new BufferedOutputStream(out);
int ch = 0;
while ((ch = bin.read()) != -1) {
bout.write(ch);
}
} catch (SQLException ex) {
Logger.getLogger(displayfetchimage.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (bin != null)
bin.close();
if (in != null)
in.close();
if (bout != null)
bout.close();
if (out != null)
out.close();
if (conn != null)
conn.close();
} catch (IOException | SQLException ex) {
System.out.println("Error : " + ex.getMessage());
}
}
}
// response.getWriter().append("Served at: ").append(request.getContextPath());
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Statement stmt = null;
String sql = null;
BufferedInputStream bin = null;
BufferedOutputStream bout = null;
InputStream in = null;
response.setContentType("image/jpeg");
ServletOutputStream out;
out = response.getOutputStream();
Connection conn = employee.DbConnection.getDatabaseConnection();
HttpSession session = (HttpSession) request.getSession();
String ID = session.getAttribute("userId").toString().toLowerCase();
try {
stmt = conn.createStatement();
sql = "select user_image from employee_data WHERE username='" + ID + "' and rownum<=1";
ResultSet result = stmt.executeQuery(sql);
if (result.next()) {
in = result.getBinaryStream(1);
}
bin = new BufferedInputStream(in);
bout = new BufferedOutputStream(out);
int ch = 0;
while ((ch = bin.read()) != -1) {
bout.write(ch);
}
} catch (SQLException ex) {
Logger.getLogger(displayfetchimage.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (bin != null)
bin.close();
if (in != null)
in.close();
if (bout != null)
bout.close();
if (out != null)
out.close();
if (conn != null)
conn.close();
} catch (IOException | SQLException ex) {
System.out.println("Error : " + ex.getMessage());
}
}
}
}
Try to flush and close the output stream if it does not display.
Blob image = rs.getBlob(ImageColName);
InputStream in = image.getBinaryStream();
// Output the blob to the HttpServletResponse
response.setContentType("image/jpeg");
BufferedOutputStream o = new BufferedOutputStream(response.getOutputStream());
byte by[] = new byte[32768];
int index = in.read(by, 0, 32768);
while (index != -1) {
o.write(by, 0, index);
index = in.read(by, 0, 32768);
}
o.flush();
o.close();
I used SQL SERVER database and so the answer's code is in accordance. All you have to do is include an <img> tag in your jsp page and call a servlet from its src attribute like this
<img width="200" height="180" src="DisplayImage?ID=1">
Here 1 is unique id of image in database and ID is a variable. We receive value of this variable in servlet. In servlet code we take the binary stream input from correct column in table. That is your image is stored in which column. In my code I used third column because my images are stored as binary data in third column. After retrieving input stream data from table we read its content in an output stream so it can be written on screen. Here is it
import java.io.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.*;
import javax.servlet.http.*;
import model.ConnectionManager;
public class DisplayImage extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException
{
Statement stmt=null;
String sql=null;
BufferedInputStream bin=null;
BufferedOutputStream bout=null;
InputStream in =null;
response.setContentType("image/jpeg");
ServletOutputStream out;
out = response.getOutputStream();
Connection conn = ConnectionManager.getConnection();
int ID = Integer.parseInt(request.getParameter("ID"));
try {
stmt = conn.createStatement();
sql = "SELECT * FROM IMAGETABLE WHERE ID="+ID+"";
ResultSet result = stmt.executeQuery(sql);
if(result.next()){
in=result.getBinaryStream(3);//Since my data was in third column of table.
}
bin = new BufferedInputStream(in);
bout = new BufferedOutputStream(out);
int ch=0;
while((ch=bin.read())!=-1)
{
bout.write(ch);
}
} catch (SQLException ex) {
Logger.getLogger(DisplayImage.class.getName()).log(Level.SEVERE, null, ex);
}finally{
try{
if(bin!=null)bin.close();
if(in!=null)in.close();
if(bout!=null)bout.close();
if(out!=null)out.close();
if(conn!=null)conn.close();
}catch(IOException | SQLException ex){
System.out.println("Error : "+ex.getMessage());
}
}
}
}
After the execution of your jsp or html file you will see the image on screen.
You can also create custom tag for displaying image.
1) create custom tag java class and tld file.
2) write logic to display image like conversion of byte[] to string by Base64.
so it is used for every image whether you are displaying only one image or multiple images in single jsp page.
We're developing a system that we're basing on OrientDB graphs (OrientDB 2.1.3). In the application, we have a thin pojo->graph persistence layer that should do the work properly, but I get OConcurrentModificationException when having multiple threads updating the database.
Here's an example scenario:
Create a Product vertex with edge to Color "Blue"
Simultaneously (while the transaction for creating Product 1 is open) create another Product vertex is created and also adds an edge to Color "Blue".
OConcurrentModificationException is thrown since the version of Color "Blue" vertex is updated. Note that I'm not trying to save or modify the Color "Blue" vertex itself.
As I understood the docs at http://orientdb.com/docs/2.1/Concurrency.html#concurrency-on-adding-edges setting -DridBag.embeddedToSbtreeBonsaiThreshold=-1 should help me avoid my problem, although it still doesn't work.
What am I missing? Is there anything else I can do to avoid this?
Update:
Stacktrace of the exception:
Error on releasing database 'infogileorientdatabasetest' in pool
com.orientechnologies.orient.core.exception.OConcurrentModificationException: Cannot UPDATE the record #40:1 because the version is not the latest. Probably you are updating an old record or it has been modified by another user (db=v34 your=v33)
at com.orientechnologies.orient.core.conflict.OVersionRecordConflictStrategy.checkVersions(OVersionRecordConflictStrategy.java:55)
at com.orientechnologies.orient.core.conflict.OVersionRecordConflictStrategy.onUpdate(OVersionRecordConflictStrategy.java:42)
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.checkAndIncrementVersion(OAbstractPaginatedStorage.java:2279)
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.doUpdateRecord(OAbstractPaginatedStorage.java:1911)
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.commitEntry(OAbstractPaginatedStorage.java:2364)
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.commit(OAbstractPaginatedStorage.java:1111)
at com.orientechnologies.orient.core.tx.OTransactionOptimistic.doCommit(OTransactionOptimistic.java:609)
at com.orientechnologies.orient.core.tx.OTransactionOptimistic.commit(OTransactionOptimistic.java:156)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2582)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2551)
at com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.commit(ONetworkProtocolBinary.java:1221)
at com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.executeRequest(ONetworkProtocolBinary.java:400)
at com.orientechnologies.orient.server.network.protocol.binary.OBinaryNetworkProtocolAbstract.execute(OBinaryNetworkProtocolAbstract.java:223)
at com.orientechnologies.common.thread.OSoftThread.run(OSoftThread.java:77)
Update 2 - test case
I have reproduced the error using this test case. I would be delighted if there's something else I've done wrong to cause the problem... :-)
Update 3 Updated test case with OGlobalConfiguration.RID_BAG_EMBEDDED_TO_SBTREEBONSAI_THRESHOLD.setValue(-1) in a static block.
package se.infogile.persistence.orientdb;
import com.orientechnologies.orient.client.remote.OServerAdmin;
import com.orientechnologies.orient.core.config.OGlobalConfiguration;
import com.orientechnologies.orient.core.db.OPartitionedDatabasePool;
import com.orientechnologies.orient.core.db.OPartitionedDatabasePoolFactory;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.exception.OConcurrentModificationException;
import com.orientechnologies.orient.core.exception.OConfigurationException;
import com.orientechnologies.orient.core.exception.OStorageException;
import com.orientechnologies.orient.core.tx.OTransaction;
import com.orientechnologies.orient.enterprise.channel.binary.OResponseProcessingException;
import com.orientechnologies.orient.server.OServer;
import com.orientechnologies.orient.server.OServerMain;
import com.orientechnologies.orient.server.config.OServerConfiguration;
import com.orientechnologies.orient.server.config.OServerConfigurationLoaderXml;
import com.orientechnologies.orient.server.config.OServerNetworkListenerConfiguration;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* Created by heintz on 14/10/15.
*/
public class OrientDBEdgeProblemTest {
static {
OGlobalConfiguration.RID_BAG_EMBEDDED_TO_SBTREEBONSAI_THRESHOLD.setValue(-1);
}
private static OPartitionedDatabasePoolFactory dbPoolFactory = new OPartitionedDatabasePoolFactory(100);
private static Logger logger = LoggerFactory.getLogger(OrientDBEdgeProblemTest.class);
private OServer server = null;
private static ExecutorService executorService = Executors.newFixedThreadPool(10);
private static final String dbName = "edgeproblemtest";
#Test
public void testVersionIncrementError() throws Throwable {
OrientGraph graph = getGraph(dbName);
graph.getRawGraph().setDefaultTransactionMode();
graph.createVertexType("Product");
graph.createVertexType("Color");
graph.createEdgeType("HasColor");
graph.getRawGraph().begin(OTransaction.TXTYPE.OPTIMISTIC);
// graph.begin();
Vertex v1 = graph.addVertex("Color", "name", "Blue");
graph.commit();
graph.shutdown();
char[] alphabet = new char[] {'A','B','C','D','E','F','G'};
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 2; i++) {
int pos = i;
futures.add(executorService.submit(new Callable<Object>() {
#Override
public Object call() throws Exception {
OrientGraph g = getGraph(dbName);
try {
g.begin();
Vertex v2 = g.addVertex("Product", "name", "Product "+alphabet[pos]);
g.addEdge(null, v2, v1, "HasColor");
Thread.sleep(200);
g.commit();
} catch (OConcurrentModificationException ocme) {
logger.error("Exception while saving: ", ocme);
Assert.fail("OConcurrentModificationException");
} finally {
g.shutdown();
}
return null;
}
}));
}
for (Future f : futures) {
f.get();
}
executorService.shutdown();
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
#AfterSuite
public void tearDown() throws Exception {
logger.info("Shutting down OrientDB");
if (server != null) {
server.shutdown();
}
}
private OrientGraph getGraph(String dbName) {
String _db = "remote:localhost:3424";
String url = _db + "/" + dbName;
ODatabaseDocumentTx db = null;
try {
OPartitionedDatabasePool pool = dbPoolFactory.get(url,
"root",
"admin");
db = pool.acquire();
} catch (OResponseProcessingException | OConfigurationException | OStorageException oce) {
try {
logger.info("creating new database named " + dbName);
System.err.println("Before DB creation");
OServerAdmin serverAdmin = new OServerAdmin(_db).connect(
"root",
"admin"
);
serverAdmin.createDatabase(dbName, "document", "plocal");
serverAdmin.close();
System.err.println("After DB creation");
} catch (IOException ex) {
logger.error("Unable to create database " + dbName, ex);
}
OPartitionedDatabasePool pool = dbPoolFactory.get(url,
"root",
"admin");
db = pool.acquire();
}
return new OrientGraph(db);
}
#BeforeSuite
public void setUpDatabase() throws Exception {
File f = new File(".");
InputStream is = GraphPersistenceServiceTest.class.getResourceAsStream("/orientdb.config");
Assert.assertNotNull(is);
logger.info("Starting OrientDB");
server = OServerMain.create();
OServerConfigurationLoaderXml loaderXml = new OServerConfigurationLoaderXml(OServerConfiguration.class, GraphPersistenceServiceTest.class.getResourceAsStream("/orientdb.config"));
OServerConfiguration oServerConfiguration = new OServerConfiguration(loaderXml);
System.setProperty("ORIENTDB_ROOT_PASSWORD", "admin");
System.setProperty("RUNMODE", "UNITTEST");
OServerNetworkListenerConfiguration networkConfig = oServerConfiguration.network.listeners.iterator().next();
networkConfig.portRange = "3424-3430";
server.setServerRootDirectory("./target/orientdb");
server.startup(oServerConfiguration);
File serverDir = new File("./target/orientdb");
if (serverDir.exists()) {
FileUtils.deleteDirectory(serverDir);
}
serverDir.mkdirs();
File dbDir = new File(serverDir, "databases");
dbDir.mkdirs();
server.activate();
OGlobalConfiguration.dumpConfiguration(System.out);
Thread.sleep(2000);
}
}
Hi that is because when you add edges to the vertex, vertex itself is modified to store this information, but you may work in mode when information about edges is stored in separate object. Merely use property
-DridBag.embeddedToSbtreeBonsaiThreshold=true and you will rid off this exception.
I tried to create an SQLite database and do some stuff with it. But I found that my onCreate method is not even invoked!!
I am sending a message to LogCat on the begining of the onCreate method.
My assumption is, the (super) constructor will invoke onCreate method. Is that right?
My Code:
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.content.Context;
import android.database.Cursor;
import android.content.ContentValues;
import android.util.Log;
public class DatabaseHandler extends SQLiteOpenHelper {
// Static Constants
/*** Database details ***/
// Database version
private static final int DATABASE_VERSION = 1;
// Database name
private static final String DATABASE_NAME = "database_name";
/*** Database Tables ***/
/** Events **/
// Event table
private static final String TABLE_EVENT = "event";
// Event table columns
private static final String COLUMN_EVENT_EID = "_eid";
private static final String COLUMN_EVENT_CREATION_DATE = "creation_date";
private static final String COLUMN_EVENT_TITLE = "title";
private static final String COLUMN_EVENT_ICON = "icon";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.e("MyApp", "onCreate invoked");
// Tables creation queries
String CREATE_EVENT_TABLE = "create table " + TABLE_EVENT + "(" + COLUMN_EVENT_EID + " integer primary key, "
+ COLUMN_EVENT_CREATION_DATE + " text, "
+ COLUMN_EVENT_TITLE + " text, "
+ COLUMN_EVENT_ICON + " text)";
// Creating tables
db.execSQL(CREATE_EVENT_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e("MyApp", "onUpgrade invoked");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_EVENT);
}
}
MainActivity Code:
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatabaseHandler db = new DatabaseHandler(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
The documentation says:
The database is not actually created or opened until one of getWritableDatabase() or getReadableDatabase() is called.
Let me clear the on the logic flow. Here is Lazy-initialization concept.
The (super) constructor on DatabaseHandler will not invoke onCreate method. Calling DatabaseHandler constructor will initializes: context, database name, factory that creates the database, database version, and database error handler.
getWritableDatabase() > getDatabaseLocked() > - SQLiteDatabase.create()
OR
getReadableDatabase() > getDatabaseLocked() > - SQLiteDatabase.create()
Answer: After your database gets created successfully, your configurations changes, next time again getReadableDatabase() or getWritableDatabase() calls getDatabaseLocked() and there onCreate(db) method inside getDatabaseLocked() gets executed.
Explanation:
The above SQLiteDatabase.create() method is responsible to create SQLiteDatabase in the disk.
But the process in lazy-initialization (mean, it doesn't make everything ready. It creates those objects on the runtime if you need them. For this it used a lot of if..else statements).
If you see the full body of getDatabaseLocked(), this is below. [You can search onCreate() method inside the body of getDatabaseLocked()]
private SQLiteDatabase getDatabaseLocked(boolean writable) {
if (mDatabase != null) {
if (!mDatabase.isOpen()) {
// Darn! The user closed the database by calling mDatabase.close().
mDatabase = null;
} else if (!writable || !mDatabase.isReadOnly()) {
// The database is already open for business.
return mDatabase;
}
}
if (mIsInitializing) {
throw new IllegalStateException("getDatabase called recursively");
}
SQLiteDatabase db = mDatabase;
try {
mIsInitializing = true;
if (db != null) {
if (writable && db.isReadOnly()) {
db.reopenReadWrite();
}
} else if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
try {
if (DEBUG_STRICT_READONLY && !writable) {
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
} catch (SQLiteException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
}
onConfigure(db);
final int version = db.getVersion();
if (version != mNewVersion) {
if (db.isReadOnly()) {
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
db.beginTransaction();
try {
if (version == 0) {
onCreate(db);
} else {
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
onUpgrade(db, version, mNewVersion);
}
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
onOpen(db);
if (db.isReadOnly()) {
Log.w(TAG, "Opened " + mName + " in read-only mode");
}
mDatabase = db;
return db;
} finally {
mIsInitializing = false;
if (db != null && db != mDatabase) {
db.close();
}
}
}
Please note, inside the body of getDatabaseLocked() method, there are so many if.. else cases. These if.. else cases determines your current environment (configuration), and based on your current environment they call appropriate methods to initialize/configure whatever needed.
Also, note: All the callbacks methods in your DatabaseHandler (class that implemented SQLiteOpenHelper) are called inside the getDatabaseLocked() body.
Source code SQLiteOpenHelper.java:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/database/sqlite/SQLiteOpenHelper.java
Source code SQLiteDatabase.java:
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/database/sqlite/SQLiteDatabase.java
Sample to follow: https://github.com/uddhavgautam/SQLiteBasicSample
Your are right, the (super) constructor will invoke onCreate method, BUT only if the actual database does not exits.
From http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onCreate%28android.database.sqlite.SQLiteDatabase%29
A helper class to manage database creation and version management.
You create a subclass implementing onCreate(SQLiteDatabase),
onUpgrade(SQLiteDatabase, int, int) and optionally
onOpen(SQLiteDatabase), and this class takes care of opening the
database if it exists, creating it if it does not, and upgrading it as
necessary.
As the official documents says, "getWritableDatabase () Create and/or open a database that will be used for reading and writing. The first time this is called, the database will be opened and onCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int) and/or onOpen(SQLiteDatabase) will be called."
Once opened successfully, the database is cached, so you can call this method every time you need to write to the database. (Make sure to call close() when you no longer need the database.) Errors such as bad permissions or a full disk may cause this method to fail, but future attempts may succeed if the problem is fixed.
http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase()