I've recently entered the world of AEM and sling (api). What I'm trying to do is write Java code to get the sling:members and its properties sling:resources for a new collection I created in the touch. I'm able to reference the collection properties with a ResourceResolver.resolve(path). The sling:members show up as { ....}. Do I have to do a separate ResourceResolver?
String path="/content/dam/collections/m/fafdsfdaf/my_collection";
Resource resourceMember = resourceResolver.resolve(path+"/sling:members");
ValueMap metaData = resourceMember.adaptTo(ValueMap.class);
String[] slingResources = metaData.get("sling:resources", new String[0]);
Am I totally off the mark? Any help would be greatly appreciated.
The correct way to get the members of the collection is to use the ResourceCollection API. To do this you obtain the resource which points to the collection then adapt it to a ResourceCollection. From there you call getResources() which returns you an iterator over the members.
Resource r = resourceResolver.getResource("/content/dam/collections/m/fafdsfdaf/my_collection");
ResourceCollection collection = r.adaptTo(ResourceCollection.class);
Iterator<Resource> it = collection.getResources();
while(it.hasNext()) {
Resource p = it.next();
%><%= p.getPath() %><%
}
Turns out this is the correct way to do this and is working.
Related
I am trying to modify a field in select objects in a List but I am unable to find a way to do so, using plain Iterator because it has no set() method.
I tried using ArrayListIterator that provides a set() method, but this throws a casting exception. Is there way to workaround this?
Iterator it = topContainer.subList.iterator();
while (it.hasNext()) {
MyObject curObj = (MyObject) it.next();
if ( !curObj.getLabel().contains("/") ) {
String newLabel = curObj.getLabel() + "/";
curObj.setLabel(newLabel);
((ArrayListIterator) it).set(curObj)
}
}
I expect the original current object in the list to be set without incident, but instead I am getting this exception:
java.util.ArrayList$itr cannot be cast to
org.apache.commons.collections.iterators.ArrayListIterator
What is the proper way of accomplishing what I would like to do?
You do not need to call set at all. You can just call setLabel on curObj:
// please, don't use raw types!
Iterator<? extends MyObject> it = topContainer.subList.iterator();
while (it.hasNext()) {
MyObject curObj = it.next();
if ( !curObj.getLabel().contains("/") ) {
String newLabel = curObj.getLabel() + "/";
curObj.setLabel(newLabel);
}
}
The correct way would be following (works not for java versions below 1.5):
for(MyObject curObj : topContainer.subList){
if (!curObj.getLabel().contains("/")) {
String newLabel = curObj.getLabel() + "/";
curObj.setLabel(newLabel);
}
}
This is an enhanced for-loop, and it does call the iterator too, but you can't see it.
Also setting the object via the iterator is not needed, as you're working with references to Objects in Java, when you edit an object, everyone that has a pointer to that object, will see the change too. For more you can read this great post: Is Java “pass-by-reference” or “pass-by-value”?
If you can't use Java 5, then you're missing out big time. The current java version is 11. So you should really, really, really, upgrade your JDK
you just have to set the label. In JAVA 11 you can use streams. it makes your code more readable.
List<MyObject> list = topContainer.subList;
list
.stream()
.filter(Predicate.not(e->e.getLabel().contains("/")))
.forEach(e->e.setLabel(e.getLabel()+"/"));
In java 8 you can use
(!e->e.getLabel().contains("/"))
instead of
Predicate.not(e->e.getLabel().contains("/")
I need to convert an object i got from database to a map, how can i do that?
Variable that should contain data inside the object
public Map<Byte, Byte> currentSkills = new ConcurrentHashMap<>();
How I get that object from the database
MongoCollection<Document> users = Database.connection.getDatabase("app").getCollection("users");
Document playerInfo = users.find(eq("Name", username)).first();
player.skills.currentSkills = playerInfo.get("Skills");
I made a little research and found some libraries that can do it, is there any way i can do this without using external libraries?
I am trying to retrieve the node 0's property - tag values, which is a linkedList object property I believe. as you can see it is [****,****]
I wish to retrieve the object value and store into a List<String> object
So I can get the each value out for late use, e.g
String idA = "542f74fd-bfaf-4377-854a-8e62082edc6c";
string idB = "39aab11f-243f-464c-ae6d-c1f069f17d6c";
My attampt is something like below:
List<String> tagList = new ArrayList<String>();
tagList = componentNode.getProperties(node, "tags");
also tried this:
List<String> tagList = new ArrayList<String>();
tagList = PropertyUtil.getProperty(node, "tags");
but none of them works.
Please suggest me with code sample.
Thanks
I believe they are called multi value properties in JCR and is supported via Arrays instead of Lists.
I haven't tested the code myself but I believe it'll work.
This should do the trick:
Property property = node.getProperty("tags");
Value[] tags = property.getValues();
and then you can convert/wrap it to List if you really want to.
Hope that helps,
Cheers,
Title of the question may give you the impression that it is duplicate question, but according to me it is not.
I am just a few months old in Java and a month old in MongoDB, SpringBoot and REST.
I have a Mongo Collection with 3 fields in a document, _id (default field), appName and appKey. I am using list to iterate through all the documents and find one document whose appName and appKey matches with the one that is passed. This collection right now has only 4 entries, and thus it is running smoothly. But I was reading a bit about collections and found that if there will be a higher number of documents in a collection then the result with list will be much slower than hashMap.
But as I have already said that I am quite new to Java, I am having a bit of trouble converting my code to hashMap, so I was hoping if someone can guide me through this.
I am also attaching my code for reference.
public List<Document> fetchData() {
// Collection that stores appName and appKey
MongoCollection<Document> collection = db.getCollection("info");
List<Document> nameAndKeyList = new ArrayList<Document>();
// Getting the list of appName and appKey from info DB
AggregateIterable<Document> output = collection
.aggregate(Arrays.asList(new BasicDBObject("$group", new BasicDBObject("_id",
new BasicDBObject("_id", "$id").append("appName", "$appName").append("appKey", "$appKey"))
)));
for (Document doc : output) {
nameAndKeyList.add((Document) doc.get("_id"));
}
return nameAndKeyList;
}// End of Method
And then I am calling it in another method of the same class:
List<Document> nameAndKeyList = new ArrayList<>();
//InfoController is the name of the class
InfoController obj1 = new InfoController();
nameAndKeyList = obj1.fetchData();
// Fetching and checking if the appName & appKey pair
// is present in the DB one by one.
// If appName & appKey mismatches, it increments the value
// of 'i' and check them with the other values in DB
for (int i = 0; i < nameAndKeyList.size(); i++) {
"followed by my code"
And if I am not wrong then there will be no need for the above loop also.
Thanks in advance.
You just need a simple find query to get the record you need directly from Mongo DB.
Document document = collection
.find(new Document("appName", someappname).append("appKey", someappkey)).first();
First of all a list is not much slower or faster than an HashMap. A Hasmap is commonly used to save key-pair values such as "ID", "Name" or something like that. In your case I see you are using ArrayList without a specified size for the list. better use a linked list when you do not know the size because an arraylist is holding a array behind and extending this by copying. If you want to generate a Hasmap out of the List or use a Hasmap you need to map an ID and the value to the records.
HashMap<String /*type of the identifier*/, String /*type of value*/> map = new HashMap<String,String>();
for (Document doc : output) {
map.put(doc.get("_id"), doc.get("_value"));
}
First, avoid premature optimization (lookup the expression if you don’t know what it is). Put a realistic number of thousands of items containing near-realistic data in your list. Try to retrieve an item that isn’t there. This will force your for loop to traverse the entire list. See how long it takes. Try a number of times to get an impression of whether you get impatient. If you don’t, you’re done.
If you find out that you need a speed-up, I agree that HashMap is one of the obvious solutions to try. One of the first things to consider with this is a key type for you HashMap. As I understand, what you need to search for is an item where appName and appKey are both right. The good solution is to write a simple class with these two fields and equals and hashCode methods (I’ll call it DocumentHashMapKey for now, think of a better name). For hashCode(), try Objects.hash(appName, appKey). If it doesn’t give satisfactory performance with the data you have, consider alternatives. Now you are ready to build your HashMap< DocumentHashMapKey, Document>.
If you’re lazy or just want a first impression of how a HashMap performs, you may also build your keys by concatenating appName + "$##" + appKey (where the string in the middle is something that is unlikely to be part of a name or key) and use HashMap<String, Document>.
Everything I said can be refined depending on your needs. This was just to get you started.
Thanks everyone for your help, without which I would not have got to a solution.
public HashMap<String, String> fetchData() {
// Collection that stores appName and apiKey
MongoCollection<Document> collection = db.getCollection("info");
HashMap<String, String> appKeys = new HashMap<String, String>();
// Getting the list of appName and appKey from info DB
AggregateIterable<Document> output = collection
.aggregate(Arrays.asList(new BasicDBObject("$group", new BasicDBObject("_id",
new BasicDBObject("_id", "$id").append("appName", "$appName").append("appKey", "$appKey"))
)));
String appName = null;
String appKey = null;
for (Document doc : output) {
Document temp = (Document) doc.get("_id");
appName = (String) temp.get("appName");
appKey = (String) temp.get("appKey");
appKeys.put(appName, appKey);
}
return appKeys;
Calling the above method into another method of the same class.
InfoController obj = new InfoController();
//Fetching the values of 'appName' & 'appKey' sent from 'info' DB
HashMap<String, String> appKeys = obj.fetchData();
storedAppkey = appKeys.get(appName);
//Handling the case of mismatch
if (storedAppkey == null || storedApikey.compareTo(appKey)!=0)
{//Then the response and further processing that I need to do.
Now what HashMap has done is that it has made my code more readable and the 'for' loop that I was using for iterating is gone, although it might not make much difference in the performance as of now.
Thanks once again to everyone for your help and support.
When looking at the documentation for Geotools FeatureCollection, the subsection on Performance Options notes:
TreeSetFeatureCollection: the traditional TreeSet implementation used by default.
Note this does not perform well with spatial queries as the contents
are not indexed.
Later it recommends a SpatialIndexFeatureCollection for faster queries:
SpatialIndexFeatureCollection: uses a spatial index to hold on to
contents for fast visual display in a MapLayer; you cannot add more
content to this feature collection once it is used
DataUtilities.source( featureCollection ) will wrap
SpatialIndexFeatureCollection in a SpatialIndexFeatureSource that is
able to take advantage of the spatial index.
The example given is:
final SimpleFeatureType TYPE =
DataUtilities.createType("location","geom:Point,name:String");
WKTReader2 wkt = new WKTReader2();
SimpleFeatureCollection collection = new SpatialIndexFeatureCollection();
collection.add( SimpleFeatureBuilder.build( TYPE, new Object[]{ wkt.read("POINT(1,2)"), "name1"} ));
collection.add( SimpleFeatureBuilder.build( TYPE, new Object[]{ wkt.read("POINT(4,4)"), "name1"} ));
// Fast spatial Access
SimpleFeatureSource source = DataUtilities.source( collection );
SimpleFeatureCollection features = source.getFeatures( filter );
Besides not being able to compile this code (SimpleFeatureCollection is an interface and does not contain the member add), the code for SpatialIndexFeatureSource.getFeatures(Filter) directly calls SpatialIndexFeatureCollection.subCollection(Filter) which is defined as
public SimpleFeatureCollection subCollection(Filter filter) {
throw new UnsupportedOperationException();
}
Github
Here is an example of my own attempt to use this
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
SimpleFeatureCollection answers = getAnswers();
SpatialIndexFeatureCollection collection = new SpatialIndexFeatureCollection();
collection.addAll(answers);
SimpleFeatureSource source = DataUtilities.source( collection );
SimpleFeatureCollection gridCollection = getGridCollection();
SimpleFeatureIterator iter = gridCollection.features();
while(iter.hasNext()) {
SimpleFeature grid = iter.next();
Geometry gridCell = (Geometry) grid.getDefaultGeometry();
Filter gridFilter = ff.intersects(ff.property("geometry"), ff.literal(gridCell));
SimpleFeatureCollection results = source.getFeatures(combinedFilter);
}
Unsurprisingly, this results in a UnsupportedOperationException
I have not been able to get this example to work and would really like to take advantage of the spatial indexing. How am I supposed to use a SpatialIndexFeatureCollection similar to the above example?
SpatialIndexFeatureCollection now implements the subCollection method. See the PR here. I haven't had a chance to backport the changes but future releases will now work the way you expected.