diff --git a/.gitignore b/.gitignore index 64b1d59..ea4cbb7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ *~ #*# gradle +gradlew +._git_gburd .gradle run-jetty-run/ license.err diff --git a/build.gradle b/build.gradle index 9a74300..0b995d6 100644 --- a/build.gradle +++ b/build.gradle @@ -195,21 +195,15 @@ dependencyManagement { // user = 'root' // } -task performJPAWeaving(type: JavaExec, dependsOn: "compileJava"){ +task weaveJpaEntities(type: JavaExec, dependsOn: "compileJava"){ inputs.dir compileJava.destinationDir outputs.dir compileJava.destinationDir main "org.eclipse.persistence.tools.weaving.jpa.StaticWeave" - args "-persistenceinfo", - "src/main/resources", - compileJava.destinationDir.getAbsolutePath(), - compileJava.destinationDir.getAbsolutePath() + args "-loglevel", "FINE", + "-persistenceinfo", "src/main/resources", + compileJava.destinationDir.getAbsolutePath(), + compileJava.destinationDir.getAbsolutePath() classpath = configurations.compile } -tasks.withType(JavaCompile){ - doLast{ - tasks.performJPAWeaving.execute() - } -} -// http://stackoverflow.com/questions/6431026/generating-jpa2-metamodel-from-a-gradle-build-script -// http://bsideup.blogspot.com/2015/04/querydsl-with-gradle-and-idea.html +classes.dependsOn weaveJpaEntities diff --git a/ops/haproxy.conf b/ops/haproxy.conf new file mode 100644 index 0000000..1281fee --- /dev/null +++ b/ops/haproxy.conf @@ -0,0 +1,111 @@ +global + log 127.0.0.1 local0 + log 127.0.0.1 local1 notice + maxconn 256000 + spread-checks 5 + daemon + quiet +# chroot /var/lib/haproxy +# user haproxy +# group haproxy + +defaults + log global + option dontlognull + option allbackups + maxconn 256000 + timeout connect 5000 + timeout check 5000 + timeout client 30000 + timeout server 30000 + +# Load balancer stats page access at hostname:8080/haproxy_stats +listen stats + bind *:9876 + mode http + stats enable + stats realm Haproxy\ Statistics\ CrDB + stats uri /stats + stats hide-version +# stats auth admin:admin@crdb + +backend crdb_pg_n_cr_backend + balance leastconn + mode tcp + option tcpka + option tcplog + option srvtcpka + option log-health-checks + option redispatch + option pgsql-check user haproxy + balance roundrobin + timeout connect 3s + timeout server 20s + server usw2c-756 storage-base-usw2c-756.ops:26257 check + server usw2b-755 storage-base-usw2b-755.ops:26257 check + server use1b-754 storage-base-use1b-754.ops:26257 check + server euw1c-753 storage-base-euw1c-753.ops:26257 check + server euw1b-752 storage-base-euw1b-752.ops:26257 check +# server aps2b-751 storage-base-aps2b-751.ops:26257 check + server aps1b-750 storage-base-aps1b-750.ops:26257 check + server aps1a-749 storage-base-aps1a-749.ops:26257 check + server apn1c-748 storage-base-apn1c-748.ops:26257 check + server apn1a-747 storage-base-apn1a-747.ops:26257 check + server apn1a-746 storage-base-apn1a-746.ops:26257 check + server aps1a-745 storage-base-aps1a-745.ops:26257 check +# server aps2a-744 storage-base-aps2a-744.ops:26257 check + server euw1a-743 storage-base-euw1a-743.ops:26257 check +# server usw2a-742 storage-base-usw2a-742.ops:26257 check + server use1a-740 storage-base-use1a-740.ops:26257 check + +frontend crdb_cr_frontend + bind *:26257 + mode tcp + option tcplog + option contstats + option tcpka + default_backend crdb_pg_n_cr_backend + +frontend crdb_pg_frontend + bind *:5432 + mode tcp + option tcplog + option contstats + option tcpka + default_backend crdb_pg_n_cr_backend + +backend crdb_admin_gui_backend + balance leastconn + mode tcp + option tcpka + option tcplog + option srvtcpka + option log-health-checks + option redispatch + balance roundrobin + timeout connect 3s + timeout server 20s + server usw2c-756 storage-base-usw2c-756.ops:8080 check + server usw2b-755 storage-base-usw2b-755.ops:8080 check + server use1b-754 storage-base-use1b-754.ops:8080 check + server euw1c-753 storage-base-euw1c-753.ops:8080 check + server euw1b-752 storage-base-euw1b-752.ops:8080 check +# server aps2b-751 storage-base-aps2b-751.ops:8080 check + server aps1b-750 storage-base-aps1b-750.ops:8080 check + server aps1a-749 storage-base-aps1a-749.ops:8080 check + server apn1c-748 storage-base-apn1c-748.ops:8080 check + server apn1a-747 storage-base-apn1a-747.ops:8080 check + server apn1a-746 storage-base-apn1a-746.ops:8080 check + server aps1a-745 storage-base-aps1a-745.ops:8080 check +# server aps2a-744 storage-base-aps2a-744.ops:8080 check + server euw1a-743 storage-base-euw1a-743.ops:8080 check + server usw2a-742 storage-base-usw2a-742.ops:8080 check + server use1a-740 storage-base-use1a-740.ops:8080 check + +frontend crdb_admin_gui_frontend + bind *:7777 + mode tcp + option tcplog + option contstats + option tcpka + default_backend crdb_admin_gui_backend diff --git a/src/main/java/com/example/crud/Application.java b/src/main/java/com/example/crud/Application.java index 50d0c5f..c49822d 100644 --- a/src/main/java/com/example/crud/Application.java +++ b/src/main/java/com/example/crud/Application.java @@ -111,7 +111,7 @@ public class Application { @Bean public Map jpaProperties() { Map props = new HashMap<>(); - props.put("eclipselink.weaving", "static"); //TODO(gburd): enable + props.put("eclipselink.weaving", "static"); return props; } @@ -133,6 +133,7 @@ public class Application { return dataSource; } + /* @Bean public CacheManager cacheManager() { //TODO(gburd): is there an eclipselink cache manager? or caffeine? or...? @@ -143,5 +144,6 @@ public class Application { return manager; } + */ } diff --git a/src/main/java/com/example/crud/controllers/EmployeeController.java b/src/main/java/com/example/crud/controllers/EmployeeController.java index 94623bd..995883b 100644 --- a/src/main/java/com/example/crud/controllers/EmployeeController.java +++ b/src/main/java/com/example/crud/controllers/EmployeeController.java @@ -26,6 +26,13 @@ public class EmployeeController { @Autowired private EmployeeService employeeService; + /** + * Read all employees. + * + * Examples: + * 1. HTTP GET localhost:8443/api/v1/employees + * 2. curl -i -X GET localhost:8443/employees + */ @Transactional(readOnly = true, isolation = Isolation.REPEATABLE_READ) @RequestMapping(value = "/api/v1/employees", method = GET, produces = "application/json") public ResponseEntity> index() { @@ -44,6 +51,13 @@ public class EmployeeController { return response; } + /** + * Create a new employee. + * + * Examples: + * 1. HTTP POST localhost:8443/api/v1/employee firstName=Tedd lastName=Hanson honorific=Mr suffix=Jr. socialSecurityNumber=555-55-5555 + * 2. curl -i -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Karl", "lastName" : "Pasim", "socialSecurityNumber" : "123-23-2312" }' localhost:8443/api/v1/employee + */ @Retry(times = 3, on = org.springframework.dao.OptimisticLockingFailureException.class) @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.REPEATABLE_READ) @RequestMapping(value = "/api/v1/employee", method = POST, consumes = "application/json") @@ -53,7 +67,7 @@ public class EmployeeController { try { val e = employeeService.saveEmployee(employee); if (e != null) { - response = ResponseEntity.status(HttpStatus.CREATED).body(e.getId()); + response = ResponseEntity.status(HttpStatus.CREATED).body(e); } else { response = ResponseEntity.status(HttpStatus.NOT_MODIFIED).build(); } @@ -63,23 +77,15 @@ public class EmployeeController { return response; } - @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) - @RequestMapping(value = "/api/v1/employee/{id:[\\d]+}", method = DELETE) - public ResponseEntity deleteEmployee(@PathVariable Long id) { - log.debug("Deleting employee"); - @SuppressWarnings("unchecked") ResponseEntity response = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); - try { - employeeService.delete(id); - response = ResponseEntity.status(HttpStatus.OK).body(id); - } catch (Exception e) { - response = ResponseEntity.status(HttpStatus.NOT_FOUND).build(); - } - return response; - } - + /** + * Read an employee by primary key (id). + * + * Examples: + * 1. HTTP GET localhost:8443/api/v1/employee/851864136237137920 + * 2. curl -i -X GET localhost:8443/employee/851864136237137920 + */ @Transactional(readOnly = true, isolation = Isolation.REPEATABLE_READ) - //@RequestMapping(value = "/api/v1/employee/{id:[\\d]+}", method = GET) - @RequestMapping(value = "/api/v1/employee/{id}", method = GET) + @RequestMapping(value = "/api/v1/employee/{id:[\\d]+}", method = GET) public ResponseEntity find(@PathVariable Long id) { log.debug("Getting a specific employee by id {}", id); @SuppressWarnings("unchecked") ResponseEntity response = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); @@ -96,6 +102,13 @@ public class EmployeeController { return response; } + /** + * Read the set of employees with a given last name. + * + * Examples: + * 1. HTTP GET localhost:8443/api/v1/employee?last=washington + * 2. curl -i -X GET localhost:8443/employee?last=washington + */ @Transactional(readOnly = true, isolation = Isolation.REPEATABLE_READ) @RequestMapping(value = "/api/v1/employee/named", method = GET) public ResponseEntity> find(@RequestParam("last") String name) { @@ -114,19 +127,25 @@ public class EmployeeController { return response; } - @Transactional(readOnly = true, isolation = Isolation.REPEATABLE_READ) + /** + * Delete a new employee. + * + * Examples: + * 1. HTTP DELETE localhost:8443/api/v1/employee/851864136237137920 + * 2. curl -i -X DELETE localhost:8443/api/v1/employee/851864136237137920 + */ + @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE) @RequestMapping(value = "/api/v1/employee/{id:[\\d]+}", method = DELETE) - public @ResponseBody Long delete(@PathVariable Long id) { + public ResponseEntity deleteEmployee(@PathVariable Long id) { log.debug("Remove an employee by id {}", id); - employeeService.delete(id); - return id; + @SuppressWarnings("unchecked") ResponseEntity response = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + try { + employeeService.delete(id); + response = ResponseEntity.status(HttpStatus.OK).body(id); + } catch (Exception e) { + response = ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } + return response; } - /* - @Transactional(readOnly = true, isolation = Isolation.REPEATABLE_READ) - @RequestMapping("/api/v1/employee/lastNameLength") - public List fetchByLength(Long length) { - return employeeService.fetchByLastNameLength(length); - } - */ } diff --git a/src/main/java/com/example/crud/db/monitoring/EclipseLinkCache.java b/src/main/java/com/example/crud/db/monitoring/EclipseLinkCache.java deleted file mode 100644 index 8afecb0..0000000 --- a/src/main/java/com/example/crud/db/monitoring/EclipseLinkCache.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.example.crud.db.monitoring; - -import org.eclipse.persistence.internal.sessions.IdentityMapAccessor; -import org.eclipse.persistence.jpa.JpaEntityManager; -import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl; -import org.eclipse.persistence.sessions.Session; -import org.eclipse.persistence.sessions.server.ServerSession; - -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import javax.persistence.Persistence; - -public class EclipseLinkCache { - EntityManagerFactory emf = Persistence.createEntityManagerFactory("default"); - EntityManager em = emf.createEntityManager(); - Session session = em.unwrap(Session.class); - JpaEntityManager jem = em.unwrap(JpaEntityManager.class); - UnitOfWorkImpl ouw = jem.unwrap(UnitOfWorkImpl.class); - ServerSession ss = jem.unwrap(ServerSession.class); - IdentityMapAccessor ima = (IdentityMapAccessor) ss.getIdentityMapAccessor(); - - - /** - * long count = countCachedEntitiesL1(clazz); - */ - public long countCachedEntitiesL1(Class clazz) { - return ouw.getCloneMapping().keySet().stream() - .filter(entity -> entity.getClass().equals(clazz)) - .count(); - } - - /** - * int count = countCachedEntitiesL2(clazz); - */ - public int countCachedEntitiesL2(Class clazz) { - return ima.getIdentityMap(clazz).getSize(); - } - -} diff --git a/src/main/java/com/example/crud/db/monitoring/EclipseLinkGaugeSet.java b/src/main/java/com/example/crud/db/monitoring/EclipseLinkGaugeSet.java deleted file mode 100644 index e6ab1ad..0000000 --- a/src/main/java/com/example/crud/db/monitoring/EclipseLinkGaugeSet.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.example.crud.db.monitoring; - -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricSet; - -import java.lang.management.ManagementFactory; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -/** - * A set of gauges for operating system settings. - */ -public class EclipseLinkGaugeSet implements MetricSet { - - private final Optional level1CacheObjectCount; - private final Optional level1CacheMemorySize; - private final Optional level1CacheHitMissRatio; - private final Optional level2CacheObjectCount; - private final Optional level2CacheHitMissRatio; - - /** - * Creates new gauges using the platform OS bean. - */ - public EclipseLinkGaugeSet() { - this(ManagementFactory.getEclipseLinkMXBean()); - } - - /** - * Creates a new gauges using the given OS bean. - * - * @param mxBean an {@link EclipseLinkMXBean} - */ - public EclipseLinkGaugeSet(EclipseLinkMXBean mxBean) { - this.mxBean = mxBean; - - committedVirtualMemorySize = getMethod("getCommittedVirtualMemorySize"); - totalSwapSpaceSize = getMethod("getTotalSwapSpaceSize"); - freeSwapSpaceSize = getMethod("getFreeSwapSpaceSize"); - processCpuTime = getMethod("getProcessCpuTime"); - freePhysicalMemorySize = getMethod("getFreePhysicalMemorySize"); - totalPhysicalMemorySize = getMethod("getTotalPhysicalMemorySize"); - openFileDescriptorCount = getMethod("getOpenFileDescriptorCount"); - maxFileDescriptorCount = getMethod("getMaxFileDescriptorCount"); - systemCpuLoad = getMethod("getSystemCpuLoad"); - processCpuLoad = getMethod("getProcessCpuLoad"); - } - - - @Override - public Map getMetrics() { - final Map gauges = new HashMap<>(); - - gauges.put("committedVirtualMemorySize", (Gauge) () -> invokeLong(committedVirtualMemorySize)); - gauges.put("totalSwapSpaceSize", (Gauge) () -> invokeLong(totalSwapSpaceSize)); - gauges.put("freeSwapSpaceSize", (Gauge) () -> invokeLong(freeSwapSpaceSize)); - gauges.put("processCpuTime", (Gauge) () -> invokeLong(processCpuTime)); - gauges.put("freePhysicalMemorySize", (Gauge) () -> invokeLong(freePhysicalMemorySize)); - gauges.put("totalPhysicalMemorySize", (Gauge) () -> invokeLong(totalPhysicalMemorySize)); - gauges.put("fd.usage", (Gauge) () -> invokeRatio(openFileDescriptorCount, maxFileDescriptorCount)); - gauges.put("systemCpuLoad", (Gauge) () -> invokeDouble(systemCpuLoad)); - gauges.put("processCpuLoad", (Gauge) () -> invokeDouble(processCpuLoad)); - - return gauges; - } - - private Optional getMethod(String name) { - try { - final Method method = mxBean.getClass().getDeclaredMethod(name); - method.setAccessible(true); - return Optional.of(method); - } catch (NoSuchMethodException e) { - return Optional.empty(); - } - } - - private long invokeLong(Optional method) { - if (method.isPresent()) { - try { - return (long) method.get().invoke(mxBean); - } catch (IllegalAccessException | InvocationTargetException ite) { - return 0L; - } - } - return 0L; - } - - private double invokeDouble(Optional method) { - if (method.isPresent()) { - try { - return (double) method.get().invoke(mxBean); - } catch (IllegalAccessException | InvocationTargetException ite) { - return 0.0; - } - } - return 0.0; - } - - private double invokeRatio(Optional numeratorMethod, Optional denominatorMethod) { - if (numeratorMethod.isPresent() && denominatorMethod.isPresent()) { - try { - long numerator = (long) numeratorMethod.get().invoke(mxBean); - long denominator = (long) denominatorMethod.get().invoke(mxBean); - if (0 == denominator) { - return Double.NaN; - } - return 1.0 * numerator / denominator; - } catch (IllegalAccessException | InvocationTargetException ite) { - return Double.NaN; - } - } - return Double.NaN; - } - -}