Why does my static route change in spark framework when using get request? - spark-framework

I have the following simple main class that executes Spark.
Spark.port(4570);
final Configuration configuration = new Configuration(new Version(2, 3, 0));
configuration.setClassForTemplateLoading(SparkHandler.class, "/");
Spark.staticFileLocation("/public");
Spark.get("/", (request, response) -> {
// read patterns
// attributes for web-interface.
Map<String, Object> attributes = new HashMap<>();
attributes.put("data", "someData");
return new ModelAndView(attributes, "timeline.ftl");
} , new FreeMarkerEngine());
Everything woks fine. When I go to http://localhost:4570/ I got the requested web-page!
I now change the path in the get statement to /a/b/c but execute the very same code:
Spark.port(4570);
final Configuration configuration = new Configuration(new Version(2, 3, 0));
configuration.setClassForTemplateLoading(SparkHandler.class, "/");
Spark.staticFileLocation("/public");
Spark.get("/a/b/c", (request, response) -> {
// read patterns
// attributes for web-interface.
Map<String, Object> attributes = new HashMap<>();
attributes.put("data", "someData");
return new ModelAndView(attributes, "timeline.ftl");
} , new FreeMarkerEngine());
If I now go to e.g. http://localhost:4570/a/b/c, it returns messages that lots of resources that could previously be found are not available any more. E.g.
INFO 28/07/16 14:45:03:The requested route [/a/b/vis/vis.js] has not been mapped in Spark
However, it is exactly in the location /public/vis/vis.js.
Does that get command change my static directory? Or is something happening here that I just do not understand :).

I found the answer!
In my freemarker/html file I used relative parts like e.g.
<script src="./vis/vis.js"></script>
Changing them to absolute paths solves the problem:
<script src="/vis/vis.js"></script>
Sorry for the silly question, but maybe it helps others.

Related

How to parse an object variable in eventChannel callback method?

