We have 5 custom reports for our 94 districts. A capability grants access to these custom reports.
The issue is that each district should not see the report results from another district.
Currently, the only alternative is to create 5 * 94 = 470 custom reports, granting a set of 5 to each district. However, this is cumbersome when a report needs to be updated.
TaskDefinitions (Reports) create TaskResult objects (the result of a report). In addition, to the TaskResult object, a JasperReport object is created. Neither the TaskResult/JasperResult object "re-executes" BeanShell when you open the task result.
Is there a way to only have 5 reports and scope the results so that only users in that district can see them?
I have an example of how this might be achieved when based on this code below which will look at the scope(s) of the one who is running the report. It will only return identities that are in the same scope as the one that is running the report
// Retrieve Scope of Executor then filter all Identities on that Scope only
import org.apache.commons.logging.Log;
import sailpoint.object.Filter;
import sailpoint.object.Identity;
import sailpoint.object.Scope;
Identity identity = context.getObjectByName(Identity.class, arguments.get("launcher"));
if (identity != null) {
String scopeName = identity.getAssignedScope().getDisplayableName();
List roleFilters = new ArrayList();
if (scopeName!= null) {
roleFilters.add(Filter.eq("identity.assignedScope.name", scopeName));
}
if (!roleFilters.isEmpty()) {
queryOptions.addFilter(Filter.or(roleFilters));
}
} else {
// When Saving with Preview or Execute the Launcher is empty so all results would be shown.
// This filter will prevent that (creates empty report, it works when executed from the My Reports
queryOptions.addFilter(Filter.eq("identity.name", "xxx"));
}
return queryOptions;
The problem with the code sample above:
This will create the report intended for Group A, however Group B, and C will also be able to view it.
So the end goal is to have one report that anyone can run, however only the data that is associated with that scope is visible no matter what user group is involved (scope). So Group B would only be able to view Group B even if Group A ran it.
I think you don't have good options here.
What comes to my mind is to create these reports programatically (writing some script to generate the XML artifact for the TaskDefinition and importing/exporting using IIQDA for example) and maintain them in the same way, so everytime you need to change each one of these hundreds of artifacts, you can just re-generate them via code.
The only thing I'd do in a different way is to use 94 scopes for each 5-set report instead of using capabilities.
Related
I am working an automation for IBM Rational Team Concert (IBM aka Jazz RTC).
How may one list all streams owned by a specific project area?
Which are the required API calls?
I could not find any getters in the IProjectArea instance, nor service or client instances with such methods. And I could not figure out how to use search criteria for this purpose.
The streams owned by a project area may be queried using IWorkspaceSearchCriteria. Because streams are, actually, workspaces of type 'stream'. The API is not quite clear how to specify the owning project area.
Get the IWorkspaceManager from the ITeamRepository, which contains the findWorkspaces method.
You don't need IProjectAreaHandle. Only the project area name.
Create a IWorkspaceSearchCriteria and set kind to IWorkspaceSearchCriteria.STREAMS and set exactOwnerName to the string containing the project area name.
Call IWorkspaceManager.findWorkspaces(...) to get a list of IWorkspaceHandles. The first parameter is the search criteria. Se second parameter is the maximum number of results (which I set to IWorkspaceManager.MAX_QUERY_SIZE, which is 512. The third parameter is the progress monitor, which may be null.
If you need to get stream name, description or other attributes, then you need to call IItemManager.fetchCompleteItems(...) fetch the full IWorkspace instances.
Here is an example in Groovy:
Lit<IComponentHandle> listComponents(String projectAreaName) {
final manager = repositoty.getClientLibrary(IWorkspaceManager) as IWorkspaceManager;
final criteria = IWorkspaceSearchCriteria.FACTORY.newInstance();
criteria.setKind(IWorkspaceSearchCriteria.STREAMS);
criteria.setExactOwnerName(projectAreaName)
final itemManager = repositoty.itemManager()
return itemManager.fetchCompleteItems(handles, IItemManager.DEFAULT, null) as List<IWorkspace>
}
I am currently trying to implement file exports in background so that the user can do some actions while the file is downloading.
I used the apache isis CommandExexuteIn:Background action attribute. However, I got an error
"Not an (encodable) value", this is an error thrown by the ScalarValueRenderer class.
This is how my method looks like:
#Action(semantics = SemanticsOf.SAFE,
command = CommandReification.ENABLED)
commandExecuteIn = CommandExecuteIn.BACKGROUND)
public Blob exportViewAsPdf() {
final Contact contact = this;
final String filename = this.businessName + " Contact Details";
final Map<String, Object> parameters = new HashMap<>();
parameters.put("contact", contact);
final String template = templateLoader.buildFromTemplate(Contact.class, "ContactViewTemplate", parameters);
return pdfExporter.exportAsPdf(filename, template);
}
I think the error has something to do with the command not actually invoking the action but returns the persisted background command.
This implementation actually worked on the method where there is no return type. Did I miss something? Or is there a way to implement background command and get the expected results?
interesting use case, but it's not one I anticipated when that part of the framework was implemented, so I'm not surprised it doesn't work. Obviously the error message you are getting here is pretty obscure, so I've raised a
JIRA ticket to see if we could at least improve that.
I'm interested to know in what user experience you think the framework should provide here?
In the Estatio application that we work on (that has driven out many of the features added to the framework over the last few years) we have a somewhat similar requirement to obtain PDFs from a reporting server (which takes 5 to 10 seconds) and then download them. This is for all the tenants in a shopping centre, so there could be 5 to 50 of these to generate in a single go. The design we went with was to move the rendering into a background command (similar to the templateLoader.buildFromTemplate(...) and pdfExporter.exportAsPdf(...) method calls in your code fragment, and to capture the output as a Document, via the document module. We then use the pdfbox addon to stitch all the document PDFs together as a single downloadable PDF for printing.
Hopefully that gives you some ideas of a different way to support your use case
Thx
Dan
How can I access the history of a Workflow instance using the Adobe AEM api for java?
Say I've created one workflow which contains 3 workitems. I want to access the details associated with all the workitems for that workflow (E.g.Status,Title,User,StartTime,EndTime,Action,Comment).
Take a look at the following classes.
com.day.cq.workflow.WorkflowSession
https://docs.adobe.com/docs/en/cq/5-6-1/javadoc/com/day/cq/workflow/WorkflowService.html
and
com.day.cq.workflow.WorkflowSession
https://docs.adobe.com/docs/en/cq/5-6-1/javadoc/com/day/cq/workflow/WorkflowSession.html
If you want to see a code example on how to filter on a particular workflow instance, you can find a lot of documents in the following file of your AEM instance:
/crx/de/index.jsp#/libs/cq/workflow/components/console/archive/json.jsp
In summary, you will need to create a workflow service and fetch the model to iterate over it's instances to apply relevant filters.
Alternatively, you can write a query to get data from /var/eventing/jobs node which is essentially a workflow instance data store.
This might work for you
List<HistoryItem> history = workflowSession.getHistory(workItem.getWorkflow());
HistoryItem current;
if (history.size() > 0) {
HistoryItem current = history.get(history.size() - 1);
do {
current = current.getPreviousHistoryItem();
} while (current != null);
}
I want to create a Role for each User Group within my portal so that I can grant specific access to many users at once, depending on what groups they belong to.
Using Liferay API, is there any way to programmatically add a Role for each User Group that exists within the Portal?
This would be more efficient than adding each role individually through the UI.
Something like
for(i = 0; i < userGroups.size(); i++){
roles.add(userGroups[i].getName());
}
If possible, I'd like to then assign the same User Group to that Role within the same method, otherwise the role would know nothing of the associated user group:
roles.assignUserGroup(userGroups[i]);
Anyone accomplished a task similar to this?
Linked Liferay Forum Post http://liferay.com/community/forums/-/message_boards/message/46355079
In short you need to create a Role with a similar name as that of the UserGroups you have and then assign the UserGroup to that Role.
You can do that programmatically with Liferay's API, since that is how liferay also creates the different types of Roles and assigns users, user-groups etc to the role.
You just need to dig into to the source code to do this. Check source code for RoleLocalServiceImpl, UserGroupLocalServiceImpl and GroupLocalServiceImpl.
I am providing the steps for Liferay v6.2, there should not be much change in 6.0 and 6.1:
Fetch all the UserGroups using UserGroupLocalServiceUtil.getUserGroups(companyId)
Loop through it as you have done:
for (UserGroup userGroup : userGroups) {
... // steps to follow
}
Get the name of the UserGroup: userGroup.getName()
Create a Role using RoleLocalServiceUtil.addRole( ... ) and assign the userGroup to role using GroupLocalServiceUtil.addRoleGroups( ... )
for (UserGroup userGroup : userGroups) {
String userGroupName = userGroup.getName();
// for locale specific title (optional, can be null)
Map<Locale, String> titleMap = new HashMap<Locale, String>();
titleMap.put(Locale.ENGLISH, userGroupName);
// for locale specific description (optional, can be null)
Map<Locale, String> descriptionMap = new HashMap<Locale, String>();
titleMap.put(Locale.ENGLISH, "Role created for UserGroup - " + userGroupName);
int type = RoleConstants.TYPE_REGULAR;
// adding the role
Role role = RoleLocalServiceUtil.addRole(userId, Role.class.getName(), 0, userGroupName, titleMap, descriptionMap, type, null, null);
// assigning the UserGroup to the role
GroupLocalServiceUtil.addRoleGroups(role.getRoleId(), new long[]{userGroup.getGroupId()}); // need to pass groupId and not userGroupId
}
Now were would you write this code-snippet? There are various places depending upon what requirement you have:
Custom plugin portlet with a UI to execute this code. (better if required periodically)
Custom plugin action-hook and the code goes inside a StartUpAction, executes the code when the hook is being deployed. Hook should be undeployed or else will run everytime the hook is deployed. (better for one time use)
Custom plugin upgrade hook, executes the code during deployment once based on the upgrade condition. (better for one time use)
Use Beanshell, Server Administration → Script → Select Beanshell → Paste the code-snippet → Execute. You need to have the proper import statements and then just the code-snippet and you are good to go. For an example of Beanshell usage you can check my other answer. (better for one time use)
Even after all this you would still have to take the pains to give permission to each role ;-)
Hope this helps though.
I'm new to Drools Expert, currently from the Sample project of the drools what I can only do is print something to the console. Now I integrate drools to a web project and It was successful, I was be able to print something to the console depending on the interaction of the user to the page.
My rules currently is like this:
rule "A test Rule"
when
m: FLTBean ( listeningScore == 1, test : listeningScore )
then
System.out.println( test );
end
So what if I want to print it out to a web page? How would I do that? Do I need to use return to return some value back to the java page and render it to the page?
In order to display something on a web page, then you need to be using the API to invoke Drools and get some output, which can then be rendered by your web application.
Therefore, you need to consider how to get output from it within your Java code. There are a few ways of doing this.
For example, when performing a simple action such as validating a request, then just operate on the request which you insert. For instance:
rule "IBAN doesn't begin with a country ISO code."
no-loop
when
$req: IbanValidationRequest($iban:iban, $country:iban.substring(0, 2))
not Country(isoCode == $country) from countryList
then
$req.reject("The IBAN does not begin with a 2-character country code. '" + $country + "' is not a country.");
update($req);
end
In that example, I'm calling a "reject" method on the fact which I inserted. That modifies the inserted fact, so that after rules execution, I have an object in my Java code, with a flag to indicate whether it was rejected or not. This method works well for stateless knowledge sessions. i.e.
Java code - Insert request fact via API
Drools rule - Modify the request fact (flag rejection, annotate, set properties, etc)
Java code - Look at the fact to see what was done to it
The following code example of how to perform this interaction is taken from the following full colass:
https://github.com/gratiartis/sctrcd-payment-validation-web/blob/master/src/main/java/com/sctrcd/payments/validation/payment/RuleBasedPaymentValidator.java
// Create a new knowledge session from an existing knowledge base
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
// Create a validation request
PaymentValidationRequest request = new PaymentValidationRequest(payment);
// A stateless session is executed with a collection of Objects, so we
// create that collection containing just our request.
List<Object> facts = new ArrayList<Object>();
facts.add(request);
// And execute the session with that request
ksession.execute(facts);
// At this point, rules such as that above should have been activated.
// The rules modify the original request fact, setting a flag to indicate
// whether it is valid and adding annotations to indicate if/why not.
// They may have added annotations to the request, which we can now read.
FxPaymentValidationResult result = new FxPaymentValidationResult();
// Get the annotations that were added to the request by the rules.
result.addAnnotations(request.getAnnotations());
return result;
An alternative in a stateful session would be that rules could insert facts into working memory. After executing the rules, you can then query the session via the API and retrieve one or more result objects. You can get all facts in the session using the getObjects() method of the KnowledgeSession. To get facts with particular properties, there is also a getObjects(ObjectFilter) method. The project linked below has examples of using these methods in the KnowledgeEnvironment and DroolsUtil classes.
Alternatively, you could insert a service as a global variable. The rules could then invoke methods on that service.
For an example of how to use Drools within a web application, I knocked up this web site recently, which provides a REST API to invoke Drools rules and get responses.
https://github.com/gratiartis/sctrcd-payment-validation-web
If you have Maven installed, you should be able to try it out pretty quickly, and play around with the code.