Why does my java project in GCP can't create entityManagerFactory? - java

I've uploaded a java spring-boot project to GCP. When I enter the server's url in the browser, I get status code 500. I checked the error reporting in GCP and this is what I see (MovieTown is the project's name):
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean ( org/springframework.beans.factory.support/AbstractAutowireCapableBeanFactory.java:1804 )
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean ( org/springframework.beans.factory.support/AbstractAutowireCapableBeanFactory.java:620 )
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean ( org/springframework.beans.factory.support/AbstractAutowireCapableBeanFactory.java:542 )
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0 ( org/springframework.beans.factory.support/AbstractBeanFactory.java:335 )
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton ( org/springframework.beans.factory.support/DefaultSingletonBeanRegistry.java:234 )
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean ( org/springframework.beans.factory.support/AbstractBeanFactory.java:333 )
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean ( org/springframework.beans.factory.support/AbstractBeanFactory.java:208 )
at org.springframework.context.support.AbstractApplicationContext.getBean ( org/springframework.context.support/AbstractApplicationContext.java:1154 )
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization ( org/springframework.context.support/AbstractApplicationContext.java:908 )
at org.springframework.context.support.AbstractApplicationContext.refresh ( org/springframework.context.support/AbstractApplicationContext.java:583 )
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh ( org/springframework.boot.web.servlet.context/ServletWebServerApplicationContext.java:147 )
at org.springframework.boot.SpringApplication.refresh ( org/springframework.boot/SpringApplication.java:734 )
at org.springframework.boot.SpringApplication.refreshContext ( org/springframework.boot/SpringApplication.java:408 )
at org.springframework.boot.SpringApplication.run ( org/springframework.boot/SpringApplication.java:308 )
at org.springframework.boot.SpringApplication.run ( org/springframework.boot/SpringApplication.java:1306 )
at org.springframework.boot.SpringApplication.run ( org/springframework.boot/SpringApplication.java:1295 )
at com.MovieTown.MovieTownApplication.main ( com/MovieTown/MovieTownApplication.java:15 )
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke ( jdk/internal.reflect/NativeMethodAccessorImpl.java:77 )
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke ( jdk/internal.reflect/DelegatingMethodAccessorImpl.java:43 )
at java.lang.reflect.Method.invoke ( java/lang.reflect/Method.java:568 )
at org.springframework.boot.loader.MainMethodRunner.run ( org/springframework.boot.loader/MainMethodRunner.java:49 )
at org.springframework.boot.loader.Launcher.launch ( org/springframework.boot.loader/Launcher.java:108 )
at org.springframework.boot.loader.Launcher.launch ( org/springframework.boot.loader/Launcher.java:58 )
at org.springframework.boot.loader.JarLauncher.main ( org/springframework.boot.loader/JarLauncher.java:65 )
Caused by: org.hibernate.service.spi.ServiceException
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService ( AbstractServiceRegistryImpl.java:275 )
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService ( AbstractServiceRegistryImpl.java:237 )
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService ( AbstractServiceRegistryImpl.java:214 )
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices ( DefaultIdentifierGeneratorFactory.java:175 )
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies ( AbstractServiceRegistryImpl.java:286 )
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService ( AbstractServiceRegistryImpl.java:243 )
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService ( AbstractServiceRegistryImpl.java:214 )
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init> ( InFlightMetadataCollectorImpl.java:173 )
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete ( MetadataBuildingProcess.java:127 )
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata ( EntityManagerFactoryBuilderImpl.java:1460 )
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build ( EntityManagerFactoryBuilderImpl.java:1494 )
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory ( SpringHibernateJpaPersistenceProvider.java:58 )
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory ( LocalContainerEntityManagerFactoryBean.java:365 )
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory ( AbstractEntityManagerFactoryBean.java:409 )
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet ( AbstractEntityManagerFactoryBean.java:396 )
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet ( LocalContainerEntityManagerFactoryBean.java:341 )
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods ( AbstractAutowireCapableBeanFactory.java:1863 )
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean ( AbstractAutowireCapableBeanFactory.java:1800 )
…
I've already created a mySQL instance. I also changed the application.properties so my project will connect to it, and when I run my project locally, it connects to it successfully.
Did I miss something or did something wrong?

Related

Load Drools Guided Decision Table to Java List/Map

Hi I was wondering if there is a way to load all the content of the guided decision table to java collection (list/map)? I achieved this by making each rule(row) calling a java method where I add this to a hashmap but performance-wise is really bad I was wondering if there is a better way to do so. Thanks in advance!
[![enter image description here]
package MyPkg;
import com.abc.por.model.Bborder;
import com.abc.por.utils.BborderUtil;
import com.abc.por.utils.MyUtil;
import com.abc.por.model.constants.FE;
//from row number: 1
//PRE_Regression
rule "Row 1 HPDT"
#RuleName(OnlyOnePharmacy)
no-loop true
lock-on-active true
ruleflow-group "HighPayer"
dialect "mvel"
when
borderUtil : BborderUtil( )
Bborder( src : src == "SPECIAL" )
border : Bborder( requestDateTime >= "24-Dec-2020" , requestDateTime < "03-May-2022" )
then
MyUtil myUtil = new MyUtil();
myUtil.setPlanCode( "RGC" );
myUtil.setPlanType( "RGC" );
myUtil.setFeIndicator( "NO" );
myUtil.setPharmacies( "RED" );
insert( myUtil );
modify( borderUtil ) {
setRuleFired( true )
}
borderUtil.populateDrugDataToMap( null, myUtil, border );
retract( myUtil);
end
//from row number: 2
//PRE_Regression
rule "Row 2 HPDT"
#RuleName(SinglePharmacy)
no-loop true
lock-on-active true
ruleflow-group "HighPayer"
dialect "mvel"
when
borderUtil : BborderUtil( )
Bborder( src : src == "SPECIAL" )
border : Bborder( requestDateTime >= "24-Dec-2020" )
then
MyUtil myUtil = new MyUtil();
myUtil.setPlanCode( "RGA" );
myUtil.setPlanType( "RGA" );
myUtil.setFeIndicator( "NO" );
myUtil.setPharmacies( "MPT,RED" );
insert( myUtil );
modify( borderUtil ) {
setRuleFired( true )
}
borderUtil.populateDrugDataToMap( null, myUtil, border );
retract( myUtil);
end
//from row number: 3
//PRE_Regression
rule "Row 3 HPDT"
#RuleName(FE=BE)
no-loop true
lock-on-active true
ruleflow-group "HighPayer"
dialect "mvel"
when
borderUtil : BborderUtil( )
Bborder( src : src == "SPECIAL" )
border : Bborder( requestDateTime >= "24-Dec-2020" )
then
MyUtil myUtil = new MyUtil();
myUtil.setPlanCode( "RGB" );
myUtil.setPlanType( "RGB" );
myUtil.setFeIndicator( "YES" );
myUtil.setPharmacies( "MPT,RED" );
insert( myUtil );
modify( borderUtil ) {
setRuleFired( true )
}
borderUtil.populateDrugDataToMap( null, myUtil, border );
retract( myUtil);
end

Integrating BIRT with Esproc

We've been using Esproc with our BIRT reports for a while now and everything worked perfectly. We followed this tutorial and things worked. However, the latest version of their software incorporated a couple of new functionalities and as such, we now need to upgrade the version running with BIRT. The thing is that now, nothing's working. We keep getting NullPointerException when trying to run reports. This is what we're getting so far:
The following report will be sent to Eclipse:
------
STATUS
------
pluginId org.eclipse.jface
pluginVersion 3.12.0.v20160518-1929
code 2
severity 4
message Problems occurred when invoking code from plug-in: "org.eclipse.jface".
fingerprint eb22eddc61b2abbaef12193bb7441fab
Exception:java.lang.NullPointerException: null
at com.esproc.jdbc.Server.getDfxList(Unknown Source:88)
at com.esproc.jdbc.InternalConnection.getMetaData(Unknown Source:314)
at org.eclipse.birt.report.data.oda.jdbc.ui.provider.JdbcMetaDataProvider.isSupportSchema(JdbcMetaDataProvider.java:305)
at org.eclipse.birt.report.data.oda.jdbc.ui.editors.SQLDataSetEditorPage.createDBMetaDataSelectionComposite(SQLDataSetEditorPage.java:405)
at org.eclipse.birt.report.data.oda.jdbc.ui.editors.SQLDataSetEditorPage.createPageControl(SQLDataSetEditorPage.java:334)
at org.eclipse.birt.report.data.oda.jdbc.ui.editors.SQLDataSetEditorPage.createPageCustomControl(SQLDataSetEditorPage.java:307)
at org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage.createControl(DataSetWizardPage.java:123)
at org.eclipse.datatools.connectivity.oda.design.internal.ui.DataSetEditorPageCore.createContents(DataSetEditorPageCore.java:74)
at org.eclipse.jface.preference.PreferencePage.createControl(PreferencePage.java:241)
at org.eclipse.birt.report.designer.data.ui.dataset.PropertyPageWrapper.createPageControl(PropertyPageWrapper.java:61)
at org.eclipse.birt.report.designer.data.ui.property.PropertyNode.createPageControl(PropertyNode.java:238)
at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.showPage(AbstractPropertyDialog.java:577)
at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.showSelectionPage(AbstractPropertyDialog.java:482)
at org.eclipse.birt.report.designer.data.ui.dataset.DataSetEditor.showSelectionPage(DataSetEditor.java:913)
at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog$2$1.run(AbstractPropertyDialog.java:438)
at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog$2.selectionChanged(AbstractPropertyDialog.java:433)
at org.eclipse.jface.viewers.Viewer$1.run(Viewer.java:158)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:50)
at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:173)
at org.eclipse.jface.viewers.Viewer.fireSelectionChanged(Viewer.java:155)
at org.eclipse.jface.viewers.StructuredViewer.updateSelection(StructuredViewer.java:2191)
at org.eclipse.jface.viewers.StructuredViewer.setSelection(StructuredViewer.java:1728)
at org.eclipse.jface.viewers.TreeViewer.setSelection(TreeViewer.java:1077)
at org.eclipse.jface.viewers.Viewer.setSelection(Viewer.java:383)
at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.initTreeSelection(AbstractPropertyDialog.java:408)
at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.createDialogArea(AbstractPropertyDialog.java:299)
at org.eclipse.birt.report.designer.data.ui.dataset.DataSetEditor.createDialogArea(DataSetEditor.java:124)
at org.eclipse.jface.dialogs.Dialog.createContents(Dialog.java:767)
at org.eclipse.birt.report.designer.data.ui.dataset.DataSetEditor.createContents(DataSetEditor.java:602)
at org.eclipse.jface.window.Window.create(Window.java:426)
at org.eclipse.jface.dialogs.Dialog.create(Dialog.java:1095)
at org.eclipse.birt.report.designer.ui.dialogs.BaseDialog.open(BaseDialog.java:107)
at org.eclipse.birt.report.designer.data.ui.actions.EditDataSetAction.doAction(EditDataSetAction.java:105)
at org.eclipse.birt.report.designer.internal.ui.views.actions.AbstractElementAction.run(AbstractElementAction.java:70)
at org.eclipse.jface.action.Action.runWithEvent(Action.java:473)
at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:565)
at org.eclipse.jface.action.ActionContributionItem.lambda$4(ActionContributionItem.java:397)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4410)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1079)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4228)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3816)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:1121)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1022)
at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:150)
at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:687)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:604)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:148)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:138)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:388)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:243)
at sun.reflect.NativeMethodAccessorImpl.invoke0(null:-2)
at sun.reflect.NativeMethodAccessorImpl.invoke(null:-1)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(null:-1)
at java.lang.reflect.Method.invoke(null:-1)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:673)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:610)
at org.eclipse.equinox.launcher.Main.run(Main.java:1519)
------
REPORT
------
anonymousId 12355fbc-cb0f-41c4-b330-1d4a60fd5df2
name
email
comment
eclipseBuildId 4.6.0.I20160606-1100
eclipseProduct org.eclipse.epp.package.reporting.product
javaRuntimeVersion 1.8.0_71-b15
osgiWs win32
osgiOs Windows10
osgiOsVersion 10.0.0
osgiArch x86_64
severity UNKNOWN
-------
BUNDLES
-------
name org.eclipse.birt.report.data.oda.jdbc.ui
version 4.6.0.v201606072122
name org.eclipse.birt.report.data.oda.jdbc
version 4.6.0.v201606072122
name org.eclipse.birt
version 4.6.0.v201606072122
name org.eclipse.birt.report.designer.ui
version 4.6.0.v201606072122
name org.eclipse.birt.report.designer.ui.views
version 4.6.0.v201606072122
name org.eclipse.core.databinding.observable
version 1.6.0.v20160511-1747
name org.eclipse.core.databinding
version 1.6.0.v20160412-0910
name org.eclipse.core.runtime
version 3.12.0.v20160606-1342
name org.eclipse.datatools.connectivity.oda.design.ui
version 3.3.0.201603142002
name org.eclipse.datatools.connectivity.oda.design
version 3.4.0.201603142002
name org.eclipse.datatools.connectivity.oda
version 3.5.0.201603142002
name org.eclipse.datatools.connectivity
version 1.13.0.201603142002
name org.eclipse.e4.ui.workbench
version 1.4.0.v20160517-1624
name org.eclipse.e4.ui.workbench.swt
version 0.14.0.v20160523-1900
name org.eclipse.equinox.app
version 1.3.400.v20150715-1528
name org.eclipse.equinox.launcher
version 1.3.200.v20160318-1642
name org.eclipse.jface
version 3.12.0.v20160518-1929
name org.eclipse.swt
version 3.105.0.v20160603-0902
name org.eclipse.ui
version 3.108.0.v20160518-1929
name org.eclipse.ui.ide.application
version 1.1.100.v20160518-1929
name org.eclipse.ui.ide
version 3.12.0.v20160601-1609
Anyone has any idea what's going on?
Thanks
Okay, so I was able to actually get things working and the solution isn't exactly what I'd call trivial. I actually had to modify and recompile three BIRT classes. You can easily get the source code here if you don't want to do the Google search. Anyway, our first modification is given to us by the error message cited above. We need to alter JdbcMetaDataProvider.java located in the org.eclipse.birt.report.data.oda.jdbc.ui_4.6.0.v201606072122.jar package. What we're looking for is the isSupportSchema() method. and more specifically this bit of code:
try
{
return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
}
catch ( SQLException e )
{
try
{
reconnect( );
return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
}
catch ( Exception e1 )
{
try
{
ResultSet rs = connection.getMetaData( ).getSchemas( );
if( rs != null )
return true;
else
return false;
}
catch (SQLException e2)
{
logger.log( Level.WARNING, e.getMessage( ), e1 );
return false;
}
}
}
Not having access to Esproc's code, I can't exactly say why it does this, but connection.getMetaData( ).supportsSchemasInTableDefinitions( ); throws a NullPointerException. With no "catch" block to treat said exception, Eclipse will just stop its execution and prevent you from accessing your dataset. So we need to fix that like so:
try
{
return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
}
catch ( SQLException e )
{
try
{
reconnect( );
return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
}
catch ( Exception e1 )
{
try
{
ResultSet rs = connection.getMetaData( ).getSchemas( );
if( rs != null )
return true;
else
return false;
}
catch (SQLException e2)
{
logger.log( Level.WARNING, e.getMessage( ), e1 );
return false;
}
}
}
catch (NullPointerException e)
{
return false;
}
Now then, the next two bits of code we need to alter are located in the oda-jdbc.jar package. The first one we're looking for is the Connection.java class and more specifically the method populateConnectionProp( ).
private void populateConnectionProp( ) throws SQLException
{
if( jdbcConn!= null )
{
if( this.autoCommit != null )
jdbcConn.setAutoCommit( this.autoCommit );
else
{
if (DBConfig.getInstance().qualifyPolicy(
jdbcConn.getMetaData().getDriverName(),
DBConfig.SET_COMMIT_TO_FALSE) ) {
this.autoCommit = false;
jdbcConn.setAutoCommit( false );
}
}
if( this.isolationMode!= Constants.TRANSCATION_ISOLATION_DEFAULT)
jdbcConn.setTransactionIsolation( this.isolationMode );
}
}
This time the culprit throwing a NullPointerException is this line jdbcConn.getMetaData().getDriverName(). Again, not having access to Esproc's code, I don't really know why trying to recover the driver's name doesn't work, but anyway all we need to do is actually catch the exception and things will work normally again:
private void populateConnectionProp( ) throws SQLException
{
if( jdbcConn!= null )
{
if( this.autoCommit != null )
jdbcConn.setAutoCommit( this.autoCommit );
else
{
try
{
if (DBConfig.getInstance().qualifyPolicy(
jdbcConn.getMetaData().getDriverName(),
DBConfig.SET_COMMIT_TO_FALSE) ) {
this.autoCommit = false;
jdbcConn.setAutoCommit( false );
}
}
catch(NullPointerException e)
{
this.autoCommit = false;
jdbcConn.setAutoCommit( false );
}
}
if( this.isolationMode!= Constants.TRANSCATION_ISOLATION_DEFAULT)
jdbcConn.setTransactionIsolation( this.isolationMode );
}
}
The other class we're looking for is the CallStatement.java class. In it we're going to have to locate the getCallableParamMetaData() method that I've pasted below:
private java.util.List getCallableParamMetaData( )
{
java.util.List paramMetaDataList = new ArrayList( );
try
{
DatabaseMetaData metaData = conn.getMetaData( );
String cataLog = conn.getCatalog( );
String procedureNamePattern = getNamePattern( this.paramUtil.getProcedure( ) );
String schemaPattern = null;
if ( this.paramUtil.getSchema( ) != null )
{
schemaPattern = getNamePattern( this.paramUtil.getSchema( ) );
}
// handles schema.package.storedprocedure for databases such as
// Oracle
if ( !metaData.supportsCatalogsInProcedureCalls( ) )
{
if (this.paramUtil.getPackage( ) != null)
{
cataLog = getNamePattern( this.paramUtil.getPackage( ) );
}
}
java.sql.ResultSet rs = null;
rs = metaData.getProcedureColumns( cataLog,
schemaPattern,
procedureNamePattern,
null );
while ( rs.next( ) )
{
ParameterDefn p = new ParameterDefn( );
p.setParamName( rs.getString( "COLUMN_NAME" ) );
p.setParamInOutType( rs.getInt( "COLUMN_TYPE" ) );
p.setParamType( rs.getInt( "DATA_TYPE" ) );
p.setParamTypeName( rs.getString( "TYPE_NAME" ) );
p.setPrecision( rs.getInt( "PRECISION" ) );
p.setScale( rs.getInt( "SCALE" ) );
p.setIsNullable( rs.getInt( "NULLABLE" ) );
if ( p.getParamType( ) == Types.OTHER )
correctParamType( p );
paramMetaDataList.add( p );
}
rs.close( );
}
catch ( SQLException e )
{
logger.log( Level.SEVERE, "Fail to get SP paramters", e );
}
catch( JDBCException ex)
{
logger.log( Level.SEVERE, "Fail to get SP paramters", ex );
}
return paramMetaDataList;
}
Basically, somewhere within the while ( rs.next( ) ) loop lies the culprit throwing the NullPointerException. So all we need to do to is add a catch statement to treat it as follow:
private java.util.List getCallableParamMetaData( )
{
java.util.List paramMetaDataList = new ArrayList( );
try
{
DatabaseMetaData metaData = conn.getMetaData( );
String cataLog = conn.getCatalog( );
String procedureNamePattern = getNamePattern( this.paramUtil.getProcedure( ) );
String schemaPattern = null;
if ( this.paramUtil.getSchema( ) != null )
{
schemaPattern = getNamePattern( this.paramUtil.getSchema( ) );
}
// handles schema.package.storedprocedure for databases such as
// Oracle
if ( !metaData.supportsCatalogsInProcedureCalls( ) )
{
if (this.paramUtil.getPackage( ) != null)
{
cataLog = getNamePattern( this.paramUtil.getPackage( ) );
}
}
java.sql.ResultSet rs = null;
rs = metaData.getProcedureColumns( cataLog,
schemaPattern,
procedureNamePattern,
null );
while ( rs.next( ) )
{
ParameterDefn p = new ParameterDefn( );
p.setParamName( rs.getString( "COLUMN_NAME" ) );
p.setParamInOutType( rs.getInt( "COLUMN_TYPE" ) );
p.setParamType( rs.getInt( "DATA_TYPE" ) );
p.setParamTypeName( rs.getString( "TYPE_NAME" ) );
p.setPrecision( rs.getInt( "PRECISION" ) );
p.setScale( rs.getInt( "SCALE" ) );
p.setIsNullable( rs.getInt( "NULLABLE" ) );
if ( p.getParamType( ) == Types.OTHER )
correctParamType( p );
paramMetaDataList.add( p );
}
rs.close( );
}
catch ( SQLException e )
{
logger.log( Level.SEVERE, "Fail to get SP paramters", e );
}
catch( JDBCException ex)
{
logger.log( Level.SEVERE, "Fail to get SP paramters", ex );
}
catch( NullPointerException ex1)
{
logger.log( Level.SEVERE, "Fail to get SP paramters", ex1 );
}
return paramMetaDataList;
}
Once you've done your modifications to the files, you actually need to recompile your source code. To do this successfully, you're going to need to copy a couple of jars from Eclipse's plugin folder into the same folder as where you've placed the file you're trying to compile. The jars are given below in the command you need to enter to compile your source code. Here's what you need to enter in order to compile each file:
JdbcMetaDataProvider.java
javac -cp ".;
c:/mypath/org.eclipse.birt.report.data.bidi.utils_4.6.0.v201606072122.jar;
c:/mypath/org.eclipse.birt.report.data.oda.jdbc.ui_4.6.0.v201606072122.jar;
c:/mypath/oda-jdbc.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda_3.5.0.201603142002.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda.design_3.4.0.201603142002.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda.design.ui_3.3.0.201603142002.jar;
c:/mypath/org.eclipse.emf.ecore_2.12.0.v20160420-0247.jar;
c:/mypath/org.eclipse.emf.common_2.12.0.v20160420-0247.jar" JdbcMetaDataProvider.java > log.txt 2>&1
Connection.java
javac -cp ".;
c:/mypath/org.eclipse.birt.report.data.bidi.utils_4.6.0.v201606072122.jar;
c:/mypath/oda-jdbc.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda_3.5.0.201603142002.jar;
c:/mypath/com.ibm.icu_56.1.0.v201601250100.jar" Connection.java > log.txt 2>&1
CallStatement.java
javac -cp ".;
c:/mypath/oda-jdbc.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda_3.5.0.201603142002.jar;
c:/mypath/com.ibm.icu_56.1.0.v201601250100.jar" CallStatement.java > log.txt 2>&1
Now, there's a couple of things that need to be said about the two above commands:
1) They actually need to be entered on one line. I merely broke them down like so for clarity purposes so that each jar needed was easy to spot.
2) This is actually a windows command. If you're running the command on Linux, each jar needs to be separated by a colon(:) instead of a semi-colon(;).
Once the compilation is successful, you'll end up with the following .class files:
JdbcMetaDataProvider$1TempThread.class
JdbcMetaDataProvider$2TempThread.class
JdbcMetaDataProvider.class
Connection$Constants.class
Connection.class
CallStatement.class
These need to be copied back into the original jar files so that they replace the files already there. Luckily, a jar file is nothing more than a zip file so in windows, any unzipping software will easily open things up for you and allow you to navigate to the proper folder.
Here are the the folders in question for each jar:
org\eclipse\birt\report\data\oda\jdbc\ui\provider\
org\eclipse\birt\report\data\oda\jdbc\
org\eclipse\birt\report\data\oda\jdbc\
Once that's done, restart Eclipse and things should work like normal again. I hope this helps someone in the future.

