From 7c554acddb9414eb5cb285562adef4a8e94b8510 Mon Sep 17 00:00:00 2001 From: Jerry Flood Date: Tue, 2 Apr 2019 18:52:18 -0400 Subject: Commit 2 for Integrate minizinc optimizer engine Multiple commits required due to commit size limitation. Change-Id: I50c6dffbdd8a1170d151432dad745589b5925eb6 Issue-ID: OPTFRA-436 Signed-off-by: Jerry Flood --- .../availability/timewindows/RecurringWindows.java | 12 + .../clients/optimizer/ElementAvailability.java | 197 +++++++++++++++ .../clients/optimizer/ElementWindowMapping.java | 148 +++++++++++ .../clients/optimizer/OptimizerClient.java | 279 +++++++++++++++++++++ 4 files changed, 636 insertions(+) create mode 100644 cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementAvailability.java create mode 100644 cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementWindowMapping.java create mode 100644 cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerClient.java (limited to 'cmso-optimizer/src/main') diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java index 84fc039..23e3ad8 100644 --- a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/availability/timewindows/RecurringWindows.java @@ -211,5 +211,17 @@ public class RecurringWindows { return instant.plus(date.toEpochMilli(), ChronoUnit.MILLIS); } + public static DateTimeIterator getRecurringListForChangeWindow(ChangeWindow window, Long durationInSeconds) + throws ParseException { + + String rdata = "RRULE:FREQ=MINUTELY;INTERVAL=" + durationInSeconds/60; + DateTime start = new DateTime(window.getStartTime().toInstant().toEpochMilli()); + DateTimeIterator recur = + DateTimeIteratorFactory.createDateTimeIterator(rdata, start, DateTimeZone.UTC, true); + return recur; + } + + + } diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementAvailability.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementAvailability.java new file mode 100644 index 0000000..4766db2 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementAvailability.java @@ -0,0 +1,197 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer; + +import com.google.ical.compat.jodatime.DateTimeIterator; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import org.joda.time.DateTime; +import org.onap.optf.cmso.optimizer.availability.policies.model.TimeLimitAndVerticalTopology; +import org.onap.optf.cmso.optimizer.availability.timewindows.RecurringWindows; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerParameters; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.ActiveTicketsResponse; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.TicketData; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyElementInfo; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; +import org.onap.optf.cmso.optimizer.service.rs.models.ChangeWindow; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; +import org.springframework.expression.spel.ast.OpInc; + +public class ElementAvailability extends ElementWindowMapping{ + + private List policies; + private ActiveTicketsResponse ticketResponse; + + private OptimizerParameters parameters = null; + + private List> globalRelativeAvailability = new ArrayList<>(); + + private Map> nodeUnAvailability = new TreeMap<>(); + + public ElementAvailability(List policies, OptimizerRequest optimizerRequest, + TopologyResponse topologyResponse, ActiveTicketsResponse ticketResponse) throws ParseException + { + super(optimizerRequest, topologyResponse); + this.policies = policies; + this.ticketResponse = ticketResponse; + } + + public void populate(OptimizerParameters parameters) throws ParseException { + this.parameters = parameters; + for (ChangeWindow changeWindow : optimizerRequest.getChangeWindows()) { + if (policies.size() > 0) { + globalRelativeAvailability.add(RecurringWindows.getAvailabilityWindowsForPolicies(policies, changeWindow)); + } + else { + List wholeWindow = new ArrayList<>(); + wholeWindow.add(changeWindow); + globalRelativeAvailability.add(wholeWindow); + } + } + for (String id : nodeInfo.keySet()) { + calculateNodeAvailability(nodeInfo.get(id)); + } + setNoConflicts(); + parameters.setMaxTime(new Long(parameters.getNoConflict().get(0).size())); + parameters.setNumElements(new Long(parameters.getNoConflict().size())); + + // for now we have 1 loader with unlimited capacity + parameters.setNumLoaders(1L); + Long loaderCapacity = parameters.getNumElements(); + List capacity = new ArrayList<>(); + for (Long slot =0L ; slot < parameters.getMaxTime() ; slot++) { + capacity.add(loaderCapacity); + } + parameters.getLoaderCapacity().add(capacity); + + // For now every slot has the same concurrency limit + capacity = new ArrayList<>(); + Long limit = new Long(optimizerRequest.getConcurrencyLimit()); + if (limit > parameters.getNumElements()) { + limit = parameters.getNumElements(); + } + + for (Long slot =0L ; slot < parameters.getMaxTime() ; slot++) { + capacity.add(limit); + } + parameters.setElementSlotCapacity(capacity); + + } + + private void setNoConflicts() throws ParseException { + // Only support 1 change window for now + ChangeWindow window = optimizerRequest.getChangeWindows().get(0); + Long duration = new Long(optimizerRequest.getNormalDuration()); + if (optimizerRequest.getAdditionalDuration() != null) { + duration += optimizerRequest.getAdditionalDuration(); + } + for (String elementId : nodeInfo.keySet()) { + + TopologyElementInfo info = nodeInfo.get(elementId); + Long timeZoneOffset = getTimeZoneOffset(info); + DateTimeIterator recur = getRecurringIterator(); + List element = new ArrayList<>(); + while (recur.hasNext()) { + DateTime next = recur.next(); + if (next.isAfter(window.getEndTime().getTime())) { + break; + } + ChangeWindow slot = new ChangeWindow(); + slot.setStartTime(next.toDate()); + slot.setEndTime(next.plus(duration).toDate()); + if (slotIsAvailable(slot, timeZoneOffset, nodeUnAvailability.get(elementId))) { + element.add(true); + } else { + element.add(false); + } + } + parameters.getNoConflict().add(element); + } + + } + + private boolean slotIsAvailable(ChangeWindow slot, Long timeZoneOffset, List tickets) { + if (isGloballyAvailable(slot, timeZoneOffset) && isNotRestricted(slot, tickets)) { + return true; + } + return false; + } + + private boolean isNotRestricted(ChangeWindow slot, List tickets) { + if (tickets != null) { + for (TicketData ticket : tickets) { + ChangeWindow window = new ChangeWindow(); + window.setStartTime(ticket.getStartTime()); + window.setEndTime(ticket.getEndTime()); + if (slot.overlaps(window)) { + return false; + } + } + } + return true; + } + + private boolean isGloballyAvailable(ChangeWindow slot, Long timeZoneOffset) { + for (ChangeWindow global : globalRelativeAvailability.get(0)) { + if (global.containsInTimeZone(slot, timeZoneOffset)) { + return true; + } + } + return false; + } + + private Long getTimeZoneOffset(TopologyElementInfo info) { + // TODO Auto-generated method stub + return 0L; + } + + private void calculateNodeAvailability(TopologyElementInfo info) { + Set requiredElements = new HashSet<>(); + requiredElements.add(info.getElementId()); + if (info.getRequiredElements() != null) { + requiredElements.addAll(info.getRequiredElements()); + } + if (ticketResponse.getElements() != null) { + List tickets = ticketResponse.getElements(); + for (TicketData data : tickets) { + for (String id : data.getElementIds()) { + if (requiredElements.contains(id)) { + updateNodeAvailability(id, data); + break; + } + } + } + } + } + + private void updateNodeAvailability(String elementId, TicketData data) { + List list = nodeUnAvailability.get(elementId); + if (list == null) { + list = new ArrayList<>(); + nodeUnAvailability.put(elementId, list); + } + list.add(data); + } + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementWindowMapping.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementWindowMapping.java new file mode 100644 index 0000000..42c69a2 --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/ElementWindowMapping.java @@ -0,0 +1,148 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer; + +import com.google.ical.compat.jodatime.DateTimeIterator; +import java.text.ParseException; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; +import org.joda.time.DateTime; +import org.onap.optf.cmso.optimizer.availability.timewindows.RecurringWindows; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.ElementSlot; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerSchedule; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyElementInfo; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; +import org.onap.optf.cmso.optimizer.service.rs.models.ChangeWindow; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerScheduleInfo; +import org.onap.optf.cmso.optimizer.service.rs.models.ScheduledElement; +import org.onap.optf.cmso.optimizer.service.rs.models.ScheduledElement.ScheduleType; +import org.onap.optf.cmso.optimizer.service.rs.models.UnScheduledElement; +import org.onap.optf.cmso.optimizer.service.rs.models.UnScheduledElement.NotScheduledReason; + +// This class ensures that the node indices nodes and the time slots are the +// same when processing the optimizer engine response as when initiating. +public class ElementWindowMapping { + + protected OptimizerRequest optimizerRequest; + protected TopologyResponse topologyResponse; + + protected Map nodeInfo = new TreeMap<>(); + private List nodeArray = null; + + public ElementWindowMapping(OptimizerRequest optimizerRequest, TopologyResponse topologyResponse) + throws ParseException { + this.optimizerRequest = optimizerRequest; + this.topologyResponse = topologyResponse; + initialize(); + + } + + private void initialize() throws ParseException { + List elements = topologyResponse.getElements(); + for (TopologyElementInfo info : elements) { + nodeInfo.put(info.getElementId(), info); + } + } + + protected DateTimeIterator getRecurringIterator() throws ParseException { + // Only support 1 change window for now + ChangeWindow window = optimizerRequest.getChangeWindows().get(0); + Long duration = new Long(optimizerRequest.getNormalDuration()); + if (optimizerRequest.getAdditionalDuration() != null) { + duration += optimizerRequest.getAdditionalDuration(); + } + DateTimeIterator recur = RecurringWindows.getRecurringListForChangeWindow(window, duration); + return recur; + } + + public void initializeForProcessResult() + { + // we need nodeInfo to be an array to speed up the result processing. + // but we need it sorted by elementId as when we created it.... + nodeArray = nodeInfo.values().stream().collect(Collectors.toList()); + nodeInfo.clear(); + + } + public OptimizerScheduleInfo processResult(OptimizerSchedule result) throws ParseException { + // When considering the memory vs performance + // 5 minute duration for a month long change window is 8928 slots + // The assumption is that there were be fewer allocated slots + // than potential slots. + List elements = result.getElementSlotLoader(); + Map> mapSlotToElement = elements.stream(). + collect(Collectors.groupingBy(ElementSlot::getSlot)); + DateTimeIterator iter = getRecurringIterator(); + // TODO - supporting only 1 change window at the moment..... + Long endWindow = optimizerRequest.getChangeWindows().get(0).getEndTime().getTime(); + Integer slotIndex = 1; + while (iter.hasNext()) { + DateTime dateTime = iter.next(); + if (dateTime.isAfter(endWindow)) + break; + List list = mapSlotToElement.get(slotIndex); + if (list != null) { + list.stream().forEach(x -> x.setTime(dateTime.getMillis())); + } + slotIndex++; + } + // + // All assigned ElementSlots now have corresponding UTC time + // + OptimizerScheduleInfo info = new OptimizerScheduleInfo(); + for (ElementSlot slot : elements) + { + updateInfo(slot, info); + } + return info; + } + + private void updateInfo(ElementSlot slot, OptimizerScheduleInfo info) + { + TopologyElementInfo element = nodeArray.get(slot.getElementIndex()-1); + if (slot.getSlot() > 0) + { + ScheduledElement scheduled = new ScheduledElement(); + Integer durationInSeconds = optimizerRequest.getNormalDuration(); + if (optimizerRequest.getAdditionalDuration() != null) { + durationInSeconds += optimizerRequest.getAdditionalDuration(); + } + scheduled.setDurationSeconds(durationInSeconds.longValue()); + scheduled.setElementId(element.getElementId()); + scheduled.setStartTime(new Date(slot.getTime())); + scheduled.setEndTime(new Date(slot.getTime() + (durationInSeconds*1000))); + scheduled.setScheduleType(ScheduleType.INDIVIDUAL); + info.getScheduledElements().add(scheduled); + } + else + { + UnScheduledElement unscheduled = new UnScheduledElement(); + unscheduled.setElementId(element.getElementId()); + unscheduled.setGroupId("unknown"); + unscheduled.getNotScheduledReaons().add(NotScheduledReason.Other); + unscheduled.getNotScheduledMessages().add("Unknown"); + info.getUnScheduledElements().add(unscheduled); + } + } + + +} diff --git a/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerClient.java b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerClient.java new file mode 100644 index 0000000..514097e --- /dev/null +++ b/cmso-optimizer/src/main/java/org/onap/optf/cmso/optimizer/clients/optimizer/OptimizerClient.java @@ -0,0 +1,279 @@ +/* + * ============LICENSE_START============================================== + * Copyright (c) 2019 AT&T Intellectual Property. + * ======================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + * ============LICENSE_END================================================= + * + */ + +package org.onap.optf.cmso.optimizer.clients.optimizer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.apache.commons.io.IOUtils; +import org.onap.observations.Observation; +import org.onap.optf.cmso.common.PropertiesManagement; +import org.onap.optf.cmso.common.exceptions.CmsoException; +import org.onap.optf.cmso.optimizer.availability.policies.PolicyManager; +import org.onap.optf.cmso.optimizer.availability.policies.model.TimeLimitAndVerticalTopology; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerEngineResponse; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerEngineResponse.OptimizerEngineResponseStatus; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerParameters; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerResponseUtility; +import org.onap.optf.cmso.optimizer.clients.optimizer.models.OptimizerResults; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.TicketMgtRequestManager; +import org.onap.optf.cmso.optimizer.clients.ticketmgt.models.ActiveTicketsResponse; +import org.onap.optf.cmso.optimizer.clients.topology.TopologyRequestManager; +import org.onap.optf.cmso.optimizer.clients.topology.models.TopologyResponse; +import org.onap.optf.cmso.optimizer.common.LogMessages; +import org.onap.optf.cmso.optimizer.model.Optimizer; +import org.onap.optf.cmso.optimizer.model.Request; +import org.onap.optf.cmso.optimizer.model.Ticket; +import org.onap.optf.cmso.optimizer.model.Topology; +import org.onap.optf.cmso.optimizer.model.dao.OptimizerDao; +import org.onap.optf.cmso.optimizer.model.dao.RequestDao; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerRequest; +import org.onap.optf.cmso.optimizer.service.rs.models.OptimizerResponse.OptimizeScheduleStatus; +import org.onap.optf.cmso.optimizer.service.rs.models.PolicyInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * The Class OptimizerClient. + */ +@Component +public class OptimizerClient { + private static EELFLogger debug = EELFManager.getInstance().getDebugLogger(); + + @Autowired + Environment env; + + @Autowired + PropertiesManagement pm; + + @Autowired + RequestDao requestDao; + + @Autowired + TopologyRequestManager topologyRequestManager; + + @Autowired + TicketMgtRequestManager ticketMgtRequestManager; + + @Autowired + OptimizerDao optimizerDao; + + @Autowired + PolicyManager policyManager; + + /** + * Make request. + * + * @param request the request + * @param optimizer the Optimizer + * @return the Optimizer response + */ + public OptimizerEngineResponse makeRequest(Request request, Optimizer optimizer) { + Integer maxAttempts = env.getProperty("cmso.optimizer.maxAttempts", Integer.class, 20); + OptimizerEngineResponse apiResponse = new OptimizerEngineResponse(); + if (optimizer.getOptimizeRetries() >= maxAttempts) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage(LogMessages.EXCEEDED_RETRY_LIMIT.format("Optimizer", maxAttempts.toString())); + Observation.report(LogMessages.EXCEEDED_RETRY_LIMIT, "Optimizer", maxAttempts.toString()); + return apiResponse; + } + OptimizerRequest optimizerRequest = null; + TopologyResponse topologyResponse = null; + ActiveTicketsResponse ticketResponse = null; + try { + optimizerRequest = getOptimizerRequest(request); + topologyResponse = getTopologyResponse(request.getUuid()); + ticketResponse = getTicketResponse(request.getUuid()); + OptimizerParameters optimizerParameters = + buildOptimizerParameters(optimizerRequest, topologyResponse, ticketResponse); + apiResponse = initiateOptimizer(optimizerParameters, request); + } catch (Exception e) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage(LogMessages.UNEXPECTED_EXCEPTION.format(e.getMessage())); + Observation.report(LogMessages.UNEXPECTED_EXCEPTION, e, e.getMessage()); + } + return apiResponse; + } + + private OptimizerParameters buildOptimizerParameters(OptimizerRequest optimizerRequest, + TopologyResponse topologyResponse, ActiveTicketsResponse ticketResponse) throws ParseException { + List policies = getPolicies(optimizerRequest); + OptimizerParameters parameters = new OptimizerParameters(); + ElementAvailability elementAvailability = + new ElementAvailability(policies, optimizerRequest, topologyResponse, ticketResponse); + elementAvailability.populate(parameters); + + // Policies for this are undefined... + parameters.setAttributes(getAttributes(policies, optimizerRequest)); + parameters.setAttributesRange(getAttributesRange(policies, optimizerRequest)); + parameters.setAttributeConcurrencyLimit(getAttributeConcrrencyLimit(policies, optimizerRequest)); + parameters.setNumAttributes(new Long(parameters.getAttributesRange().size())); + return parameters; + } + + private List> getAttributeConcrrencyLimit(List policies, + OptimizerRequest optimizerRequest) { + List> list = new ArrayList<>(); + return list; + } + + private List getAttributesRange(List policies, + OptimizerRequest optimizerRequest) { + List list = new ArrayList<>(); + return list; + } + + private List> getAttributes(List policies, + OptimizerRequest optimizerRequest) { + List> list = new ArrayList<>(); + return list; + } + + + private List getPolicies(OptimizerRequest optimizerRequest) { + List list = new ArrayList<>(); + for (PolicyInfo policyInfo : optimizerRequest.getPolicies()) { + TimeLimitAndVerticalTopology policy = + policyManager.getTimeLimitAndVerticalTopologyByName(policyInfo.getPolicyName()); + list.add(policy); + } + return list; + } + + private ActiveTicketsResponse getTicketResponse(UUID uuid) + throws JsonParseException, JsonMappingException, IOException { + Ticket ticketRow = ticketMgtRequestManager.getExistingTickets(uuid); + String ticketString = ticketRow.getTickets(); + ObjectMapper om = new ObjectMapper(); + return om.readValue(ticketString, ActiveTicketsResponse.class); + } + + private TopologyResponse getTopologyResponse(UUID uuid) + throws JsonParseException, JsonMappingException, IOException { + Topology topologyRow = topologyRequestManager.getExistingTopology(uuid); + String topologyString = topologyRow.getTopology(); + ObjectMapper om = new ObjectMapper(); + return om.readValue(topologyString, TopologyResponse.class); + } + + private OptimizerRequest getOptimizerRequest(Request request) + throws JsonParseException, JsonMappingException, IOException { + String requestString = request.getRequest(); + ObjectMapper om = new ObjectMapper(); + return om.readValue(requestString, OptimizerRequest.class); + } + + + private OptimizerEngineResponse initiateOptimizer(OptimizerParameters request, Request requestRow) + throws CmsoException, JsonProcessingException { + + + UUID uuid = requestRow.getUuid(); + OptimizerEngineResponse apiResponse = new OptimizerEngineResponse(); + apiResponse.setRequestId(uuid.toString()); + + String workingFolderString = env.getProperty("cmso.optimizer.engine.working.folder", "data/engine"); + File workingFolder = new File(workingFolderString + File.separator + requestRow.getUuid().toString()); + workingFolder.mkdirs(); + Long timeLimit = env.getProperty("cmso.minizinc.command.timelimit", Long.class); + // TODO calculate time limit + Process p = null; + try { + Path inputFileName = Paths.get(workingFolder.getAbsolutePath(), "input.dzn"); + Path outputFileName = Paths.get(workingFolder.getAbsolutePath(), "results.yaml"); + String dzn = request.toMiniZinc(); + Files.write(inputFileName, dzn.getBytes()); + List command = buildCommand(inputFileName, outputFileName, timeLimit.toString()); + debug.debug("engine command=", command.toString()); + ProcessBuilder pb = new ProcessBuilder(command); + p = pb.start(); + String stdout = IOUtils.toString(p.getInputStream(), "UTF-8"); + String stderr = IOUtils.toString(p.getErrorStream(), "UTF-8"); + debug.debug("stdout=" + stdout); + debug.debug("stderr=" + stderr); + if (p.isAlive()) { + p.wait(); + } + OptimizerResponseUtility responseUtility = new OptimizerResponseUtility(); + OptimizerResults optimizerResults = responseUtility.parseOptimizerResult(outputFileName.toFile()); + apiResponse.setOptimizerResults(optimizerResults); + apiResponse.setStatus(OptimizerEngineResponseStatus.COMPLETED); + + } catch (InterruptedException e) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage( + LogMessages.OPTIMIZER_REQUEST_TIMEOUT.format(uuid.toString(), timeLimit.toString())); + Observation.report(LogMessages.OPTIMIZER_REQUEST_TIMEOUT, uuid.toString(), timeLimit.toString()); + p.destroyForcibly(); + } catch (Exception e) { + apiResponse.setStatus(OptimizerEngineResponseStatus.FAILED); + apiResponse.setErrorMessage(LogMessages.UNEXPECTED_EXCEPTION.format(e.getMessage())); + Observation.report(LogMessages.UNEXPECTED_RESPONSE, e, e.getMessage()); + } finally { + if (workingFolder.exists()) { + workingFolder.delete(); + } + } + return apiResponse; + } + + private List buildCommand(Path inputFileName, Path outputFileName, String timeLimit) { + List command = new ArrayList<>(); + String minizinc = env.getProperty("cmso.minizinc.command.exe", "minizinc"); + String solver = env.getProperty("cmso.minizinc.command.solver", "OSICBC"); + String additional = env.getProperty("cmso.minizinc.command.additional", ""); + String script = env.getProperty("cmso.minizinc.command.mzn", "scripts/minizinc/generic_attributes.mzn"); + + command.add(minizinc); + command.add("--solver"); + command.add(solver); + command.add("--time-limit"); + command.add(timeLimit); + command.add("--time-limit"); + command.add(timeLimit); + command.add("--soln-sep"); + command.add("\"\""); + command.add("--search-complete-msg"); + command.add("\"\""); + for (String add : additional.split(" ")) { + command.add(add); + } + command.add("-o"); + command.add(outputFileName.toString()); + command.add(script); + command.add(inputFileName.toString()); + return command; + } + + +} -- cgit 1.2.3-korg