/* * Copyright (c) 2005-2009, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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. * */ package org.wso2.carbon.registry.extensions.handlers; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.util.AXIOMUtil; import org.wso2.carbon.registry.core.RegistryConstants; import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.ResourceImpl; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.jdbc.handlers.Handler; import org.wso2.carbon.registry.core.jdbc.handlers.RequestContext; import org.wso2.carbon.registry.core.utils.RegistryUtils; import org.wso2.carbon.registry.extensions.utils.CommonUtil; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.SimpleTimeZone; /** * A handler which can manage project metadata resources. */ public class ProjectMediaTypeHandler extends Handler { private String mediaType = "application/vnd.wso2-project+xml"; private String location; public void setMediaType(String mediaType) { this.mediaType = mediaType; } public void setLocation(String location) { this.location = location; } public void put(RequestContext requestContext) throws RegistryException { if (!CommonUtil.isUpdateLockAvailable()) { return; } CommonUtil.acquireUpdateLock(); try { Resource resource = requestContext.getResource(); Object content = resource.getContent(); String payload; if (content instanceof String) { payload = (String) content; } else { payload = RegistryUtils.decodeBytes((byte[]) content); } try { populateProjectProperties(AXIOMUtil.stringToOM(payload), resource); String path = location + RegistryUtils.getResourceName( requestContext.getResourcePath().getPath()); requestContext.getRegistry().put(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH + path, resource); requestContext.setProcessingComplete(true); } catch (ParseException e) { throw new RegistryException("Unable to parse project configuration", e); } catch (XMLStreamException e) { throw new RegistryException("Unable to parse project configuration", e); } } finally { CommonUtil.releaseUpdateLock(); } } public void importResource(RequestContext requestContext) throws RegistryException { if (!CommonUtil.isUpdateLockAvailable()) { return; } CommonUtil.acquireUpdateLock(); try { Resource resource; if (requestContext.getResource() == null) { resource = new ResourceImpl(); resource.setMediaType(mediaType); } else { resource = requestContext.getResource(); } String sourceURL = requestContext.getSourceURL(); InputStream inputStream; try { if (sourceURL != null && sourceURL.toLowerCase().startsWith("file:")) { String msg = "The source URL must not be file in the server's local file system"; throw new RegistryException(msg); } inputStream = new URL(sourceURL).openStream(); } catch (IOException e) { throw new RegistryException("The URL " + sourceURL + " is incorrect.", e); } ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int nextChar; try { while ((nextChar = inputStream.read()) != -1) { outputStream.write(nextChar); } outputStream.flush(); } catch (IOException e) { throw new RegistryException("Error while reading project definition", e); } byte[] bytes = outputStream.toByteArray(); resource.setContent(bytes); try { populateProjectProperties(AXIOMUtil.stringToOM(RegistryUtils.decodeBytes(bytes)), resource); } catch (ParseException e) { throw new RegistryException("Unable to parse project configuration", e); } catch (XMLStreamException e) { throw new RegistryException("Unable to parse project configuration", e); } String path = location + RegistryUtils.getResourceName( requestContext.getResourcePath().getPath()); requestContext.getRegistry().put(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH + path, resource); requestContext.setProcessingComplete(true); } finally { CommonUtil.releaseUpdateLock(); } } // In JDK6, you'll need to box float values into Float in order to avoid class cast issues when // using String#format(). Therefore, this exclusion is to get rid of the unwanted warnings. @SuppressWarnings("UnnecessaryBoxing") private void populateProjectProperties(OMElement payload, Resource projectResource) throws ParseException { final String MS_PROJECT_NS = payload.getNamespace().getNamespaceURI(); final SimpleDateFormat PROJECT_TIME_FORMAT = new SimpleDateFormat("'PT'H'H'm'M's'S'"); PROJECT_TIME_FORMAT.setTimeZone(new SimpleTimeZone(0, "UTC")); String startDate = null; String finishDate = null; long total; long remaining; long duration = 0l; float cost = 0.0f; float remainingCost = 0.0f; OMElement startDateElement = payload.getFirstChildWithName(new QName(MS_PROJECT_NS, "StartDate")); if (startDateElement != null) { startDate = startDateElement.getText(); } OMElement finishDateElement = payload.getFirstChildWithName(new QName(MS_PROJECT_NS, "FinishDate")); if (finishDateElement != null) { finishDate = finishDateElement.getText(); } Map<Integer, Float> rates = new LinkedHashMap<Integer, Float>(); OMElement resourcesElement = payload.getFirstChildWithName(new QName(MS_PROJECT_NS, "Resources")); if (resourcesElement != null) { Iterator resourceElements = resourcesElement .getChildrenWithName(new QName(MS_PROJECT_NS, "Resource")); while (resourceElements.hasNext()) { OMElement resourceElement = (OMElement) resourceElements.next(); OMElement idElement = resourceElement.getFirstChildWithName( new QName(MS_PROJECT_NS, "ID")); OMElement standardRateElement = resourceElement.getFirstChildWithName( new QName(MS_PROJECT_NS, "StandardRate")); rates.put(Integer.parseInt(idElement.getText()), Float.parseFloat(standardRateElement.getText())); } } OMElement assignmentsElement = payload.getFirstChildWithName(new QName(MS_PROJECT_NS, "Assignments")); long work = 0; long remainingWork = 0; if (assignmentsElement != null) { Iterator assignmentElements = assignmentsElement .getChildrenWithName(new QName(MS_PROJECT_NS, "Assignment")); while (assignmentElements.hasNext()) { OMElement assignmentElement = (OMElement) assignmentElements.next(); OMElement resourceElement = assignmentElement.getFirstChildWithName( new QName(MS_PROJECT_NS, "ResourceUID")); if (Long.parseLong(resourceElement.getText()) < 0) { // no resource assigned would mean that this item is an aggregation of // assignments. continue; } OMElement workElement = assignmentElement.getFirstChildWithName( new QName(MS_PROJECT_NS, "Work")); long time = PROJECT_TIME_FORMAT.parse(workElement.getText()).getTime(); work += time; cost += (time / 1000f / 60f / 60f) * rates.get( Integer.parseInt(resourceElement.getText())); OMElement remainingWorkElement = assignmentElement.getFirstChildWithName( new QName(MS_PROJECT_NS, "RemainingWork")); time = PROJECT_TIME_FORMAT.parse(remainingWorkElement.getText()).getTime(); remainingWork += time; remainingCost += (time / 1000f / 60f / 60f) * rates.get( Integer.parseInt(resourceElement.getText())); } } total = (work / 1000 / 60 / 60); remaining = (remainingWork / 1000 / 60 / 60); OMElement tasksElement = payload.getFirstChildWithName(new QName(MS_PROJECT_NS, "Tasks")); if (tasksElement != null) { Iterator taskElements = tasksElement .getChildrenWithName(new QName(MS_PROJECT_NS, "Task")); while (taskElements.hasNext()) { OMElement taskElement = (OMElement) taskElements.next(); OMElement typeElement = taskElement.getFirstChildWithName( new QName(MS_PROJECT_NS, "Type")); if (Integer.parseInt(typeElement.getText()) < 0) { // no resource assigned would mean that this item is an aggregation of // assignments. continue; } OMElement durationElement = taskElement.getFirstChildWithName( new QName(MS_PROJECT_NS, "Duration")); duration += PROJECT_TIME_FORMAT.parse( durationElement.getText()).getTime() / 1000 / 60 / 60 / 8; } } if (startDate != null) { projectResource.setProperty("Start Date", startDate); } if (finishDate != null) { projectResource.setProperty("Finish Date", finishDate); } if (duration > 0) { projectResource.setProperty("Duration", duration + " days"); } if (total > 0) { projectResource.setProperty("Scheduled Work", total + " hours"); } if (remaining > 0) { projectResource.setProperty("Remaining Work", remaining + " hours"); } if ((total - remaining) > 0) { projectResource.setProperty("Actual Work", (total - remaining) + " hours"); } if (cost > 0) { projectResource.setProperty("Scheduled Cost", "$" + String.format("%.2f", new Float(cost))); } if (remainingCost > 0) { projectResource.setProperty("Remaining Cost", "$" + String.format("%.2f", new Float(remainingCost))); } if ((cost - remainingCost) > 0) { projectResource.setProperty("Actual Cost", "$" + String.format("%.2f", new Float((cost - remainingCost)))); } } }