JNI attached to program successfully but cant get fields?

stackoverflow!
I managed to inject my dll into the game minecraft(made in java) and i did attach to the main thread so i can get classes and field.
Total code:
#include <Windows.h>
#include <jni.h>
#include <iostream>
#include <string>
#include "MCClass.h"
/*
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
*/
typedef jint (*hJNI_GetCreatedJavaVMs )( JavaVM** vmBuf , jsize bufLen , jsize* nVMs );
hJNI_GetCreatedJavaVMs oJNI_GetCreatedJavaVMs;
HMODULE jvmHandle;
FARPROC func_JNI_GetCreatedJavaVMs;
JavaVM *jvm;
JNIEnv *jenv;
jclass Minecraft;
jclass FMLH;
jclass FMLHI;
jclass launchWrapper;
MCClass* mc = new MCClass ( );
using namespace std;
void GetAllMinecraft ( )
{
jfieldID f = jenv->GetFieldID ( Minecraft , "serverName" , "Ljava/lang/String;" );
if ( f != NULL )
{
jstring str = (jstring)jenv->GetObjectField ( Minecraft , f );
mc->serverName = (char*)jenv->GetStringUTFChars( str , 0 );
cout << mc->serverName << endl;
}
else
{
MessageBox ( NULL , "serverName is null", "ERROR" , MB_OK );
}
}
/*
void start ( )
{
MessageBox ( NULL , "Initialization has completed." , "Works" , MB_OK );
FMLH = jenv->FindClass ( "net/minecraftforge/fml/relauncher/FMLLaunchHandler" );
if ( FMLH != nullptr )
{
MessageBox ( NULL , "FMLLaunchHandler found successfully" , "OK" , MB_OK );
jfieldID f = jenv->GetStaticFieldID ( (jclass) FMLH , "INSTANCE" , "Lnet/minecraftforge/fml/relauncher/FMLLaunchHandler;" );
MessageBox ( NULL , "FMLH passed" , "OK" , MB_OK );
if ( f == nullptr )
{
MessageBox ( NULL , "FMLLaunchHandler fieldID couldn't be found successfully" , "OK" , MB_OK );
}
else
{
MessageBox ( NULL , "FMLLaunchHandler fieldID found successfully" , "OK" , MB_OK );
FMLHI = jenv->GetStaticObjectField ( (jclass) FMLH , f );
MessageBox ( NULL , "FMLHI passed" , "OK" , MB_OK );
if ( FMLHI == nullptr )
{
MessageBox ( NULL , "FMLLaunchHandler instance couldn't be found successfully" , "OK" , MB_OK );
}
else
{
MessageBox ( NULL , "FMLHI is not nullptr" , "OK" , MB_OK );
jfieldID f1 = jenv->GetFieldID ( ( jclass ) FMLHI , "classLoader" , "Lnet/minecraft/launchwrapper/LaunchClassLoader;" ); //HERE
MessageBox ( NULL , "f1 passed" , "OK" , MB_OK );
if ( f1 == nullptr )
{
MessageBox ( NULL , "classLoader fieldID couldn't be found successfully" , "OK" , MB_OK );
}
else
{
MessageBox ( NULL , "classLoader fieldID found successfully" , "OK" , MB_OK );
launchWrapper = jenv->GetObjectField ( ( jclass ) FMLHI , f1 );
MessageBox ( NULL , "launchWrapper passed" , "OK" , MB_OK );
if ( launchWrapper == nullptr )
{
MessageBox ( NULL , "classLoader class couldn't be found successfully" , "OK" , MB_OK );
}
else
{
MessageBox ( NULL , "classLoader class found successfully" , "OK" , MB_OK );
jmethodID mmid = jenv->GetMethodID ( ( jclass ) launchWrapper , "findClass" , "(Ljava/lang/String;)Ljava/lang/Class;" );
MessageBox ( NULL , "findClass passed" , "OK" , MB_OK );
if ( mmid != NULL )
{
Minecraft = ( jclass ) jenv->CallNonvirtualObjectMethod ( launchWrapper , ( jclass ) launchWrapper , mmid , "net.minecraft.client.Minecraft" );
MessageBox ( NULL , "Minecraft class found successfully" , "OK" , MB_OK );
// GetAllMinecraft ( );
}
else
{
MessageBox ( NULL , "findClass method ID couldn't be found successfully" , "OK" , MB_OK );
}
}
}
}
}
}
else
{
MessageBox ( NULL , "FMLLaunchHandler couldn't be found successfully" , "OK" , MB_OK );
}
}
*/
const char* GetObjName ( jobject cls )
{
jclass clsClazz = jenv->GetObjectClass ( cls );
jmethodID methodId = jenv->GetMethodID ( clsClazz , "getName" , "()Ljava/lang/String;" );
jstring className = ( jstring ) jenv->CallObjectMethod ( cls , methodId );
return jenv->GetStringUTFChars ( className , NULL );
jenv->DeleteLocalRef ( clsClazz );
}
void start ( )
{
jclass preMC = jenv->FindClass ( "net/minecraftforge/fml/relauncher/FMLLaunchHandler" );
if ( preMC != NULL )
{
/*Section intercept custom findClassStart*/
jfieldID iID = jenv->GetStaticFieldID ( preMC , "INSTANCE" , "Lnet/minecraftforge/fml/relauncher/FMLLaunchHandler;" );
cout << "IID: " << iID << endl;
jobject instance = jenv->GetStaticObjectField ( preMC , iID );
cout << "INSTANCE: " << instance << endl;
jfieldID lID = jenv->GetFieldID ( preMC , "classLoader" , "Lnet/minecraft/launchwrapper/LaunchClassLoader;" );
cout << "LID: " << lID << endl;
jobject classLoader = jenv->GetObjectField ( instance , lID );
cout << "classLoader: " << classLoader << endl;
jmethodID fid = jenv->GetMethodID ( jenv->GetObjectClass(classLoader) , "findClass" , "(Ljava/lang/String;)Ljava/lang/Class;" );
cout << "FID: " << fid << endl;
jobject a = jenv->CallNonvirtualObjectMethod ( classLoader , jenv->GetObjectClass(classLoader), fid , "net/minecraft/client/Minecraft" );
preMC = ( jclass ) a;
cout << "preMC: " << preMC << endl;
/*Section intercept custom findClassEND*/
/*Section getDisplayWidthStart*/
jfieldID mid = jenv->GetStaticFieldID ( jenv->GetObjectClass(preMC) , "theMinecraft" , "Lnet/minecraft/client/Minecraft;" );
cout << "MID: " << mid << endl;
jobject MC = jenv->GetStaticObjectField ( jenv->GetObjectClass(preMC) , mid );
cout << "MC: " << MC << endl;
jfieldID mid2 = jenv->GetFieldID ( jenv->GetObjectClass(MC) , "displayWidth" , "I" );
cout << "MID2: " << mid2 << endl;
int displayWidth = jenv->GetIntField ( MC , mid2 );
cout << "DisplayWidth: " << displayWidth << endl;
/*Section getDisplayWidthEND*/
}
}
void init ( )
{
jvmHandle = GetModuleHandleA ( "jvm.dll" );
func_JNI_GetCreatedJavaVMs = GetProcAddress ( jvmHandle , "JNI_GetCreatedJavaVMs" );
oJNI_GetCreatedJavaVMs = ( hJNI_GetCreatedJavaVMs ) func_JNI_GetCreatedJavaVMs;
jint returnOF = oJNI_GetCreatedJavaVMs ( &jvm , 1 , NULL );
jint returnOf1 = jvm->AttachCurrentThread ( ( void ** ) &jenv , NULL );
if ( jenv != nullptr )
{
start ( );
}
if ( jenv->ExceptionCheck ( ) )
{
jenv->ExceptionDescribe ( );
}
jvm->DetachCurrentThread ( );
}
BOOL WINAPI DllMain ( HINSTANCE hinstDLL , DWORD fdwReason , LPVOID lpvReserved )
{
switch ( fdwReason )
{
case DLL_PROCESS_ATTACH:
init ( );
//case DLL_PROCESS_DETACH:
//case DLL_THREAD_ATTACH:
//case DLL_THREAD_DETACH:
}
}
NOTE: this game uses a custom class launcher, + i use the forge api on it.
I looked at the cout debugs and looks like the cout's stop at :
cout << "FID: " << fid << endl;
After that no more cout's get called. then the game stops responding.
Thank you for reading and hopefully i was descriptive enough.
EDIT: The whole code stops the game minecraft from responding after some time or instantly idk its random.
I use standard injection with extreme injector for now.
This is some information i got from debugging:
IID: 0000000024D1FE80
INSTANCE: 00000000191813F8
LID: 0000000000000032
classLoader: 0000000019181400
FID: 0000000016176C90
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000002d7688e, pid=6048, tid=0x0000000000001648
#
# JRE version: Java(TM) SE Runtime Environment (8.0_92-b14) (build 1.8.0_92-b14)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.92-b14 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# J 3576 C2 net.minecraft.launchwrapper.LaunchClassLoader.findClass(Ljava/lang/String;)Ljava/lang/Class; (695 bytes) # 0x0000000002d7688e [0x0000000002d76820+0x6e]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\Users\Balen\Desktop\ForgeMod\eclipse\hs_err_pid6048.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
AL lib: (EE) alc_cleanup: 1 device not closed
:runClient FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':runClient'.
> Process 'command 'C:\Program Files\Java\jdk1.8.0_92\bin\java.exe'' finished with non-zero exit value 1
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 8 mins 50.128 secs
Edit: This is to better explain everything:
I inject this dll into the game after everything in the game has initialized.
The games uses a custom class loader(LaunchClassLoader) i try to retrieve a instance of that, to do so i get the FMLLaunchHandler there i get a instanceof FMLLaunchHandler then from that instance i get classLoader and from that instance i use the classLoaders findClass to get the class.
Someone told me that i need to get a initialized version of a class to use non static methods or get non static fields.
I use a injector called extreme injector for now and use standard injection which is loadlibrary.
I also do not create my own vm, i attach to the running minecraft vm and get the env from that thru a dll and init function handles the attaching.
Thanks for reading, have nice day.

