I need to manipulate owl file using the Protege-Owl API. You know, creating classes and properties isn't too difficult.But I don't know how to delete a class or property.If we treat the owl file as a graph, deleting an class means deleting an node and its direct edge.For exemple:
<owl:unionOf rdf:parseType="Collection">
<rdf:Description rdf:about="&data;DataBundle"/>
<rdf:Description rdf:about="&data;DataItem"/>
</owl:unionOf>
if I want to delete the class DataItem,
how should I do it using Protege-OWL API? Does RDFResource.delete()can achieve this? I have tried it,but I can't achieve this,maybe there is something wrong.
what will I get after I delete the DataItem?
If DataItem is the domain of an property, what will I get after I delete it?
I hope to get your answer.
Edit: the Protege OWL API is the api described here, not the OWL API described here.
#Joshua Taylor,Thank you for your answer!I'm a new user and I make a mistake for posting this problem twice.Sorry for that.I make some mistakes in my code at first and today I tried to fix it.The following codes can delete a class or property.
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import edu.stanford.smi.protegex.owl.ProtegeOWL;
import edu.stanford.smi.protegex.owl.jena.JenaOWLModel;
import edu.stanford.smi.protegex.owl.model.RDFResource;
public class DeleteClass {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//get model from an owl file
String filePath = "D:\\ss.owl";
FileInputStream inFile= new FileInputStream(filePath);
Reader in = new InputStreamReader(inFile,"UTF-8");
JenaOWLModel jenaOwlModel = ProtegeOWL.createJenaOWLModelFromReader(in);
//get an class from the model
RDFResource oneClass=jenaOwlModel.getRDFResource("Person");
RDFResource oneDataProperty=jenaOwlModel.getRDFResource("age");
//delete the resource
oneClass.delete();
oneDataProperty.delete();
//save the model to another owl file
URI file=URI.create("file:///D:/ssChange.owl");
System.out.println(file);
jenaOwlModel.save(file);
//System.out.println(oneClass);
}
}
Related
I need to convert an object of Map<String,String> with keys like "some_att_name" to class object fields like someAttName.
I couldn't find an easy way to do this.
MapStruct does support this type of mapping (From Map to object) since v1.5.0.Beta1 as stated here.
What I want should look something like this (similar to how JSON converters work):
#Mapper
public interface MapToObjectMapper {
MapToObjectMapper INSTANCE = Mappers.getMapper(MapToObjectMapper.class);
#Mapping(strategy = SnakeCaseToCamelCaseStrategy.class)
MyObject toMyObject(Map<String,String> map);
}
You'll have to translate the keys by yourself, but that's not that hard. Here is how I do it:
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Collections;
import java.util.Map;
import java.util.regex.Pattern;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toMap;
#Mapper
public interface MapToObjectMapper {
MapToObjectMapper INSTANCE = Mappers.getMapper(MapToObjectMapper.class);
private static String snakeToCamel(String snakeCaseString) {
// You can use Guava, Apache Commons, write it yourself or just use this one
// Credits to https://stackoverflow.com/a/67605103/4494577
return Pattern.compile("_([a-z])")
.matcher(snakeCaseString)
.replaceAll(m -> m.group(1).toUpperCase());
}
MyObject toMyObject(Map<String, String> map);
default MyObject toMyObjectFromSnakeCaseMap(Map<String, String> snakeKeyPropertyMap) {
return toMyObject(snakeKeyPropertyMap.entrySet().stream()
.collect(collectingAndThen(
toMap(s -> snakeToCamel(s.getKey()), Map.Entry::getValue),
Collections::unmodifiableMap)));
}
}
Full example: https://github.com/jannis-baratheon/stackoverflow--mapstruct-snake-case-map-mapping/
Looking at the docs I can't see a 1 step mapping. I think referring to From snake_case to camelCase in Java for converting your Map's keys to camelCase and then going for a mapper without #Mapping annotations might be your best chance.
I am recording the application through Wiremock using JAVA DSL, Do we have the option to customize the mapping file names? instead of getting the filename which is generated from wiremock..
Example: searchpanel_arrivalairport_th-72f9b8b7-076f-4102-b6a8-aa38710fde1b.json (Generated form wiremock using java )
I am expecting the above file name with my desired naming convention like
seacrpanel_airport_LGW.json
Custom filenames can be added by customizing StubMappingJsonRecorder.
I added CustomStubMappingJsonRecorder and override writeToMappingAndBodyFile method.
if(fileName!=null && !fileName.equals("")){
mappingFileName=fileName+"-mapping.json";
bodyFileName=fileName+"-body.json";
}else {
mappingFileName = UniqueFilenameGenerator.generate(request.getUrl(),
"mapping", filed);
bodyFileName = UniqueFilenameGenerator.generate(request.getUrl(), "body",
fileId, ContentTypes.determineFileExtension(request.getUrl(),
response.getHeaders().getContentTypeHeader(), body));
}
There's no easy way to do this at the moment. It is however possible. As #santhiya-ps says you need to write your own implementation of RequestListener, probably using StubMappingJsonRecorder as a template.
You can't extend it and override writeToMappingAndBodyFile as that method is private, but that is the method you probably want to change.
import com.github.tomakehurst.wiremock.common.*;
import com.github.tomakehurst.wiremock.core.*;
import com.github.tomakehurst.wiremock.http.*;
import java.util.List;
import static com.github.tomakehurst.wiremock.core.WireMockApp.*;
class NameTemplateStubMappingJsonRecorder implements RequestListener {
private final FileSource mappingsFileSource;
private final FileSource filesFileSource;
private final Admin admin;
private final List<CaseInsensitiveKey> headersToMatch;
private final IdGenerator idGenerator = new VeryShortIdGenerator();
public NameTemplateStubMappingJsonRecorder(Admin admin) {
this.mappingsFileSource = admin.getOptions().filesRoot().child(MAPPINGS_ROOT);
this.filesFileSource = admin.getOptions().filesRoot().child(FILES_ROOT);
this.admin = admin;
this.headersToMatch = admin.getOptions().matchingHeaders();
}
#Override
public void requestReceived(Request request, Response response) {
// TODO copy StubMappingJsonRecorder changing as required...
}
}
You can then register your RequestListener as so:
WireMockServer wireMockServer = new WireMockServer();
wireMockServer.addMockServiceRequestListener(
new NameTemplateStubMappingJsonRecorder(wireMockServer)
);
wireMockServer.start();
So long as you still store the mapping files in the expected directory (stored in FileSource mappingsFileSource above, which will be ${rootDir}/mappings, where rootDir is configured as explained in Configuration - File Locations) they should be loaded successfully as all files with extension json in that dir are loaded as mappings.
It would be much easier if StubMappingJsonRecorder took a strategy for generating these names - it might be worth creating an issue on the WireMock repo asking for an easier way to do this. I'd suggest getting an agreement on a basic design before raising a PR though.
Scenario: (AEM 6.3.2) I'm requesting a page with the selector "test1", like this:
http://localhost:4502/content/myapp/home.test1.html
This page have a parsys where I have drop a component "slider", so the component's path is: "/content/myapp/home/jcr:content/parsys/slider"
At the "slider" component level, how can I access to the "test1" selector?
I've tried different ways (SlingModel, WCMUsePojo, the "request" HTL Global Object...), but always get the same problem: the "request" I can access is the GET request of the component (GET "/content/myapp/home/jcr:content/parsys/slider.html") where the selector is not present.
You should use the method SlingHttpServletRequest##getPathInfo inherited from HttpServletRequest
In your example, if you make a request to:
http://localhost:4502/content/myapp/home.test1.html
Then in your component's Class (Use/SlingModel) you can call request.getPathInfo() which will return: /content/myapp/home.test1.html
Then you can parse that path using: com.day.cq.commons.PathInfo
Here is an example sling model:
package com.mycom.core.models;
import com.day.cq.commons.PathInfo;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;
#Model(adaptables = SlingHttpServletRequest.class,
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class SampleModel {
#Self
SlingHttpServletRequest request;
public PathInfo getPathInfo() {
return new PathInfo(request.getPathInfo());
}
}
then in your HTML you can do:
<sly data-sly-use.sample="com.mycom.core.models.SampleModel"/>
<div>${sample.pathInfo.selectors # join=', '}</div>
An that will output: (based on your example path)
<div>test1</div>
Just checked the exact same component/code on another AEM instance (same version) and it's working... will check what can be causing the wrong behavior, but I guess the problem is solved!
I need to display the title and name of all child and grand child pages from given path in JSON format. Please provide the implementation.
First You have to try something yourself, then you call for help, not the complete solution!anyway there are couple of solution down there.
According to Adobe here you can implement page information in JSON format:
package com.adobe.example;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageInfoProvider;
#Component(metatype = false)
#Properties({
#Property(name="service.description", value="Returns the public URL of a resource.")
})
#Service
public class PageUrlInfoProvider implements PageInfoProvider {
#Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
private com.day.cq.commons.Externalizer externalizer;
private String fetchExternalUrl(ResourceResolver rr, String path) {
return externalizer.publishLink(rr, path);
}
public void updatePageInfo(SlingHttpServletRequest request, JSONObject info, Resource resource)
throws JSONException {
Page page = resource.adaptTo(Page.class);
JSONObject urlinfo = new JSONObject();
urlinfo.put("publishURL", fetchExternalUrl(null,page.getPath()));
info.put("URLs",urlinfo);
}
}
Or you may try this Page for solution
Please refer to below link which may be useful:
http://www.nateyolles.com/blog/2015/12/converting-aem-sling-resources-to-json.
Apart from the above solution you also use recursive level to get the data in the JSON format for example /content/we-retail/language-masters/en.{placeholder}.json
replace the placeholder with the level of nodes you want to print and return back the JSON wherever needed.
To know more about the rendering data in different formats,
Refer: https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html
I implemented workflows, but it would be nice to know if there are hooks provided by the client library which allow to hook in. When a workflow was triggered and finished, a CQ.Notification should be displayed. Or do i need to implement a polling library by myself?
As far as I know, there is no built-in CQ area to see when something is done, aside from looking here:
http://yoursite.com:port/libs/cq/workflow/content/console.html
Once there, you can go to the 'Instances' tab and see what's happening.
In one application that I worked on, we ended up writing our own method that sends notifications to us based on one of our workflows (our workflow ties into it - from the workflow models area, you can set your process to be a servlet that you've put into CQ). Here is the main piece of code from our servlet that catches the process being active, and then calls our methods to email us based on what it finds:
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.Arrays;
public class YourServletName implements WorkflowProcess {
#Override
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
session = workflowSession.getSession();
final WorkflowData data = workItem.getWorkflowData();
String type = data.getPayloadType();
String[] argStrings = args.get("PROCESS_ARGS", ARG_UPDATED).split(",");
String reason = argStrings[0];
String baseUrl = argStrings[1];
try {
if (type.equals(TYPE_JCR_PATH) && data.getPayload() != null) {
String resourcePath = data.getPayload().toString();
logger.info("Send Notification that {} has been {}.", resourcePath, reason.toLowerCase());
if (resourcePath != null && !resourcePath.isEmpty()) {
ResourceInfo resourceInfo = new ResourceInfo(resourcePath, baseUrl);
sendEmail(resourceInfo, reason);
}
}
} catch (EmailException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
} catch (MailingException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
}
}
}
You can find more info in the documentation for Extending Workflow Functionality.
Look at the first code block on that page, and that will give you the best idea of how you can implement a custom workflow handler.
EDIT
If you want to see it on the front-end, you could do an AJAX call to get the JSON list of currently running workflows - you can hit this url:
http://localhost:4502/etc/workflow/instances.RUNNING.json
Then you could loop through them and see if yours is in there. This isn't very nice though, since they are all just listed by IDs. I would instead suggest using the querybuilder, or again, just doing an AJAX GET. This is one example:
1_group.0_path=/etc/workflow/instances
2_group.0_type=cq:Workflow
0_group.property.2_value=COMPLETED
0_group.property=status
0_group.property.and=true
3_group.property=modelId
3_group.property.2_value=/etc/workflow/models/your-model-name/jcr:content/model
3_group.property.and=true
Then the URL would look something like this:
http://yoursiteurl:port/libs/cq/search/content/querydebug.html?_charset_=UTF-8&query=http%3A%2F%2Fyoursiteurl%3Aport%3F%0D%0A1_group.0_path%3D%2Fetc%2Fworkflow%2Finstances%0D%0A2_group.0_type%3Dcq%3AWorkflow%0D%0A0_group.property.2_value%3DRUNNING%0D%0A0_group.property%3Dstatus%0D%0A0_group.property.and%3Dtrue%0D%0A3_group.property%3DmodelId%0D%0A3_group.property.2_value%3D%2Fetc%2Fworkflow%2Fmodels%2Fyour-model-name%2Fjcr%3Acontent%2Fmodel%0D%0A3_group.property.and%3Dtrue
It's ugly, but it gets you the results you need, and then you can parse them to get further information you need.