I am using AEM 6.1 with Maven as the build manager. I have updated the .m2 local folder with the unobfuscated UberJar provided by Adobe. I am getting the following error:
ERROR [JobHandler: /etc/workflow/instances/server0/2016-07-15/model_157685507700064:/content/myApp/testing/wf_test01]
com.adobe.granite.workflow.core.job.JobHandler Process implementation
not found: com.myApp.workflow.ActivatemyAppPageProcess
com.adobe.granite.workflow.WorkflowException: Process implementation
not found: com.myApp.workflow.ActivatemyAppPageProcess at
com.adobe.granite.workflow.core.job.HandlerBase.executeProcess(HandlerBase.java:197)
at
com.adobe.granite.workflow.core.job.JobHandler.process(JobHandler.java:232)
at
org.apache.sling.event.impl.jobs.JobConsumerManager$JobConsumerWrapper.process(JobConsumerManager.java:512)
at
org.apache.sling.event.impl.jobs.queues.JobRunner.run(JobRunner.java:205)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
The UberJar does not seem to have the com.adobe.granite.workflow.core.job package. Is there any way to resolve this issue?
The .execute method for the process step ActivatemyAppPageProcess:
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
Session participantSession = null;
Session replicationSession = null;
// ResourceResolver resourceResolver = null;
try {
log.info("Inside ActivatemyAppPageProcess ");
Session session = workflowSession.getSession();
if (replicateAsParticipant(args)) {
String approverId = resolveParticipantId(workItem, workflowSession);
if (approverId != null) {
participantSession = getParticipantSession(approverId, workflowSession);
}
}
if (participantSession != null)
replicationSession = participantSession;
else {
replicationSession = session;
}
WorkflowData data = workItem.getWorkflowData();
String path = null;
String type = data.getPayloadType();
if ((type.equals("JCR_PATH")) && (data.getPayload() != null)) {
String payloadData = (String) data.getPayload();
if (session.itemExists(payloadData))
path = payloadData;
}
else if ((data.getPayload() != null) && (type.equals("JCR_UUID"))) {
Node node = session.getNodeByUUID((String) data.getPayload());
path = node.getPath();
}
ReplicationOptions opts = null;
String rev = (String) data.getMetaDataMap().get("resourceVersion", String.class);
if (rev != null) {
opts = new ReplicationOptions();
opts.setRevision(rev);
}
opts = prepareOptions(opts);
if (path != null) {
ResourceCollection rcCollection =
ResourceCollectionUtil
.getResourceCollection(
(Node) this.admin.getItem(path),
(ResourceCollectionManager) this.rcManager);
boolean isWFPackage = isWorkflowPackage(path, resolverFactory, workflowSession);
List<String> paths = getPaths(path, rcCollection);
for (String aPath : paths)
if (canReplicate(replicationSession, aPath)) {
if (opts != null) {
if (isWFPackage) {
setRevisionForPage(aPath, opts, data);
}
this.replicator
.replicate(replicationSession,
getReplicationType(),
aPath,
opts);
} else {
this.replicator
.replicate(replicationSession,
getReplicationType(),
aPath);
}
} else {
log.debug(session.getUserID() + " is not allowed to replicate " + "this page/asset " + aPath + ". Issuing request for 'replication");
Dictionary properties = new Hashtable();
properties.put("path", aPath);
properties.put("replicationType", getReplicationType());
properties.put("userId", session.getUserID());
Event event = new Event("com/day/cq/wcm/workflow/req/for/activation", properties);
this.eventAdmin.sendEvent(event);
}
} else {
log.warn("Cannot activate page or asset because path is null for this workitem: " + workItem.toString());
}
} catch (RepositoryException e) {
throw new WorkflowException(e);
} catch (ReplicationException e) {
throw new WorkflowException(e);
} finally {
if ((participantSession != null) && (participantSession.isLive())) {
participantSession.logout();
participantSession = null;
}
}
}
com.adobe.granite.workflow.core.job is not exported in AEM at all. That means, you cannot use it because it is invisible to your code.
The com.adobe.granite.workflow.core bundle does only export com.adobe.granite.workflow.core.event.
If you work with the AEM workflows, you should stick to the com.adobe.granite.workflow.api bundle.
The following packages are exported in this bundle and therefore useable:
com.adobe.granite.workflow,version=1.0.0
com.adobe.granite.workflow.collection,version=1.1.0
com.adobe.granite.workflow.collection.util,version=1.0.0
com.adobe.granite.workflow.event,version=1.0.0
com.adobe.granite.workflow.exec,version=1.0.0
com.adobe.granite.workflow.exec.filter,version=1.0.0
com.adobe.granite.workflow.job,version=1.0.0
com.adobe.granite.workflow.launcher,version=1.0.0
com.adobe.granite.workflow.metadata,version=1.0.0
com.adobe.granite.workflow.model,version=1.0.0
com.adobe.granite.workflow.rule,version=1.0.0
com.adobe.granite.workflow.serialization,version=1.0.0
com.adobe.granite.workflow.status,version=1.0.0
Even if the uber.jar has the packages , if you look on your AEM instance on /system/console/bundles and click on the com.adobe.granite.workflow.core package, you will see that in "exported packages" there is no com.adobe.granite.workflow.core.job available. So even if your IDE, Maven and/or Jenkins can handle it, AEM will not be able to execute your code.
In AEM you can only use packages that are exported in one of the available bundles or that are included in your bundle - what would be a bad idea. You would then have two versions of the same code and that will lead to further problems.
Having seen the code I would say there's another problem here. And solving that one will help you get rid off the other one, too.
You try to start another WF (request for activation) for a path that is already used in a workflow.
You have to terminate the current workflow instance to be able to do this.
An example for a clean way to do this would be:
Workflow workflow = workItem.getWorkflow();
WorkflowData wfData = workflow.getWorkflowData();
workflowSession.terminateWorkflow(workflow);
Map<String, Object> paramMap = new HashMap<String, Object>();
if (!StringUtils.isEmpty(data.getNextParticipantUid())) {
paramMap.put("nextParticipant", "admin");
}
workflowSession.startWorkflow(
workflowSession.getModel(WORKFLOW_MODEL_PATH, wfData, paramMap);
The possible reason for the error could be that your workflow process com.myApp.workflow.ActivatemyAppPageProcess service/component is not active because of which its not bound to JobHandler's list of available processes thus causing this exception.
Can you check in /system/console/components that your custom process component is active? If not then you will have to resolve the dependency which is causing the service/component to be not available.
Related
I need to check current version of Installed Application and Playstore application version. If it is not same app should navigate to Playstore .
im using xam.Plugin.LatestVersion(2.1.0) To get the latestversion number of application from play console. unfortunately not getting latest version number of application from play store. The below code im using.
private async void ChekAppVersion()
{
try
{
latestVersionNumber = await CrossLatestVersion.Current.GetLatestVersionNumber();
installedVersionNumber = CrossLatestVersion.Current.InstalledVersionNumber;
if (installedVersionNumber != latestVersionNumber)
{
await DisplayAlert("New Version", "There is a new version of this app available. Please update now?", "Ok");
await CrossLatestVersion.Current.OpenAppInStore();
ChekAppVersion();
}
else
{
}
}
catch (Exception ex)
{
}
}
Im getting the installedVersionNumber, but im unable to get the latestVersionNumber(Playstore).
Please help on this.
They have removed the version from div, now it's displayed with js, but data is still there inside a <script> tag. My current fixed code is:
private bool _lockCheckUpdates;
public async Task<bool> CheckNeedUpdate()
{
if (Connectivity.NetworkAccess != NetworkAccess.Internet || _lockCheckUpdates)
return false;
_lockCheckUpdates = true;
try
{
HttpClient myClient = CreateClient();
if (Device.RuntimePlatform == Device.Android)
{
var bundle = "com.todo.app"; //ANDROID BUNDLE NAME HERE
string url = $"https://play.google.com/store/apps/details?id={bundle}&hl=en";
string raw = await myClient.GetStringAsync(new Uri(url));
var doc = new HtmlDocument();
doc.LoadHtml(raw);
var scripts = doc.DocumentNode.Descendants()
.Where(n => n.Name == "script" && n.InnerText.Contains("AF_initDataCallback({key: 'ds:4'"))
.ToArray();
var script = scripts.First().InnerText;
var engine = new Jurassic.ScriptEngine();
var eval = "(function() { var AF_initDataCallback = function(p) { return p.data[1][2][140][0][0][0]; }; return " + script + " })()";
var result = engine.Evaluate(eval);
//var json = JSONObject.Stringify(engine, result); //for debug, check in browser console with JSON.parse(json)
var remote = $"{result}".ToDouble();
var local = App.Version.ToDouble();
return local < remote;
}
else if (Device.RuntimePlatform == Device.iOS)
{
var bundle = "com.todo.app";//iOS BUNDLE NAME HERE
string url = $"http://itunes.apple.com/lookup?bundleId={bundle}";
string raw = await myClient.GetStringAsync(new Uri(url));
var dto = JsonConvert.DeserializeObject<AppStoreRecord>(raw);
double local = App.Version.ToDouble();
if (dto.ResultCount > 0)
{
double remote = dto.Results[0].Version.ToDouble();
return remote > local;
}
}
}
catch (Exception e)
{
Logger.Error("CheckNeedUpdate", e);
}
finally
{
_lockCheckUpdates = false;
}
return false;
}
Using nugets
Jurassic to evaluate the script on page,
HtmlAgilityPack to parse html,
Xamarin.Essentials to check if we are online,
and AppoMobi.Specials for .ToDouble() etc
I hope this could also be useful to fix https://github.com/edsnider/latestversionplugin/issues/43 :)
The plugin you are using no longer works for Android https://github.com/edsnider/latestversionplugin/issues/43
You will need to find a new way to get the desired information.
PR has been made on this plugin... it works again ;-)
I am trying to write a gradle code to save file versions to a meta property file. then if version updated, download new version and update the property file to avoid download again if version not updated.
Below code basic function works but two minor issues:
every time run ./gradle demo command, the first line in versions.txt will update a timestamp, I would like to disable it but not sure how.
Sometimes the item no version change will move location (e.g move from line 10 to line 15). That means the sequence of items in property file not stable. I would like only the version changed item get updated each time.
import groovy.json.JsonBuilder
apply plugin: 'java'
public String getDownloadedVersion(verFile,key) {
String value = null;
Properties prop = new Properties();
FileInputStream is = new FileInputStream(verFile);
prop.load(is);
value = prop.getProperty(key);
is.close();
return value
}
public void writeDownloadedVersion(verFile,key,value) {
Properties verProp = new Properties();
FileInputStream verInputStream;
FileOutputStream verOutputStream;
try {
if( verFile.exists() ) {
verInputStream = new FileInputStream(verFile)
verProp.load(verInputStream);
verInputStream.close();
}
verOutputStream = new FileOutputStream(verFile);
verProp.setProperty(key, value);
verProp.store(verOutputStream, null);
verOutputStream.close();
} catch(IOException e) {
System.out.println("exception " + e)
e.printStackTrace();
}
}
public boolean version_changed(verFile,file,version) {
def localVersion = getDownloadedVersion(verFile,file)
def found = false
if (localVersion != version) {
found = true
}
return found
}
tasks.register('demo') {
def fileLst = [
["abc","3.0"],
["def","4.0"],
["ghi","5.0"],
["jkl","2.0"],
["mno","1.0"],
["pqr","2.0"],
["stu","5.0"],
["vwx","2.0"],
]
doLast {
def verFile = new File(".", "versions.txt");
fileLst.each {file, version ->
if (version_changed(verFile,file,version)) {
System.out.println(file + " " + version)
//download version
writeDownloadedVersion(verFile,file,version)
}
}
}
}
Sample version.txt file:
#Thu Apr 28 16:40:02 CDT 2022
jkl=2.0
mno=1.0
pqr=2.0
abc=3.0
stu=5.0
def=4.0
vwx=2.0
ghi=5.0
If any other better solution, please help comment!
I am trying to get all the entries in a paginated bundle.
The working code is as follow:
Bundle bundle = fhirClient.search()
.forResource(...)
.where(...)
.returnBundle(Bundle.class)
.execute();
if (bundle == null){
return null;
}
// Keep adding entries until the last page
Bundle tempBundle = fhirClient.loadPage().next(bundle).execute();
// Put all the new entries into a separated list so that we do not modify the iterator
List<Bundle.Entry> entries = new ArrayList<>();
while(tempBundle != null){
entries.addAll(tempBundle.getEntry());
if(tempBundle.getLink(Bundle.LINK_NEXT) != null) {
tempBundle = fhirClient.loadPage().next(tempBundle).execute();
}
else{
tempBundle = null;
}
}
entries.forEach(bundle::addEntry);
return bundle;
However, I was doing something like this in the while loop and it would end up in infinite loop:
while(tempBundle != null){
entries.addAll(tempBundle.getEntry());
tempBundle = fhirClient.loadPage().next(tempBundle).execute();
}
I was expecting the tempBundle would end up with null for a bundle without the next page, but it would never happen. Any idea?
You might want to take a look at this Example:
BundleFetcher.java
Especially the part where you populate the results with the following pages:
while (bundle.getLink(IBaseBundle.LINK_NEXT) != null) {
bundle = client
.loadPage()
.next(bundle)
.execute();
patients.addAll(BundleUtil.toListOfResources(ctx, bundle));
}
I think the offending part in your code is
// Keep adding entries until the last page
Bundle tempBundle = fhirClient.loadPage().next(bundle).execute();
We have a plugin that uses the BookRequest & RescheduleRequest Methods to schedule Appointment & RecurringAppointmentMaster entities.
Recently I was tasked with implementing the ability to schedule multiple appts in a given timeslot.
So in researching this, I found some posts referring to resource capacity (in work hours) & setting the Effort field of the ActivityParty to 1.0 in the Appointment.
I thought, great this will be easy.
So I changed the plugin to store the effort:
activityParty = new Entity("activityparty");
activityParty["partyid"] = new EntityReference("systemuser", apptCaregiverId);
activityParty["effort"] = (Double)1.0;
But when I ran the code, the BookRequest returned this error that confused me: ErrorCode.DifferentEffort
I searched for ErrorCode.DifferentEffort, 2139095040, BookRequest, you name it found nothing useful.
What exactly does this error mean?
Why is it so difficult to schedule concurrent appointments in CRM?
This is what I learned the hard way, so maybe it will spare someone else some frustration.
I looked in the database & noticed that the activityparty entities associated with appointments all had the effort field set to 2139095040 and I wondered where that number was coming from? In a post unrelated to CRM, I found out the 2139095040 means 'positive infinity'.
I revisited the posts where they talk about setting the effort to 1.0 & realized that they were all referring to the ServiceAppointment entity (not Appointment) and then I finally stumbled on the list of error codes
Scheduling Error Codes
DifferentEffort = The required capacity of this service does not match the capacity of resource {resource name}.
Not exactly the truth, but whatever.
The real issue is the Appointment entity does not reference a Service, therefore the capacity of the non-existent service is ‘Positive Infinity’ (2139095040).
Setting the Effort equal to anything but 2139095040 throws this error.
It isn’t really checking the capacity of the resource here, it’s just saying that the non-existent service capacity must be = 2139095040
Anyway to get around this I removed the logic that sets the effort = 1.0 and when BookRequest or RescheduleRequest returns ErrorCode.ResourceBusy, I check the Capacity vs the # appts scheduled in that timeslot & if there is capacity left over, I force it to overbook by using Create or Update.
private Guid BookAppointment(Entity appointment, bool setState, out List<string> errors)
{
Guid apptId = Guid.Empty;
try
{
BookRequest request = new BookRequest
{
Target = appointment
};
BookResponse booked = (BookResponse)this.orgService.Execute(request);
apptId = ParseValidationResult(booked.ValidationResult, setState, appointment, true, out errors);
}
catch (Exception ex)
{
errors = new List<string> { ex.GetBaseException().Message };
}
return apptId;
}
private Guid RescheduleAppointment(Entity appointment, out List<string> errors)
{ // used to reschedule non-recurring appt or appt in recurrence
Guid apptId = Guid.Empty;
try
{
RescheduleRequest request = new RescheduleRequest
{
Target = appointment
};
RescheduleResponse rescheduled = (RescheduleResponse)this.orgService.Execute(request);
apptId = ParseValidationResult(rescheduled.ValidationResult, false, appointment, false, out errors);
}
catch (Exception ex)
{
errors = new List<string> { ex.GetBaseException().Message };
}
return apptId;
}
private Guid ParseValidationResult(ValidationResult result, bool setState, Entity appointment, Boolean addNew, out List<string> errors)
{
Guid apptId = result.ActivityId;
errors = new List<string>();
if (result.ValidationSuccess == true)
{
if (setState == true)
{
SetStateRequest state = new SetStateRequest();
state.State = new OptionSetValue(3); // Scheduled
state.Status = new OptionSetValue(5); // Busy
state.EntityMoniker = new EntityReference("appointment", apptId);
SetStateResponse stateSet = (SetStateResponse)this.orgService.Execute(state);
}
}
else
{
String error;
String errortxt;
Boolean overbookAppt = true;
foreach (var errorInfo in result.TraceInfo.ErrorInfoList)
{
bool unavailable = false;
if (errorInfo.ErrorCode == "ErrorCode.ResourceNonBusinessHours")
{
errortxt = "{0} is being scheduled outside work hours";
}
else if (errorInfo.ErrorCode == "ErrorCode.ResourceBusy")
{
errortxt = "{0} is unavailable at this time";
unavailable = true;
}
else
{
errortxt = "failed to schedule {0}, error code = " + errorInfo.ErrorCode;
}
Dictionary<Guid, String> providers;
Dictionary<Guid, String> resources;
DateTime start = DateTime.Now, end = DateTime.Now;
Guid[] resourceIds = errorInfo.ResourceList.Where(r => r.EntityName == "equipment").Select(r => r.Id).ToList().ToArray();
if (unavailable == true)
{
if (appointment.LogicalName == "recurringappointmentmaster")
{
start = (DateTime)appointment["starttime"];
end = (DateTime)appointment["endtime"];
}
else
{
start = (DateTime)appointment["scheduledstart"];
end = (DateTime)appointment["scheduledend"];
}
Dictionary<Guid, Boolean> availability = GetAvailabilityOfResources(resourceIds, start, end);
resourceIds = availability.Where(a => a.Value == false).Select(t => t.Key).ToArray(); // get ids of all unavailable resources
if (resourceIds.Count() == 0)
{ // all resources still have capacity left at this timeslot - overbook appt timeslot
overbookAppt = true;
} // otherwise at least some resources are booked up in this timeslot - return error
}
if (errortxt.Contains("{0}"))
{ // include resource name in error msg
if (resourceIds.Count() > 0)
{
LoadProviderAndResourceInfo(resourceIds, out providers, out resources);
foreach (var resource in providers)
{
error = String.Format(errortxt, resource.Value);
errors.Add(error);
}
foreach (var resource in resources)
{
error = String.Format(errortxt, resource.Value);
errors.Add(error);
}
}
}
else
{ // no place for name in msg - just store it
errors.Add(errortxt);
break;
}
}
if (overbookAppt == true && errors.Count() == 0)
{ // all resources still have capacity left at this timeslot & no other errors have been returned - create appt anyway
if (addNew)
{
appointment.Attributes.Remove("owner"); // Create message does not like when owner field is specified
apptId = this.orgService.Create(appointment);
if (setState == true)
{
SetStateRequest state = new SetStateRequest();
state.State = new OptionSetValue(3); // Scheduled
state.Status = new OptionSetValue(5); // Busy
state.EntityMoniker = new EntityReference("appointment", apptId);
SetStateResponse stateSet = (SetStateResponse)this.orgService.Execute(state);
}
}
else
{
this.orgService.Update(appointment);
}
}
}
return apptId;
}
private Dictionary<Guid, Boolean> GetAvailabilityOfResources(Guid[] resourceIds, DateTime start, DateTime end)
{
Dictionary<Guid, Boolean> availability = new Dictionary<Guid, Boolean>();
QueryMultipleSchedulesRequest scheduleRequest = new QueryMultipleSchedulesRequest();
scheduleRequest.ResourceIds = resourceIds;
scheduleRequest.Start = start;
scheduleRequest.End = end;
// TimeCode.Unavailable - gets appointments
// TimeCode.Filter - gets resource capacity
scheduleRequest.TimeCodes = new TimeCode[] { TimeCode.Unavailable, TimeCode.Filter };
QueryMultipleSchedulesResponse scheduleResponse = (QueryMultipleSchedulesResponse)this.orgService.Execute(scheduleRequest);
int index = 0;
TimeInfo[][] timeInfo = new TimeInfo[scheduleResponse.TimeInfos.Count()][];
foreach (var schedule in scheduleResponse.TimeInfos)
{
TimeInfo resourceCapacity = schedule.Where(s => s.SubCode == SubCode.ResourceCapacity).FirstOrDefault();
Int32 capacity = (resourceCapacity != null) ? (Int32)resourceCapacity.Effort : 1;
Int32 numAppts = schedule.Where(s => s.SubCode == SubCode.Appointment).Count();
// resource is available if capacity is more than # appts in timeslot
availability.Add(resourceIds[index++], (capacity > numAppts) ? true : false);
}
return availability;
}
This is really a better solution than setting the Effort = 1 anyway because now we don’t need a one-time on-demand workflow to update existing data.
I hope this helps save you some time if you ever need to do this.
I am trying to figure out how to get gradle to fail a build on a version conflict between two dependencies when one of them doesn't have group specified.
For example I have a project that depends on jar from configured flat directory repository (for a vendor)
compile ':guava:r09'
and a transitive dependency that points to module retrieved from maven repository
compile 'com.google.guava:guava:13.0.1'
I understand that by design failOnVersionConflict resolution strategy will not raise a conflict for the above example. I cannot determine group name for jars in flat directory and hence would like to raise a conflict where developer can force one of the module accordingly. Thank you for taking the time to read by question.
Update:
Based on Ben's comment, I am attaching the code snippet used to raise custom conflict. But this is not helpful in my case since I cannot take advantage of force resolution strategy to resolve the conflict. I could exclude transitive dependencies or remove direct dependency altogether. Hopefully it is useful to someone else.
gradle.afterProject {
project.configurations.each { conf ->
def map = new HashMap<String, List<Dependency>>()
//println "\tConfiguration- ${project.name}:${conf.name}"
conf.allDependencies.each { dep ->
//println "\t\t${dep.group}:${dep.name}:${dep.version}"
ArrayList<Dependency> dependencies = null
if(map.containsKey(dep.name))
{
dependencies = map.get(dep.name)
}
else
{
dependencies = new ArrayList<>()
map.put(dep.name, dependencies)
dependencies.add(dep)
}
if(dep.group == null || dep.group.equals("unspecified"))
{
for(Dependency depInMap : dependencies) {
if(depInMap.version == null && dep.version == null)
continue;
if(depInMap.version != null && depInMap.version.equals(dep.version))
continue;
throw new GradleException("Customized Conflict: A conflict was found in " +
"${project.name}:${conf.name} between the following modules:" +
"\n- ${dep.group}:${dep.name}:${dep.version}" +
"\n- ${depInMap.group}:${depInMap.name}:${depInMap.version}")
}
}
dependencies.add(dep);
}
}
}
Here is solution I came up with. Given below is code snippet for some one else who may have use for it. The code isn't neat but is functional. Any suggestions are welcome.
private static boolean isGroupEmpty(DependencyResolveDetails details){
if (details.requested.group == null) {
return true;
} else if (details.requested.group == "unspecified"){
return true;
} else if(details.requested.group.isEmpty()) {
return true;
} else {
return false;
}
}
configurations.all {
def dependencyMap = [:]
def forcedModules = resolutionStrategy.forcedModules
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def targetToUse = null
for (forcedModule in forcedModules) {
if(forcedModule.name == details.requested.name &&
(forcedModule.group == details.requested.group || isGroupEmpty(details))) {
targetToUse = "${forcedModule.group}:${forcedModule.name}:${forcedModule.version}"
}
}
if(targetToUse != null) {
println "Forcing: " + targetToUse
details.useTarget targetToUse
}
else {
if(dependencyMap.containsKey(details.requested.name)) {
DependencyResolveDetails prevDetails = dependencyMap.get(details.requested.name);
boolean groupMatches = false
if(isGroupEmpty(prevDetails) || isGroupEmpty(details) ||
prevDetails.requested.group == details.requested.group){
groupMatches = true
}
if(groupMatches)
{
boolean versionMatches = false
if(prevDetails.requested.version == details.requested.version) {
versionMatches = true
}
if(!versionMatches)
{
//If versions don't match throw an exception.
throw new GradleException("Custom Conflict: A conflict was found in " +
"${project.name} between the following modules:" +
"\n- ${prevDetails.requested.group}:${prevDetails.requested.name}:" +
"${prevDetails.requested.version}" +
"\n- ${details.requested.group}:${details.requested.name}:" +
"${details.requested.version}")
}
else {
//Use either one (in this case I force the one with empty group)
DependencyResolveDetails repl
DependencyResolveDetails pref
if(isGroupEmpty(prevDetails)) {
pref = prevDetails
repl = details
}
else {
pref = details
repl = prevDetails
dependencyMap.put(details.requested.name, details)
}
repl.useTarget "unspecified:${pref.requested.name}:${pref.requested.version}"
println "Replacing module " +
"\n - ${repl.requested.group}:${repl.requested.name}:${repl.requested.version}" +
"\n with " +
"\n - ${pref.requested.group}:${pref.requested.name}:${pref.requested.version} ."
}
}
}
else {
dependencyMap.put(details.requested.name, details)
}
}
}
}