JPA criteriabuilder where statement

I would like to achieve the following where statement in my CriteriaQuery.
(Event.time >= NOW()
OR (Event.time >= '$clubHours' && (`EventSelectType`.`type`='cafe' || `EventSelectType`.`type`='DJ'))
OR (Event.endtime >= NOW() && (`EventSelectType`.`type`='festival' OR `EventSelectType`.`type`='dj' OR `EventSelectType`.`type`='cafe')))
I tried the following ;
eQr.where(
cB.or(
cB.or(
cB.greaterThanOrEqualTo(eventRoot.<Date>get("time"), curDate)
),
cB.or(
cB.and(
cB.greaterThanOrEqualTo(eventRoot.<Date>get("time"), cal.getTime())
),
cB.or(
cB.equal(eventType.<String>get("type"), "cafe"),
cB.equal(eventType.<String>get("type"), "DJ")
)
),
cB.or(
cB.and(
cB.greaterThanOrEqualTo(eventRoot.<Date>get("endtime"), curDate)
),
cB.or(
cB.equal(eventType.<String>get("type"), "festival"),
cB.equal(eventType.<String>get("type"), "DJ"),
cB.equal(eventType.<String>get("type"), "cafe")
)
)
),
cB.equal(eventRoot.<Integer>get("id"), eventID),
cB.equal(eventRoot.<Integer>get("active"), 1)
);
But all this generates is one big OR statement
(event0_.time>=? or event0_.time>=? or eventselec13_.type=? or eventselec13_.type=? or event0_.endtime>=? or eventselec13_.type=? or eventselec13_.type=? or eventselec13_.type=?)
How could I get the result I'm looking for?
EDIT
I currently have this
Predicate eventTypeIscafeORDJ = cB.or(
cB.equal(eventType.<String>get("type"), "cafe"),
cB.equal(eventType.<String>get("type"), "DJ")
);
Predicate eventTypeIsFestivalDJORCafe = cB.or(
cB.equal(eventType.<String>get("type"), "cafe"),
cB.equal(eventType.<String>get("type"), "DJ"),
cB.equal(eventType.<String>get("type"), "festival")
);
Predicate timeGreaterOrEqualTo = cB.greaterThanOrEqualTo(eventRoot.<Date>get("time"), cal.getTime());
Predicate endTimeGreaterOrEqualTo = cB.greaterThanOrEqualTo(eventRoot.<Date>get("endtime"), curDate);
Predicate equalToId = cB.equal(eventRoot.<Integer>get("id"), eventID);
eQr.where(timeGreaterOrEqualTo, cB.or( cB.and( timeGreaterOrEqualTo, eventTypeIscafeORDJ ), cB.and(endTimeGreaterOrEqualTo, eventTypeIsFestivalDJORCafe )), equalToId);
Which outputs
where event0_.time>=? and (event0_.time>=? and (eventselec13_.type=? or eventselec13_.type=?) or event0_.endtime>=? and (eventselec13_.type=? or eventselec13_.type=? or eventselec13_.type=?)) and event0_.id=633188
But it has to be
where (event0_.time>=? OR (event0_.time>=? and (eventselec13_.type=? or eventselec13_.type=?)) or (event0_.endtime>=? and (eventselec13_.type=? or eventselec13_.type=? or eventselec13_.type=?))) and event0_.id=633188
It still isn't exactly what I want and I cant seem to get it work the way I want it to.
Start with your obvious, first problem:
Event.time >= '$clubHours' && (`EventSelectType`.`type`='cafe' || `EventSelectType`.`type`='DJ'))
This should be constructed as
cB.and(
cB.greaterThanOrEqualTo(eventRoot.<Date>get("time"), cal.getTime()),
cB.or(
cB.equal(eventType.<String>get("type"), "cafe"),
cB.equal(eventType.<String>get("type"), "DJ")
)
), ...
Instead you have:
cB.and(
cB.greaterThanOrEqualTo(eventRoot.<Date>get("time"), cal.getTime())
),
cB.or(
cB.equal(eventType.<String>get("type"), "cafe"),
cB.equal(eventType.<String>get("type"), "DJ")
)
So, basically, you need to be sure to look at your parentheses and not your indenting in order to understand what your code is doing. As a side note, you would be better off constructing this predicate in steps so your code is easier to read and understand. E.g.:
Predicate eventTypeIscafeORDJ = cB.or(
cB.equal(eventType.<String>get("type"), "cafe"),
cB.equal(eventType.<String>get("type"), "DJ")
);
Predicate timeGreaterOrEqualTo = cB.greaterThanOrEqualTo(eventRoot.<Date>get("time"), cal.getTime());
eQr.where( cB.and( timeGreaterOrEqualTo, eventTypeIscafeORDJ ) );
The database is almost always the slower part of the code and the optimizer will probably make the same runtime out or either set of code, so you should make it easier on yourself and others. Further, this is the time tested way of debugging a coding problem, especially when you see all those parens.

