This repository has been archived by the owner on Jun 29, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit aac3875
Showing
73 changed files
with
15,010 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
logs | ||
project/project | ||
project/target | ||
target | ||
tmp | ||
.history | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
This is your new Play 2.0 application | ||
===================================== | ||
|
||
This file will be packaged with your application, when using `play dist`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import actors.ProcessCodePointOpenCsv; | ||
import akka.actor.ActorRef; | ||
import akka.actor.Props; | ||
import akka.actor.UntypedActorFactory; | ||
import com.google.code.morphia.logging.MorphiaLoggerFactory; | ||
import com.google.code.morphia.logging.slf4j.SLF4JLogrImplFactory; | ||
import com.google.common.base.Throwables; | ||
import com.google.common.collect.Lists; | ||
import com.google.inject.*; | ||
import com.yammer.metrics.Metrics; | ||
import com.yammer.metrics.core.Counter; | ||
import com.yammer.metrics.reporting.ConsoleReporter; | ||
import models.PostcodeUnit; | ||
import models.csv.CodePointOpenCsvEntry; | ||
import org.apache.camel.CamelContext; | ||
import org.apache.camel.Exchange; | ||
import org.apache.camel.Processor; | ||
import org.apache.camel.builder.RouteBuilder; | ||
import org.apache.camel.model.dataformat.BindyType; | ||
import org.joda.time.LocalDateTime; | ||
import org.reflections.Reflections; | ||
import org.reflections.scanners.SubTypesScanner; | ||
import org.reflections.scanners.TypeAnnotationsScanner; | ||
import org.reflections.util.ClasspathHelper; | ||
import org.reflections.util.ConfigurationBuilder; | ||
import play.Application; | ||
import play.GlobalSettings; | ||
import play.Logger; | ||
import play.libs.Akka; | ||
import play.mvc.Controller; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* @author Mathias Bogaert | ||
*/ | ||
public class Global extends GlobalSettings { | ||
private final List<Module> modules = Lists.newArrayList(); | ||
|
||
private Injector injector; | ||
private CamelContext camelContext; | ||
|
||
static { | ||
MorphiaLoggerFactory.reset(); | ||
MorphiaLoggerFactory.registerLogger(SLF4JLogrImplFactory.class); | ||
} | ||
|
||
@Override | ||
public void beforeStart(final Application application) { | ||
final Reflections reflections = new Reflections(new ConfigurationBuilder() | ||
.addUrls(ClasspathHelper.forPackage("modules", application.classloader())) | ||
.addScanners( | ||
new SubTypesScanner(), | ||
new TypeAnnotationsScanner() | ||
)); | ||
|
||
Set<Class<? extends AbstractModule>> guiceModules = reflections.getSubTypesOf(AbstractModule.class); | ||
for (Class<? extends Module> moduleClass : guiceModules) { | ||
try { | ||
if (!moduleClass.isAnonymousClass()) { | ||
modules.add(moduleClass.newInstance()); | ||
} | ||
} catch (InstantiationException | IllegalAccessException e) { | ||
throw Throwables.propagate(e); | ||
} | ||
} | ||
|
||
modules.add(new AbstractModule() { | ||
@Override | ||
protected void configure() { | ||
bind(Application.class).toInstance(application); | ||
bind(Reflections.class).toInstance(reflections); | ||
|
||
for (Class<? extends Controller> controller : reflections.getSubTypesOf(Controller.class)) { | ||
requestStaticInjection(controller); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
@Override | ||
public void onStart(Application app) { | ||
Logger.info("Creating injector with " + modules.size() + " modules."); | ||
injector = Guice.createInjector(Stage.PRODUCTION, modules); | ||
|
||
ConsoleReporter.enable(1, TimeUnit.MINUTES); | ||
|
||
final ActorRef processActorRef = Akka.system().actorOf(new Props(new UntypedActorFactory() { | ||
public ProcessCodePointOpenCsv create() { | ||
return injector.getInstance(ProcessCodePointOpenCsv.class); | ||
} | ||
}), "process-codepoint-open-csv-entry"); | ||
|
||
camelContext = injector.getInstance(CamelContext.class); | ||
try { | ||
camelContext.addRoutes(new RouteBuilder() { | ||
@Override | ||
public void configure() throws Exception { | ||
|
||
from("file://codepointopen/") | ||
.unmarshal().bindy(BindyType.Csv, "models.csv") | ||
.split(body()) | ||
.process(new Processor() { | ||
@SuppressWarnings("unchecked") | ||
@Override | ||
public void process(Exchange exchange) throws Exception { | ||
Object body = exchange.getIn().getBody(); | ||
|
||
if (body instanceof Map) { | ||
Map<String, CodePointOpenCsvEntry> csvEntryMap = (Map<String, CodePointOpenCsvEntry>) body; | ||
|
||
for (CodePointOpenCsvEntry entry : csvEntryMap.values()) { | ||
processActorRef.tell(entry); | ||
} | ||
} else { | ||
throw new RuntimeException("something went wrong; message body is no map!"); | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
} catch (Exception e) { | ||
Logger.error(e.getMessage(), e); | ||
} | ||
|
||
try { | ||
camelContext.start(); | ||
} catch (Exception e) { | ||
Logger.error("Exception starting Apache Camel context: " + e.getMessage(), e); | ||
|
||
throw Throwables.propagate(e); | ||
} | ||
} | ||
|
||
@Override | ||
public void onStop(Application app) { | ||
if (camelContext != null) { | ||
try { | ||
camelContext.stop(); | ||
} catch (Exception e) { | ||
Logger.error("Exception stopping Apache Camel context: " + e.getMessage(), e); | ||
|
||
throw Throwables.propagate(e); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package actors; | ||
|
||
import akka.actor.UntypedActor; | ||
import akka.event.Logging; | ||
import akka.event.LoggingAdapter; | ||
import com.google.common.base.CharMatcher; | ||
import com.google.common.base.Throwables; | ||
import com.mongodb.MongoException; | ||
import com.yammer.metrics.Metrics; | ||
import com.yammer.metrics.core.Counter; | ||
import com.yammer.metrics.core.Timer; | ||
import com.yammer.metrics.core.TimerContext; | ||
import models.CartesianLocation; | ||
import models.Location; | ||
import models.PostcodeUnit; | ||
import models.csv.CodePointOpenCsvEntry; | ||
import org.geotools.geometry.GeneralDirectPosition; | ||
import org.geotools.measure.AngleFormat; | ||
import org.geotools.referencing.ReferencingFactoryFinder; | ||
import org.geotools.referencing.operation.DefaultCoordinateOperationFactory; | ||
import org.opengis.geometry.DirectPosition; | ||
import org.opengis.referencing.FactoryException; | ||
import org.opengis.referencing.crs.CRSAuthorityFactory; | ||
import org.opengis.referencing.crs.CoordinateReferenceSystem; | ||
import org.opengis.referencing.operation.CoordinateOperation; | ||
|
||
import java.text.DecimalFormat; | ||
import java.text.NumberFormat; | ||
import java.util.Locale; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* @author Mathias Bogaert | ||
*/ | ||
public class ProcessCodePointOpenCsv extends UntypedActor { | ||
private CoordinateOperation coordinateOperation; | ||
|
||
private final Counter postcodesProcessed = Metrics.newCounter(ProcessCodePointOpenCsv.class, "postcodes-processed"); | ||
private final Timer latLongTransform = Metrics.newTimer(ProcessCodePointOpenCsv.class, "latitude-longitude-transform", TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS); | ||
private final Timer savePostcodeUnit = Metrics.newTimer(ProcessCodePointOpenCsv.class, "save-postcode-unit-mongodb", TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS); | ||
|
||
@Override | ||
public void preStart() { | ||
CRSAuthorityFactory crsFac = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null); | ||
|
||
try { | ||
CoordinateReferenceSystem wgs84crs = crsFac.createCoordinateReferenceSystem("4326"); | ||
CoordinateReferenceSystem osgbCrs = crsFac.createCoordinateReferenceSystem("27700"); | ||
|
||
coordinateOperation = new DefaultCoordinateOperationFactory().createOperation(osgbCrs, wgs84crs); | ||
} catch (FactoryException e) { | ||
throw Throwables.propagate(e); | ||
} | ||
} | ||
|
||
@Override | ||
public void onReceive(Object message) throws Exception { | ||
if (message instanceof CodePointOpenCsvEntry) { | ||
CodePointOpenCsvEntry entry = (CodePointOpenCsvEntry) message; | ||
|
||
PostcodeUnit unit = new PostcodeUnit(CharMatcher.WHITESPACE.removeFrom(entry.getPostcode())); | ||
unit.pqi = entry.getPositionalQualityIndicator(); | ||
unit.cartesianLocation = new CartesianLocation(Integer.parseInt(entry.getEastings()), Integer.parseInt(entry.getNorthings())); | ||
|
||
final TimerContext latLongCtx = latLongTransform.time(); | ||
try { | ||
DirectPosition eastNorth = new GeneralDirectPosition(Integer.parseInt(entry.getEastings()), Integer.parseInt(entry.getNorthings())); | ||
DirectPosition latLng = coordinateOperation.getMathTransform().transform(eastNorth, eastNorth); | ||
|
||
unit.location = new Location(round(latLng.getOrdinate(0), 7), round(latLng.getOrdinate(1), 7)); | ||
} finally { | ||
latLongCtx.stop(); | ||
} | ||
|
||
final TimerContext saveCtx = savePostcodeUnit.time(); | ||
try { | ||
unit.save(); | ||
|
||
postcodesProcessed.inc(); | ||
} catch (MongoException.DuplicateKey e) { | ||
// ignore | ||
} finally { | ||
saveCtx.stop(); | ||
} | ||
} | ||
} | ||
|
||
public static double round(double valueToRound, int numberOfDecimalPlaces) { | ||
double multipicationFactor = Math.pow(10, numberOfDecimalPlaces); | ||
double interestedInZeroDPs = valueToRound * multipicationFactor; | ||
return Math.round(interestedInZeroDPs) / multipicationFactor; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// ACCORDION | ||
// --------- | ||
|
||
|
||
// Parent container | ||
.accordion { | ||
margin-bottom: @baseLineHeight; | ||
} | ||
|
||
// Group == heading + body | ||
.accordion-group { | ||
margin-bottom: 2px; | ||
border: 1px solid #e5e5e5; | ||
.border-radius(4px); | ||
} | ||
.accordion-heading { | ||
border-bottom: 0; | ||
} | ||
.accordion-heading .accordion-toggle { | ||
display: block; | ||
padding: 8px 15px; | ||
} | ||
|
||
// Inner needs the styles because you can't animate properly with any styles on the element | ||
.accordion-inner { | ||
padding: 9px 15px; | ||
border-top: 1px solid #e5e5e5; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// ALERT STYLES | ||
// ------------ | ||
|
||
// Base alert styles | ||
.alert { | ||
padding: 8px 35px 8px 14px; | ||
margin-bottom: @baseLineHeight; | ||
text-shadow: 0 1px 0 rgba(255,255,255,.5); | ||
background-color: @warningBackground; | ||
border: 1px solid @warningBorder; | ||
.border-radius(4px); | ||
color: @warningText; | ||
} | ||
.alert-heading { | ||
color: inherit; | ||
} | ||
|
||
// Adjust close link position | ||
.alert .close { | ||
position: relative; | ||
top: -2px; | ||
right: -21px; | ||
line-height: 18px; | ||
} | ||
|
||
// Alternate styles | ||
// ---------------- | ||
|
||
.alert-success { | ||
background-color: @successBackground; | ||
border-color: @successBorder; | ||
color: @successText; | ||
} | ||
.alert-danger, | ||
.alert-error { | ||
background-color: @errorBackground; | ||
border-color: @errorBorder; | ||
color: @errorText; | ||
} | ||
.alert-info { | ||
background-color: @infoBackground; | ||
border-color: @infoBorder; | ||
color: @infoText; | ||
} | ||
|
||
// Block alerts | ||
// ------------------------ | ||
.alert-block { | ||
padding-top: 14px; | ||
padding-bottom: 14px; | ||
} | ||
.alert-block > p, | ||
.alert-block > ul { | ||
margin-bottom: 0; | ||
} | ||
.alert-block p + p { | ||
margin-top: 5px; | ||
} |
Oops, something went wrong.