I have deployed a mature web application to a new server on tomcat 7. The database the system uses is quite empty as we're in the early stages of configuring it for use.
Going to the app, you get a login page. Log in and it usually takes you to the main page of the app.
But after coming in the following morning, we always get the same problem:
We bring up the login screen - no problem
Enter our username and password - system hangs
We go to tomcat and using
the system tray, stop the service.
The stopping service progress bar appears then goes away, but the status
on the tomcat properties dialog still shows 'Started' and both the Start
and Stop buttons are disabled.
We check the tomcat logs and there are no errors
We restart the server and it works ok again
There is nothing obvious we can see. A tomcat 'Find Leaks' request shows nothing, and looking at the heap sizes on VisualVM shows a consistent pattern of heap takeup followed by garbage collection bringing it back down to the same low level (so no apparent leaks)
I thought it may be mysql connections timing out, but that shouldnt be the case because if I log in with the wrong password, the system goes to the database to check the password and returns as expected with 'wrong password'. The only point at which it fails is if you enter the correct password.
The only clue we have is that there is an error when logging in, where the system uses some custom code to figure out the users' host name:
2019-02-14 08:10:14,277 08:10:14.277 [http-bio-8080-exec-9] ERROR com.sw.app.ui.UserAuthenticatedWebSession - Unknown host!
java.net.UnknownHostException: null
at java.net.Inet6AddressImpl.getHostByAddr(Native Method) ~[na:1.8.0_201]
at java.net.InetAddress$2.getHostByAddr(Unknown Source) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_201]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_201]
at com.sw.app.data.utils.NetUtilities.getHostName(NetUtilities.java:114) ~[app-data-4.0.15.1-SNAPSHOT.jar:na]
This is only invoked if the user logs in successfully to store where they are logging in from, but the exception is caught in the code and then just logged rather than propagated upwards, and then we use a default 'unknown' host name. This is the code:
public static String getHostName( InetAddress inaHost ) throws UnknownHostException
{
try {
Class<? extends InetAddress> clazz = Class.forName( "java.net.InetAddress" ).asSubclass( InetAddress.class );
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
constructors[0].setAccessible( true );
InetAddress ina = (InetAddress)constructors[0].newInstance();
Field[] fields = ina.getClass().getDeclaredFields();
for( Field field : fields ) {
// Depends on the version of java we are dealing with:
// Older version - single nameservice
if( field.getName().equals( "nameService" ) ) {
return getHostName( field.get( null ), inaHost );
} else if( field.getName().equals( "nameServices" ) ) {
// newer version - multiple name services possible
StringBuilder builder = new StringBuilder();
field.setAccessible( true );
// A list of nameservice objects
#SuppressWarnings( "unchecked" )
List<Object> nameServices = (List<Object>)field.get( null );
for( Object nameService : nameServices ) {
String hostName = getHostName( nameService, inaHost );
if( builder.length() > 0 ) {
builder.append( ", " );
}
builder.append( hostName );
}
return builder.toString();
}
}
} catch( ClassNotFoundException cnfe ) {
throw new InvalidOperationException( "Class not found when looking up host name", cnfe );
} catch( IllegalAccessException iae ) {
throw new InvalidOperationException( "Cannot access method/field", iae );
} catch( InstantiationException ie ) {
throw new InvalidOperationException( "Cannot instantiate class", ie );
} catch( InvocationTargetException ite ) {
throw (UnknownHostException)ite.getCause();
}
return null;
}
/**
* Get the host name using reflection on the hidden class implementation of the InetAddress details.
* #param p_nameService
* #param p_address
* #return
* #throws IllegalAccessException
* #throws InvocationTargetException
*/
private static String getHostName( Object nameService, InetAddress address ) throws IllegalAccessException, InvocationTargetException {
Method[] methods = nameService.getClass().getDeclaredMethods();
for( Method method : methods ) {
// The nameService is assumed to have a method, getHostByAddr, which takes the byte[] inet address
if( method.getName().equals( "getHostByAddr" ) ) {
method.setAccessible( true );
return (String)method.invoke( nameService, address.getAddress() );
}
}
return "";
}
Does anyone have similar issues?
-- Edit --
Here is the database configuration bean class.
#Configuration
public class AppPersistence {
private static final Logger LOGGER = LoggerFactory.getLogger( AppPersistence.class );
protected static final String INTERNAL_IP_DOMAIN = "*******";
protected static final String JDBC_PROTOCOL = "jdbc:mysql://";
protected static final String DEFAULT_DATABASE_NAME = "*******";
/** The path for context-based property lookups */
protected static final String CONTEXT_LOOKUP_PATH = "java:comp/env";
/** This is the default location for the database - on the same machine as the deployment */
protected static final String DB_LOCAL = JDBC_PROTOCOL + "localhost:3306/" + DEFAULT_DATABASE_NAME;
#Bean
public DataSource createDataSource() throws Exception {
BasicDataSource source = new BasicDataSource();
// allow for parameterised config
source.setDriverClassName( Driver.class.getName() );
source.setUrl( getProperty( "app.database.url", DB_LOCAL ) );
source.setUsername( getProperty( "app.database.username", "*****" ) );
source.setPassword( getProperty( "app.database.password", "****" ) );
LOGGER.warn( "Connecting to: " + source.getUrl() );
return source;
}
protected String getProperty( String name, String default ) {
// first check system properties
String val = System.getProperty( name );
if( val != null ) {
logLookup( "System Properties", name, val );
return val;
}
// check environment variables
val = System.getenv( name );
if( val != null ) {
logLookup( "System Environment Variables", name, val );
return val;
}
// if we are deployed to a container, check the environment variables in that.
try {
Context context = InitialContext.doLookup( "java:comp/env" );
if( context != null ) {
Object valObj = context.lookup( name );
if( valObj != null ) {
logLookup( "Context", name, valObj.toString() );
return valObj.toString();
}
}
} catch( NamingException e ) {
// if running on a dev machine this will probably happen
LOGGER.warn( "Could not find context for lookup of " + p_name + " - assuming running in dev mode with defaults. Error was: " + e.toString( true ) );
LOGGER.info( "Error received on lookup of " + name + ":", e );
}
return p_default;
}
protected void logLookup( String source, String lookup, String value ) {
if( value.contains( "password" ) ) {
// avoid displaying any password info
LOGGER.warn( "Successfully looked up sensitive value from " + source + " for name '" + lookup + "': [******]" );
} else {
LOGGER.warn( "Successfully looked up value from " + source + " for name '" + lookup + "': '" + value + "'" );
}
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory( DataSource dataSource ) {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPersistenceUnitName( "com.sw.app.data.persistence" );
entityManagerFactory.setDataSource( dataSource );
entityManagerFactory.setJpaVendorAdapter( new HibernateJpaVendorAdapter() );
entityManagerFactory.setLoadTimeWeaver( new InstrumentationLoadTimeWeaver() );
entityManagerFactory.setJpaDialect( new HibernateJpaDialect() );
entityManagerFactory.setPackagesToScan( "com.sw.app.data", "com.sw.app.rawimport",
"com.sw.app.view", "com.sw.app.warranty" );
entityManagerFactory.setJpaPropertyMap( hibernateJpaProperties( dataSource ) );
return entityManagerFactory;
}
private Map<String, ?> hibernateJpaProperties( DataSource dataSource ) {
HashMap<String, String> properties = new HashMap<>();
// Need to copy these values over, otherwise c3p0 can't see them.
if( dataSource instanceof BasicDataSource ) {
BasicDataSource source = (BasicDataSource)p_dataSource;
properties.put( "hibernate.connection.driver_class", source.getDriverClassName() );
properties.put( "hibernate.connection.url", source.getUrl() );
properties.put( "hibernate.connection.username", source.getUsername() );
properties.put( "hibernate.connection.password", source.getPassword() );
}
// Added to avoid some merge problems when updating entities (eg contact to custimport)
properties.put( "hibernate.event.merge.entity_copy_observer", "allow" );
// Second level cache
properties.put( "hibernate.cache.use_second_level_cache", "true" );
properties.put( "hibernate.cache.use_query_cache", "true" );
properties.put( "hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider" );
properties.put( "hibernate.cache.region.factory_class", EhCacheRegionFactory.class.getName() );
properties.put( "hibernate.generate_statistics", "false" );
properties.put( "hibernate.show_sql", "false" );
properties.put( "hibernate.format_sql", "false" );
// validate | update | create | create-drop -->
properties.put( "hibernate.hbm2ddl.auto", "update" );
properties.put( "hibernate.dialect", MySQL5Dialect.class.getName() );
// [main] WARN org.hibernate.cfg.AnnotationBinder - HHH000457: Joined inheritance hierarchy [com.sw.system4.data.collateral.AbstractCollateral] defined explicit #DiscriminatorColumn. Legacy Hibernate behavior was to ignore the #DiscriminatorColumn. However, as part of issue HHH-6911 we now apply the explicit #DiscriminatorColumn. If you would prefer the legacy behavior, enable the `hibernate.discriminator.ignore_explicit_for_joined` setting (hibernate.discriminator.ignore_explicit_for_joined=true) -->
properties.put( "hibernate.discriminator.ignore_explicit_for_joined", "true" );
//properties.put("hibernate.hbm2ddl.import_files", "insert-data.sql");
//properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
// This wasnt required in persistence.xml, but for some reason is here.
properties.put( "hibernate.connection.provider_class", C3P0ConnectionProvider.class.getName() );
// just adding c3p0 props was enough in persistence.xml, but not here.
properties.put( "hibernate.c3p0.min_size", "5" );
properties.put( "hibernate.c3p0.max_size", "20" );
properties.put( "hibernate.c3p0.timeout", "300" ); // 5mins
properties.put( "hibernate.c3p0.max_statements", "50" );
properties.put( "hibernate.c3p0.idle_test_period", "100" );
properties.put( "hibernate.c3p0.preferredTestQuery", "select 1" );
properties.put( "hibernate.c3p0.testConnectionOnCheckout", "true" );
properties.put( "hibernate.c3p0.numHelperThreads", "12" );
properties.put( "hibernate.c3p0.maxStatementsPerConnection", "25" );
properties.put( "hibernate.c3p0.statementCacheNumDeferredCloseThreads", "1" );
return l_properties;
}
#Bean
public JpaTransactionManager transactionManager( EntityManagerFactory emf ) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory( emf );
return jpaTransactionManager;
}
}
What is your database? Is it a Cloud Database? I had a similar problem with CloudSQL. What happened was when some active connections didn't do anything with the database, from the database side, it rejects the connection after some hours. But on the application side, you will see it as an active connection. I have used Apache DBCP pool, and I was able to solve the problem using this in the database configurations.
dataSource.setValidationQuery("SELECT 1");
dataSource.setTestOnBorrow(true);
dataSource.setTestWhileIdle(true);
Because you are using C3P0, following commands should work for you.
hibernate.dbcp.testOnBorrow=true
hibernate.dbcp.testOnReturn=true
hibernate.dbcp.validationQuery=SELECT 1
Related
I'm developing a Vaadin Flow (version 14.1) app and I have this issue, I don't get it to connect directly with MySQL database.
I have set up the JDBC connection with maven, I've also created a singleton class I call Datasource where I store my values and methods. However right now it only has one as I'm testing this, this is what I want to do:
Click on a button on the app and update a label
Here's the button click listener:
button.addClickListener(click -> {
label.setText(Datasource.getInstance().getUsername());
});
Here's the Datasource class method:
public String getUsername() {
String username = "QUERY-FAILED";
try {
start();
statement = conn.createStatement();
ResultSet rs = statement.executeQuery("select * from names");
rs.next();
username = rs.getString(1);
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
return username;
}
But the label doesn't update, if I comment the try block it updates to QUERY-FAILED which is the string I put to test if it failed, but if it isn't commented the label just stays the same.
I also tried to add a main method to the Datasource class and run it as a Java application, and the method works fine, it does return a string with the username. So I'm guessing I'm stuck somewhere in between the connection with the vaadin app. Also, If I try to get the username String in my vaadin app when I'm starting the app (and not with a click listener) I got an long stack of errors with the Datasource indicating a nullpointerexception here:
statement = conn.createStatement();
Thanks in advance!
I cannot spot any problem with your code. But I can provide an entire working example app for you to compare
My example app goes along the lines laid out in your Question's code. A Vaadin Button performs a database query using a DataSource object from a table of user names. The value from the first row found is displayed in a Vaadin Label widget on the web page.
This app was built and run with Vaadin 14.1.5 using a "Plain Java Servlet" flavor of a starter project provided by the Vaadin.com site. Running on macOS Mojave with the bundled Jetty web container.
My only changes to their Maven POM file was to change to Java version 13, and to add a dependency for H2 Database Engine to make this a self-contained example using an in-memory database.
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
I used the hook for Vaadin starting, to establish my DataSource object and initialize the database. Following the manual, nested in the resources folder, I created folders META-INF > services. Per the Java SPI facility, there I created a file named com.vaadin.flow.server.VaadinServiceInitListener containing a single line to specify the name of my class that implements the interface named in the name of this file:
work.basil.example.ApplicationServiceInitListener
That is, my ApplicationServiceInitListener class implement the Vaadin interface VaadinServiceInitListener. My class will be automatically instantiated and its method invoked via that Java SPI facility when my Vaadin web app launches.
My ApplicationServiceInitListener class:
package work.basil.example;
import com.vaadin.flow.server.ServiceInitEvent;
import com.vaadin.flow.server.VaadinServiceInitListener;
import org.h2.jdbcx.JdbcDataSource;
public class ApplicationServiceInitListener implements VaadinServiceInitListener
{
#Override
public void serviceInit ( ServiceInitEvent serviceInitEvent )
{
System.out.println( "DEBUG Running `serviceInit` of " + this.getClass().getCanonicalName() );
// Database work.
prepareDataSource();
App.INSTANCE.provideDatabase().initializeDatabase();
}
private void prepareDataSource ( )
{
JdbcDataSource ds = new JdbcDataSource();
ds.setURL( "jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
App.INSTANCE.rememberDataSource( ds );
}
}
That class calls my App class which acts as a sort of service locator. Designed as a singleton via enum.
package work.basil.example;
import javax.sql.DataSource;
import java.util.Objects;
public enum App
{
INSTANCE;
// -------| DataSource |---------------------------------
private DataSource dataSource;
public DataSource provideDataSource ( )
{
return this.dataSource;
}
public void rememberDataSource ( DataSource dataSource )
{
this.dataSource = Objects.requireNonNull( dataSource );
}
// -------| Database |---------------------------------
private Database database;
public Database provideDatabase ( )
{
return new Database();
}
}
That class calls my Database class. In real work, Database would be an interface with various concrete implementations for testing versus deployment. I ignored that here for demonstration purposes.
package work.basil.example;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Database
{
public String getFirstUserName ( )
{
String userName = "QUERY-FAILED";
String newline = "\n";
StringBuilder sql = new StringBuilder();
sql.append( "SELECT name_ from user_ ; " ).append( newline );
System.out.println( "sql = " + sql );
try (
Connection conn = App.INSTANCE.provideDataSource().getConnection() ;
Statement statement = conn.createStatement() ;
ResultSet resultSet = statement.executeQuery( sql.toString() ) ;
)
{
while ( resultSet.next() )
{
userName = resultSet.getString( "name_" );
break; // Go no further. We need only the first row found.
}
}
catch ( SQLException e )
{
e.printStackTrace();
}
return userName;
}
public void initializeDatabase ( )
{
System.out.println( "DEBUG Running `initializeDatabase` of " + this.getClass().getCanonicalName() );
String newline = "\n";
// Create table.
StringBuilder sql = new StringBuilder();
sql.append( "CREATE TABLE user_ ( " ).append( newline );
sql.append( "pkey_ IDENTITY NOT NULL PRIMARY KEY , " ).append( newline ); // `identity` = auto-incrementing long integer.
sql.append( "name_ VARCHAR NOT NULL " ).append( newline );
sql.append( ") " ).append( newline );
sql.append( ";" ).append( newline );
System.out.println( "sql = " + sql );
try (
Connection conn = App.INSTANCE.provideDataSource().getConnection() ;
Statement statement = conn.createStatement() ;
)
{
statement.executeUpdate( sql.toString() );
}
catch ( SQLException e )
{
e.printStackTrace();
}
System.out.println("DEBUG Finished `CREATE TABLE` statement.");
// Populate table.
sql = new StringBuilder();
sql.append( "INSERT INTO user_ ( name_ ) " ).append( newline );
sql.append( "VALUES " ).append( newline );
sql.append( "( 'Alice' ) , " ).append( newline );
sql.append( "( 'Bob' ) , " ).append( newline );
sql.append( "( 'Carol' ) " ).append( newline );
sql.append( ";" ).append( newline );
System.out.println( "sql = " + sql );
try (
Connection conn = App.INSTANCE.provideDataSource().getConnection() ;
Statement statement = conn.createStatement() ;
)
{
int rowsAffected = statement.executeUpdate( sql.toString() );
System.out.println( "DEBUG Inserted rows into name_ table: " + rowsAffected );
}
catch ( SQLException e )
{
e.printStackTrace();
}
System.out.println("DEBUG Finished `INSERT` statement.");
}
}
And lastly, the MainView class. I disable the #PWA annotation as we are not using that feature for progressive web apps.
package work.basil.example;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
/**
* The main view contains a button and a click listener.
*/
#Route ( "" )
//#PWA ( name = "Project Base for Vaadin", shortName = "Project Base" )
public class MainView extends VerticalLayout
{
private Label label;
private Button button;
public MainView ( )
{
// Widgets
this.label = new Label( "User: ?" );
this.button = new Button(
"Get user" ,
event -> {
Notification.show( "Getting user." );
String userName = App.INSTANCE.provideDatabase().getFirstUserName();
this.label.setText( "User: " + userName );
}
);
add( button );
// Arrange
this.add( label , button );
}
}
You should check if the ResultSet rs actually has results. When calling rs.next(), look if it returns false. How to check if ResultSet is empty
public String getUsername() {
String username = "QUERY-FAILED";
try {
start();
statement = conn.createStatement();
ResultSet rs = statement.executeQuery("select userName from names");
if(rs.next() != false){
username = rs.getString(1);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
return username;
}
Another thing I noticed is that from the query select * from names, one cannot be sure that the userName attribute is the first column, which you are reading with rs.getString(1). Make sure to write your query more precise to avoid hard-to-find bugs: select userName from names; Do this even if the table only has one column, because what if somebody prepended another column? it could break your application.
In my project I am using cucumber with junit, maven and selenium webdriver inclusive with java and extent report.
My extent report is generated in an folder 'output' and within the same folder screenshot of failed test-cases are also saved.
After execution of test and generation of report I want to compress the folder 'output' into zip file and mail it.
Issue : At the instance when my code converts the file into zip format, the test-report is not yet generated (as it generates after completion of all test cases) so when 'output' folder is compressed it only contains the failed screenshot and same is being mailed..
Please suggest
this is my runner file
this is my hooks class
This is my runner class...............
#CucumberOptions(
features = {"featurefiles/DefineStaffType.feature"}
, glue = {"stepdefinitions"}
, monochrome = true
, plugin = {"pretty:STDOUT",
"json:target/cucumber.json",
"junit:target/cucumber.xml",
"com.cucumber.listener.ExtentCucumberFormatter:output/report.html"}
, tags = {"#Scenario1, #Scenario2, #Scenario3"}
)
public class DefineStaffTypeRunner {
#AfterClass
public static void reportSetup ( ) throws IOException, EmailException {
Reporter.loadXMLConfig ( new File ( "configuration\\extentconfig.xml" ) );
Reporter.setSystemInfo ( "User Name", System.getProperty ( "user.name" ) );
Reporter.setSystemInfo ( "Time Zone", System.getProperty ( "user.timezone" ) );
Reporter.setSystemInfo ( "64 Bit", "Windows 10" );
Reporter.setSystemInfo ( "3.1.0", "Selenium" );
Reporter.setSystemInfo ( "1.9", "Maven" );
Reporter.setSystemInfo ( "1.9", "Java Version" );
Reporter.setTestRunnerOutput ( "Define Staff Type " );
FileConversion.convertToZip ( "output" );
new MailHandlingUtility ( ).sendMailWithAttachment ( );
}
}
This is my hooks class
public class CucumberHooks extends GenericBaseClass {
DriverMethods dm = new DriverMethods ( );
CaptureScreenshot cs = new CaptureScreenshot ( );
static MailHandlingUtility mhu = new MailHandlingUtility ( );
#Before
public void launchBrowser (Scenario currentscenario) throws IOException {
this.scenario = currentscenario;
driver = getCurrentDriver ( );
dm.maximizeWindow ( );
}
#After
public void tearDownScenario (Scenario currentscenario) throws IOException, EmailException {
scenario.write ( "Scenario is finished" + currentscenario );
cs.catureScreenshot ( (Scenario) scenario );
driver.close ( );
driver.quit ( );
driver = null;
}
}
I have to work with an already existing Eclipse RAP application which contains of two features and around 40 dependencies.
Since the Eclipse RAP doesn't have a preStartup() method I call the update procedure in the RAP's start() method:
public class MyApplication implements IApplication
{
#Override
public Object start( IApplicationContext context ) throws Exception
{
P2Util.update();
...
}
}
The IProvisioningAgent is not null, the IMetadataRepositoryManager and IArtifactRepositoryManager are correctly initialized.
public static boolean configureRepository( IProvisioningAgent agent )
{
String repo = "file:///c:/export/repository/"; // TODO HERE!
log.debug( "Initiliazing Repository Managers" );
IMetadataRepositoryManager metadataManager = ( IMetadataRepositoryManager ) agent.getService( IMetadataRepositoryManager.SERVICE_NAME );
IArtifactRepositoryManager artifactManager = ( IArtifactRepositoryManager ) agent.getService( IArtifactRepositoryManager.SERVICE_NAME );
URI uri;
try
{
uri = new URI( repo );
}
catch ( URISyntaxException e1 )
{
log.error( "Unexpected URISyntaxException, the specified path is not a valid URI", e1 ); //$NON-NLS-1$
return false;
}
if ( metadataManager == null )
{
log.error( "IMetadataRepositoryManager instance is null!" );
return false;
}
metadataManager.addRepository( uri );
log.debug( "Added repository to MetadataManager: " + repo );
if ( artifactManager == null )
{
log.error( "IArtifactRepositoryManager instance is null!" );
return false;
}
artifactManager.addRepository( uri );
log.debug( "Added repository to ArtifactManager: " + repo );
return true;
}
Still one problem occurs all the time after I call checkForUpdates().
public static IStatus checkForUpdates( IProvisioningAgent agent ) throws OperationCanceledException
{
log.info( "Checking for new updates in repository" );
ProvisioningSession session = new ProvisioningSession( agent );
UpdateOperation operation = new UpdateOperation( session );
IStatus status = operation.resolveModal( new NullProgressMonitor() );
return status;
}
It returns the following status:
Status OK: org.eclipse.equinox.p2.operations code=10001 Your original request has been modified. null children=[]
I have already checked the flag "Support software installation in the launched application" in my run configuration, the problem persists.
I'm experimenting with Neo4J via Embedded Java API.
My Build path seems ok (no Exceptions during runtime).
When I create some nodes and relations, I can query it directly after it with success.
But after shutting down and re-run my programm, i'm only getting the data I created in the new runtime and none of them before.
But if I look at my directory, I see, that the size has grown with each runtime, I perform a creating of data.
Here's my code:
public static void main(String[] args)
{
GraphDatabaseService gdb = new GraphDatabaseFactory().newEmbeddedDatabase( "/mytestdb/" );
create( gdb );
query( gdb );
gdb.shutdown();
}
private static void query( GraphDatabaseService gdb )
{
StringLogger sl = StringLogger.wrap( new Writer()
{
#Override
public void write( char[] arg0, int arg1, int arg2 ) throws IOException
{
for( int i=arg1; i<=arg2; i++ ) System.out.print( arg0[i] );
}
#Override
public void flush() throws IOException
{}
#Override
public void close() throws IOException
{}
} );
ExecutionEngine ee = new ExecutionEngine( gdb, sl );
ExecutionResult result = ee.execute( "MATCH (p:Privilleg) RETURN p" );
System.out.println( result.dumpToString() );
}
private static void create( GraphDatabaseService gdb )
{
Transaction tx = gdb.beginTx();
Node project = gdb.createNode( MyLabels.Project );
Node user = gdb.createNode( MyLabels.User );
Node priv1 = gdb.createNode( MyLabels.Privilleg );
Node priv2 = gdb.createNode( MyLabels.Privilleg );
user.setProperty( "name", "Heinz" );
user.setProperty( "email", "heinz#gmx.net" );
priv1.setProperty( "name", "Allowed to read all" );
priv1.setProperty( "targets", Short.MAX_VALUE );
priv1.setProperty( "read", true );
priv1.setProperty( "write", false );
priv2.setProperty( "name", "Allowed to write all" );
priv2.setProperty( "targets", Short.MAX_VALUE );
priv2.setProperty( "read", false );
priv2.setProperty( "write", true );
project.setProperty( "name", "My first project" );
project.setProperty( "sname", "STARTUP" );
user.createRelationshipTo( priv1, MyRelationships.UserPrivilleg );
user.createRelationshipTo( priv2, MyRelationships.UserPrivilleg );
priv1.createRelationshipTo( project, MyRelationships.ProjectPrivilleg );
priv2.createRelationshipTo( project, MyRelationships.ProjectPrivilleg );
tx.success();
}
Your code doesn't close the transaction. Typically you use a try-with-resources block:
try (Transaction tx=gdb.beginTx()) {
// do stuff in the graph
tx.success();
}
Since Transaction is AutoClosable its close() method will be called implicitly upon leaving the code block. If (for whatever) reason you decide not to use try-with-resources, be sure to explicitly call close().
On a different notice: your code uses ExecutionEngine. Since Neo4j 2.2 you directly call gdb.execute(myCypherString) instead.
Thank you! This works.
Also, before I closed the transaction, it takes about 20 seconds to shuting down the db. This also is now less than a second.
I'm implementing a Java RESTful webservice on Heroku. Currently my entry point looks like
public class Main
{
public static final String BASE_URI = getBaseURI();
public static void main( String[] args ) throws Exception
{
final Map<String, String> initParams = new HashMap<String, String>();
initParams.put( "com.sun.jersey.config.property.packages", "services.contracts" );
initParams.put( "com.sun.jersey.api.json.POJOMappingFeature", "true" );
System.out.println( "Starting grizzly..." );
SelectorThread threadSelector =
GrizzlyWebContainerFactory.create( BASE_URI, initParams );
System.out.println( String.format( "Jersey started with WADL available at %sapplication.wadl.", BASE_URI,
BASE_URI ) );
}
private static String getBaseURI()
{
return "http://localhost:" + ( System.getenv( "PORT" ) != null ? System.getenv( "PORT" ) : "9998" ) + "/";
}
}
where the initParms contains RESTful services being hosted. I understand that GrizzlyWebContainerFactory.create() returns an instance of ServletContainer (SelectorThread), but how would I multithread the returned threadSelector such that multiple SelectorThread's can handle the incoming requests under one process (aka web dyno)? The reason is to increase performance of a single dyno in handling requests.
Any suggestions appreciated! Thanks!
You can call:
SelectorThread.setSelectorReadThreadsCount(int)