Skip to content

Commit

Permalink
Implement persistence layer using Elide
Browse files Browse the repository at this point in the history
  • Loading branch information
QubitPi committed Aug 15, 2023
1 parent 65d61d2 commit 9cfc501
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 515 deletions.
6 changes: 5 additions & 1 deletion docs/docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ configs. In short, the Standalone Jetty container will be setup with
export JETTY_HOME=/path/to/jetty-home-11.0.15
mkdir -p /path/to/jetty-base
cd /path/to/jetty-base
java -jar $JETTY_HOME/start.jar --add-module=annotations,server,http,deploy
java -jar $JETTY_HOME/start.jar --add-module=annotations,server,http,deploy,servlet,webapp,resources,jsp,websocket
```

where `/path/to/` is the _absolute_ path to the directory containing the `jetty-home-11.0.15` directory
Expand All @@ -142,6 +142,10 @@ Lastly, drop the [WAR file](#packaging) into **/path/to/jetty-base/webapps** dir
mv /path/to/war-file /path/to/jetty-base/webapps/ROOT.war
```

### Setting Environment Variables

- **MODEL_PACKAGE_NAME**: Model package in CLASSPATH

### Running Astraios

```bash
Expand Down
37 changes: 34 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,35 @@
<version>6.25.2</version>
</dependency>

<!-- Elide -->
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-core</artifactId>
<version>7.0.0-pr6</version>
<exclusions>
<exclusion>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-graphql</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-standalone</artifactId>
<version>7.0.0-pr6</version>
<exclusions>
<exclusion>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-graphql</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>

<!-- Testing -->
<dependency>
<groupId>org.spockframework</groupId>
Expand Down Expand Up @@ -233,18 +262,20 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@
@Config.Sources({"system:env", "system:properties"})
public interface ApplicationConfig extends Config {

@Key("EXAMPLE_CONFIG_KEY_NAME")
String exampleConfigKey();
@Key("MODEL_PACKAGE_NAME")
String modelPackageName();
}
138 changes: 136 additions & 2 deletions src/main/java/com/paiondata/astraios/application/BinderFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,42 @@
*/
package com.paiondata.astraios.application;

import static com.yahoo.elide.standalone.Util.combineModelEntities;

import com.yahoo.elide.Elide;
import com.yahoo.elide.ElideSettings;
import com.yahoo.elide.ElideSettingsBuilder;
import com.yahoo.elide.core.TransactionRegistry;
import com.yahoo.elide.core.datastore.DataStore;
import com.yahoo.elide.core.dictionary.EntityDictionary;
import com.yahoo.elide.core.dictionary.Injector;
import com.yahoo.elide.core.utils.ClassScanner;
import com.yahoo.elide.core.utils.DefaultClassScanner;
import com.yahoo.elide.core.utils.coerce.CoerceUtil;
import com.yahoo.elide.datastores.jpa.JpaDataStore;
import com.yahoo.elide.datastores.jpa.PersistenceUnitInfoImpl;
import com.yahoo.elide.datastores.jpa.transaction.NonJtaTransaction;

import org.aeonbits.owner.ConfigFactory;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.Binder;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.hibernate.Session;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.spi.PersistenceUnitInfo;
import jakarta.validation.constraints.NotNull;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.function.Consumer;

/**
* A binder factory builds a custom binder for the Jersey application.
* <p>
Expand All @@ -37,15 +66,120 @@ public class BinderFactory {
* <p>
* This binder should bind all relevant resources for runtime dependency injection.
*
* @param injector A standard HK2 service locator
*
* @return a binder instance that will be registered by putting as a parameter to
* {@link org.glassfish.jersey.server.ResourceConfig#register(Object)}
*/
@NotNull
public Binder buildBinder() {
public Binder buildBinder(final ServiceLocator injector) {
return new AbstractBinder() {

private static final Consumer<EntityManager> TXCANCEL = em -> em.unwrap(Session.class).cancelQuery();

private static final ApplicationConfig CONFIG = ConfigFactory.create(ApplicationConfig.class);

private final ClassScanner classScanner = new DefaultClassScanner();

@Override
protected void configure() {
// intentionally left blank
final ElideSettings elideSettings = buildElideSettings();

bind(buildElide(elideSettings)).to(Elide.class).named("elide");
bind(elideSettings).to(ElideSettings.class);
bind(elideSettings.getDictionary()).to(EntityDictionary.class);
bind(elideSettings.getDataStore()).to(DataStore.class).named("elideDataStore");
}

private Elide buildElide(final ElideSettings elideSettings) {
return new Elide(
elideSettings,
new TransactionRegistry(),
elideSettings.getDictionary().getScanner(),
false
);
}

private ElideSettings buildElideSettings() {
return new ElideSettingsBuilder(buildDataStore(buildEntityManagerFactory()))
.withEntityDictionary(buildEntityDictionary(injector))
.build();
}

private DataStore buildDataStore(final EntityManagerFactory entityManagerFactory) {
return new JpaDataStore(
entityManagerFactory::createEntityManager,
em -> new NonJtaTransaction(em, TXCANCEL),
entityManagerFactory::getMetamodel);
}

private EntityManagerFactory buildEntityManagerFactory() {
final String modelPackageName = CONFIG.modelPackageName();
final ClassLoader classLoader = null;

final PersistenceUnitInfo persistenceUnitInfo = new PersistenceUnitInfoImpl(
"astraios",
combineModelEntities(classScanner, modelPackageName, false),
getDefaultDbConfigs(),
classLoader
);

return new EntityManagerFactoryBuilderImpl(
new PersistenceUnitInfoDescriptor(persistenceUnitInfo),
new HashMap<>(),
classLoader
).build();
}

@SuppressWarnings("MultipleStringLiterals")
private static Properties getDefaultDbConfigs() {
final Properties dbProperties = new Properties();

dbProperties.put("hibernate.show_sql", "true");
dbProperties.put("hibernate.hbm2ddl.auto", "create");
dbProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
dbProperties.put("hibernate.current_session_context_class", "thread");
dbProperties.put("hibernate.jdbc.use_scrollable_resultset", "true");

// Collection Proxy & JDBC Batching
dbProperties.put("hibernate.jdbc.batch_size", "50");
dbProperties.put("hibernate.jdbc.fetch_size", "50");
dbProperties.put("hibernate.default_batch_fetch_size", "100");

// Hikari Connection Pool Settings
dbProperties.putIfAbsent("hibernate.connection.provider_class",
"com.zaxxer.hikari.hibernate.HikariConnectionProvider");
dbProperties.putIfAbsent("hibernate.hikari.connectionTimeout", "20000");
dbProperties.putIfAbsent("hibernate.hikari.maximumPoolSize", "30");
dbProperties.putIfAbsent("hibernate.hikari.idleTimeout", "30000");

dbProperties.put("jakarta.persistence.jdbc.driver", "com.mysql.jdbc.Driver");
dbProperties.put("jakarta.persistence.jdbc.url", "jdbc:mysql://localhost/elide?serverTimezone=UTC");
dbProperties.put("jakarta.persistence.jdbc.user", "root");
dbProperties.put("jakarta.persistence.jdbc.password", "root");

return dbProperties;
}

private EntityDictionary buildEntityDictionary(final ServiceLocator injector) {
return new EntityDictionary(
new HashMap<>(),
new HashMap<>(),
new Injector() {
@Override
public void inject(final Object entity) {
injector.inject(entity);
}

@Override
public <T> T instantiate(final Class<T> cls) {
return injector.create(cls);
}
},
CoerceUtil::lookup,
new HashSet<>(),
classScanner
);
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
*/
package com.paiondata.astraios.application;

import com.paiondata.astraios.web.filters.CorsFilter;
import com.yahoo.elide.Elide;

import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.Binder;
import org.glassfish.jersey.media.multipart.MultiPartFeature;

import jakarta.inject.Inject;
import jakarta.servlet.ServletContext;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Context;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;

Expand All @@ -30,21 +32,31 @@
*/
@Immutable
@ThreadSafe
@ApplicationPath("v1")
@ApplicationPath("/v1/data/")
public class ResourceConfig extends org.glassfish.jersey.server.ResourceConfig {

private static final String ENDPOINT_PACKAGE = "com.paiondata.astraios.web.endpoints";
private static final String ENDPOINT_PACKAGE = "com.yahoo.elide.jsonapi.resources";

/**
* DI Constructor.
*
* @param injector A standard HK2 service locator
* @param servletContext Currently unused
*/
@Inject
public ResourceConfig() {
final Binder binder = new BinderFactory().buildBinder();
public ResourceConfig(final ServiceLocator injector, @Context final ServletContext servletContext) {
final Binder binder = new BinderFactory().buildBinder(injector);

packages(ENDPOINT_PACKAGE);
register(new CorsFilter());
register(binder);
register(MultiPartFeature.class);

register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
@Override
protected void configure() {
final Elide elide = injector.getService(Elide.class, "elide");
elide.doScans();
}
});

packages(ENDPOINT_PACKAGE);
}
}

This file was deleted.

Loading

0 comments on commit 9cfc501

Please sign in to comment.