I am programming a flutter app, in which I have a callback from the native system containing some nfc information. I register the callback via the following line of code:
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
The callback looks like this:
void _onEvent(Object event) {
//Receive Event
print("NFC Event received");
//Get the Payload
event['Payload']; //This does not work, it gives an error
}
But how can I parse out the data? I know it contains a field by the name Payload however, I cannot access it via event['Payload'].
I am very confused, I tried to cast it to another type like this: Map<String, String> eventMap = Map<String, String>.from(event); but that didnt work. Could someone please point out what I am doing wrong and how I can correctly extract the data?
Without too much information of native part, I suggest
you can reference this package or fork this https://github.com/akeblom/flutter-nfc-reader
directly
this repo fix some issue of pub.dev and work well in real device
the dart code you need reside in
https://github.com/akeblom/flutter-nfc-reader/blob/master/lib/flutter_nfc_reader.dart
void _onEvent(dynamic data) {
print("Event");
print(data);
}
Edit add more detail
akeblom has add Write NFC capability to IOS, so IOS part should work. please ue this fork https://github.com/akeblom/flutter-nfc-reader
For IOS MissingPluginException issue, I do not have IOS, I suggest you can ask akeblom
The data part you mentioned in comments if I do not misunderstand is line 77, please see describe below
In Android part.
https://github.com/akeblom/flutter-nfc-reader/blob/master/android/src/main/kotlin/it/matteocrippa/flutternfcreader/FlutterNfcReaderPlugin.kt
line 174, use kotlin mapOf returns a new read-only map with the specified contents and eventSink.success result to Dart
if (message != null) {
val data = mapOf(kId to id, kContent to message, kError to "", kStatus to "read")
eventSink?.success(data)
}
In https://github.com/akeblom/flutter-nfc-reader/blob/master/lib/flutter_nfc_reader.dart
line 22, with named constructor
factory NfcData.fromMap(Map data) {
NfcData result = NfcData(
id: data['nfcId'],
content: data['nfcContent'],
error: data['nfcError'],
statusMapper: data['nfcStatus'],
);
In line 77, NFC read start and _onEvent(dynamic data) get the data.
stream use this named constructor, and parse data, here with map((result)) transfer to NfcData
static Stream<NfcData> get read {
final resultStream = _channel
.invokeMethod('NfcRead')
.asStream()
.asyncExpand((_) => stream
.receiveBroadcastStream()
.map((result) => NfcData.fromMap(result)));
return resultStream;
In https://github.com/akeblom/flutter-nfc-reader/blob/master/example/lib/main.dart
line 33, response has transfered to NfCData, so example just use _nfcData = response;
FlutterNfcReader.read.listen((response) {
setState(() {
_nfcData = response;
});
});
The simplest way I found to parse an event to a Map is the following:
I encoded the variable to a String (but I use json.encode(event)instead of event.toString()as encode(event)returns a valid string.
Then I use this string to construct a map via json.decode. All of this is achieved with the flutter native library dart:convert. The complete code looks like this:
import 'dart:convert';
...
void _onEvent(dynamic event) {
//Receive Event
print("NFC Event received");
String str = json.encode(event);
Map eventMap = json.decode(str);
}
Have you tried event.toString()? It might return a string containing the field you are trying to get, from which you can easily parse the value.
You may also want to try:
Class<?> clazz = event.getClass();
Field payload= clazz.getField("Payload"); //Note, this can throw an exception if the field doesn't exist.
String fieldValue = payload.toString();
If it isn't returning what you want, you may need to make an interface for the object type, with a get method, or override the toString method to get return the Payload value.

vertx how to reroute with query params

Due to some url versioning, we try to map multiple paths to the same handler.
I tried to achieve this via rerouting but the query parameters get lost in the process.
// reroute if the path contains apiv3 / api v3
router.route("/apiv3/*").handler( context -> {
String path = context.request().path();
path = path.replace("apiv3/", "");
LOG.info("Path changed to {}", path);
context.reroute(path);
});
What is the most elegant way around this problem?
There are some discussions on google groups but surprisingly nothing quick and simple to implement.
The reroute documentation says:
It should be clear that reroute works on paths, so if you need to
preserve and or add state across reroutes, one should use the
RoutingContext object.
So you could create a global catch-all route that stores any query param in the RoutingContext:
router.route().handler(ctx -> {
ctx.put("queryParams", ctx.queryParams());
ctx.next();
});
Then your apiv3 catch-all route:
router.route("/apiv3/*").handler( context -> {
String path = context.request().path();
path = path.replace("apiv3/", "");
LOG.info("Path changed to {}", path);
context.reroute(path);
});
Finally an actual route handler:
router.get("/products").handler(rc -> {
MultiMap queryParams = rc.get("queryParams");
// handle request
});

Getting server info

I'm looking to write some code that pulls from an external source. On our build/qa environment, I want it to hit a different source then production. Just need a way to identify the servers name. Similar to currentPage.getName(), but more like currentServer.getName().
Sorry for the limited info. I'm not a java developer. Here's what i've found.
Using this I was able to get a list of the available environment variables.
<%
Map<String, String> envMap = System.getenv();
SortedMap<String, String> sortedEnvMap = new TreeMap<String, String>(envMap);
Set<String> keySet = sortedEnvMap.keySet();
for (String key : keySet) {
String value = envMap.get(key);
%><%=key%>: <%=value%><br><%
}
%>
That led me to this bit of code.
String server = System.getenv("HOSTNAME");

Adobe AEM (CQ) 5.6 Remove renditions workflow

I'm looking for a way (preferably a workflow) that removes/cleans renditions!
My problem is that over time I have loads of images with renditions that are no longer used.
Is there a good way to clean this and "reclaim" my disk space? :)
Though i would like to suggest you sling servlet route to remove as you will have more control over what should be deleted and from which path.
You can reuse some of the code from below as well.
I created a sample program a few weeks back to remove renditions except the original one whenever a new image was added and i was using workflows:
The code below was a component. A workflow was created and this class was then added as a process step to a workflow and the same workflow was set in any launcher and event type was created.
Basically, i used Query builder api and workflow api and was able to achieve the same. If you use servlet way as suggested you can take path as a parameter and then use query builder api to locate the renditions folder and then iterate over the same and remove the nodes.
Sample values that will be extracted via query builder:
http://localhost:4502/bin/querybuilder.json?path=%2fcontent%2fdam%2fgeometrixx%2ficons&property=jcr%3aprimaryType&property.1_value=nt%3afolder
public void execute(WorkItem item, WorkflowSession wfsession, MetaDataMap args)
throws WorkflowException {
try {
resourceResolver = resourceResolverFactory.getAdministrativeResourceResolver(null);
WorkflowData workflowData = item.getWorkflowData();
String path = workflowData.getPayload().toString();
path = path.replace("/jcr:content/renditions", "");
session = resourceResolver.adaptTo(Session.class);
Map<String, String> map = new HashMap<String, String>();
map.put("path", path);
map.put("property", "jcr:primaryType");
map.put("property.1_value", "nt:folder");
Query query = builder.createQuery(PredicateGroup.create(map), session);
SearchResult result = query.getResult();
List<Hit> hits = result.getHits();
Resource renditionResource = resourceResolver.resolve(hits.get(0).getPath());
Iterator<Resource> reneditionIterator = renditionResource.listChildren();
while(reneditionIterator.hasNext()){
Resource specificResource= reneditionIterator.next();
Node renditionNode = specificResource.adaptTo(Node.class);
if(!renditionNode.getName().equals("original")){
renditionNode.remove();
}
}
} catch (LoginException e) {
e.printStackTrace();
}
Servlet
ResourceResolver resourceResolver = slingHTTPrequest.getResourceResolver();
String path = slingHTTPrequest.getParameter("path");
session = resourceResolver.adaptTo(Session.class);
Map<String, String> map = new HashMap<String, String>();
map.put("path", path);
map.put("property", "jcr:primaryType");
map.put("property.1_value", "nt:folder");
Query query = builder.createQuery(PredicateGroup.create(map), session);
SearchResult result = query.getResult();
List<Hit> hits = result.getHits();
for(Hit hit: hits){
Resource renditionResource = resourceResolver.resolve(hit.getPath());
Iterator<Resource> reneditionIterator = renditionResource.listChildren();
while(reneditionIterator.hasNext()){
Resource specificResource= reneditionIterator.next();
Node renditionNode = specificResource.adaptTo(Node.class);
LoggerUtil.debugLog(this.getClass(),"Node name will be {}",renditionNode.getName());
if(!renditionNode.getName().equals("original")){
LoggerUtil.debugLog(this.getClass(), "removing rendition, parent node name is{}",renditionNode.getParent().getParent().getParent().getName());
renditionNode.remove();
}
}
}

Need to scan WEB-INF/lib/xxx-ejb.jar for Type and Method annotations

I want to do the following using Google Reflections:
Scan only WEB-INF/lib/Patrac-ejb.jar
Scan only the package com.patrac and all of its sub-packages.
Scan for only type- and method annotations.
The following configuration seems to work fine but I don't have any experience with Google Reflections.
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.filterInputsBy(new FilterBuilder().include("Patrac-ejb.jar").include(FilterBuilder.prefix("com.patrac")))
.setScanners(new MethodAnnotationsScanner(), new TypeAnnotationsScanner())
.setUrls(ClasspathHelper.forWebInfLib(servletContext))
);
It appears to be working. I want to make sure it's not scanning all the other JARs in WEB-INF/lib. Is there an easy way to discover what JARs are being matched by the filter inputs in the configuration? Any advice about my approach would be much appreciated.
The following worked:
// Get the URL for Patrac-ejb.jar:
Set<URL> urls = ClasspathHelper.forWebInfLib(webUtil.getServletContext());
URL patracJarUrl = null;
for(URL url : urls)
{
if(url.getFile().endsWith("Patrac-ejb.jar"))
{
patracJarUrl = url;
break;
}
}
if(null == patracJarUrl)
{
throw new IllegalStateException("Patrac-ejb.jar not found.");
}
// Add the Patrac-ejb.jar URL to the configuration.
Configuration configuration = new ConfigurationBuilder()
.filterInputsBy(new FilterBuilder()
.include(FilterBuilder.prefix("com.patrac")))
.setScanners(new MethodAnnotationsScanner(), new TypeAnnotationsScanner())
.setUrls(patracJarUrl);