How to add a MANIFEST file usig cmake and module UseJava?

Goal is simple. adding a MANNIFEST file into final jar archive.
For this I read many documentation but i miss the right information. Finally I come to you to get some help, thanks in advance.
What I do ?
cmake_minimum_required(VERSION 2.8)
find_package(Java REQUIRED)
include(UseJava)
enable_testing()
project(DAI)
set( cwd "${CMAKE_CURRENT_SOURCE_DIR}" )
set( AIName "SkirmishDAI" )
set( SRC_DIR "${cwd}/src" )
set( LIB_DIR "${cwd}/libs" )
set( MAJOR_VERSION 0 )
set( MINOR_VERSION 1 )
set( PATCH_VERSION 0 )
set( VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}" )
set( CMAKE_JAVA_INCLUDE_PATH "${LIB_DIR}" )
set( CMAKE_JAVA_COMPILE_FLAGS "-source" "1.7" "-target" "1.7" )
set( DAI_JAR_NAME "${AIName}-${VERSION}.jar" )
set( DAI_JAR_FILE "${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${DAI_JAR_NAME}" )
set( DAI_MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/META-INF/MANIFEST.MF" )
configure_file("manifest.extras.in" "${DAI_MANIFEST}" #ONLY )
FILE( GLOB_RECURSE JAVA_SRC_FILES "${SRC_DIR}/main/java/*.java" )
FILE( GLOB_RECURSE JAVA_TEST_FILES "${SRC_DIR}/test/java/*.java" )
add_jar( ${AIName} ${JAVA_SRC_FILES} ${JAVA_TEST_FILES} VERSION ${VERSION} MANIFEST ${DAI_MANIFEST} )
This will add into the jar file a manifest … but a wrong place.
That mean, when manifest go to ${CMAKE_CURRENT_BINARY_DIR}/META-INF/MANIFEST.MF, I will get the same full path in the jar file intead of META-INF/MANIFEST.MF
jarfile
/
/com/cool/app/Main.class
/mypath/to/bin/dir/META-INF/MANIFEST.MF
while I expect to get
jarfile
/
/com/cool/app/Main.class
/META-INF/MANIFEST.MF
UPDATE: Make run following command:
$ make VERBOSE=1
…
[ 31%] Creating Java archive SkirmishDAI-0.1.0.jar
cd /mnt/data/projects/spring/build/AI/Skirmish/DAI/CMakeFiles/SkirmishDAI.dir && /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.65-2.5.2.5.fc20.x86_64/bin/jar -cf /mnt/data/projects/spring/build/AI/Skirmish/DAI/SkirmishDAI-0.1.0.jar /mnt/data/projects/spring/build/AI/Skirmish/DAI/META-INF/MANIFEST.MF #java_class_filelist
cd /mnt/data/projects/spring/build/AI/Skirmish/DAI/CMakeFiles/SkirmishDAI.dir && /usr/bin/cmake -D_JAVA_TARGET_DIR=/mnt/data/projects/spring/build/AI/Skirmish/DAI -D_JAVA_TARGET_OUTPUT_NAME=SkirmishDAI-0.1.0.jar -D_JAVA_TARGET_OUTPUT_LINK=SkirmishDAI.jar -P /usr/share/cmake/Modules/UseJavaSymlinks.cmake.
…
The problem likely stems from a duplicated path in the following lines:
set( DAI_MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/META-INF/MANIFEST.MF" )
configure_file("manifest.extras.in" "${CMAKE_CURRENT_BINARY_DIR}/${DAI_MANIFEST}" #ONLY )
You probably meant:
set( DAI_MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/META-INF/MANIFEST.MF" )
configure_file("manifest.extras.in" "${DAI_MANIFEST}" #ONLY )

Categories

Resources