/*
The contents of this file are subject to the Common Public Attribution License
Version 1.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.projity.com/license . The License is based on the Mozilla Public
License Version 1.1 but Sections 14 and 15 have been added to cover use of
software over a computer network and provide for limited attribution for the
Original Developer. In addition, Exhibit A has been modified to be consistent
with Exhibit B.
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License. The
Original Code is OpenProj. The Original Developer is the Initial Developer and
is Projity, Inc. All portions of the code written by Projity are Copyright (c)
2006, 2007. All Rights Reserved. Contributors Projity, Inc.
Alternatively, the contents of this file may be used under the terms of the
Projity End-User License Agreeement (the Projity License), in which case the
provisions of the Projity License are applicable instead of those above. If you
wish to allow use of your version of this file only under the terms of the
Projity License and not to allow others to use your version of this file under
the CPAL, indicate your decision by deleting the provisions above and replace
them with the notice and other provisions required by the Projity License. If
you do not delete the provisions above, a recipient may use your version of this
file under either the CPAL or the Projity License.
[NOTE: The text of this license may differ slightly from the text of the notices
in Exhibits A and B of the license at http://www.projity.com/license. You should
use the latest text at http://www.projity.com/license for your modifications.
You may not remove this license text from the source files.]
Attribution Information: Attribution Copyright Notice: Copyright 2006, 2007
Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
an open source solution from Projity. Attribution URL: http://www.projity.com
Graphic Image as provided in the Covered Code as file: openproj_logo.png with
alternatives listed on http://www.projity.com/logo
Display of Attribution Information is required in Larger Works which are defined
in the CPAL as a work which combines Covered Code or portions thereof with code
not governed by the terms of the CPAL. However, in addition to the other notice
obligations, all copies of the Covered Code in Executable and Source Code form
distributed must, as a form of attribution of the original author, include on
each user interface screen the "OpenProj" logo visible to all users. The
OpenProj logo should be located horizontally aligned with the menu bar and left
justified on the top left of the screen adjacent to the File menu. The logo
must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
must direct them back to http://www.projity.com.
*/
package com.projity.exchange;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.Closure;
import com.projectlibre.core.hierarchy.Hierarchy;
import com.projectlibre.core.hierarchy.HierarchyNode;
import com.projectlibre.core.pm.exchange.MspImporter;
import com.projectlibre.core.pm.exchange.ProjectConverter;
import com.projectlibre.core.pm.exchange.converters.openproj.OpenprojAssignmentConverter;
import com.projectlibre.core.pm.exchange.converters.openproj.OpenprojDependencyConverter;
import com.projectlibre.core.pm.exchange.converters.openproj.OpenprojImportState;
import com.projectlibre.core.pm.exchange.converters.openproj.OpenprojProjectConverter;
import com.projectlibre.core.pm.exchange.converters.openproj.OpenprojResourceConverter;
import com.projectlibre.core.pm.exchange.converters.openproj.OpenprojTaskConverter;
import com.projectlibre.pm.calendar.CalendarOptions;
import com.projectlibre.pm.calendar.WorkCalendar;
import com.projectlibre.pm.scheduling.ScheduleFrom;
import com.projectlibre.pm.tasks.SnapshotList;
import com.projectlibre.pm.tasks.Task;
import com.projectlibre.pm.tasks.TaskSnapshot;
import com.projity.configuration.CircularDependencyException;
import com.projity.contrib.util.Log;
import com.projity.contrib.util.LogFactory;
import com.projity.grouping.core.Node;
import com.projity.grouping.core.NodeFactory;
import com.projity.job.Job;
import com.projity.job.JobRunnable;
import com.projity.options.CalendarOption;
import com.projity.pm.assignment.Assignment;
import com.projity.pm.assignment.AssignmentService;
import com.projity.pm.calendar.CalendarService;
import com.projity.pm.calendar.WorkingCalendar;
import com.projity.pm.criticalpath.TaskSchedule;
import com.projity.pm.resource.Resource;
import com.projity.pm.resource.ResourceImpl;
import com.projity.pm.resource.ResourcePool;
import com.projity.pm.task.NormalTask;
import com.projity.pm.task.Project;
import com.projity.server.data.EnterpriseResourceData;
import com.projity.server.data.MSPDISerializer;
import com.projity.server.data.Serializer;
import com.projity.session.Session;
import com.projity.session.SessionFactory;
import com.projity.strings.Messages;
import com.projity.util.Alert;
import com.projity.util.DateTime;
import com.projity.util.Environment;
/**
* This class is based on the project mpxj http://www.tapsterrock.com/mpxj/
* The enumerated types in projity currently correspond exactly to the types in mpx, so there is no need to convert them.
* However, if the projity enumerations change, it will be necessary to map them to mpx types.
*
*/
public class MicrosoftImporter extends ServerFileImporter{
static Log log = LogFactory.getLog(MicrosoftImporter.class);
protected com.projectlibre.pm.tasks.Project plProject= null;
protected OpenprojImportState state=new OpenprojImportState();
List allTasks = null;
ArrayList subprojects;
private Date earliestStart = DateTime.getMaxDate();
protected HashMap taskMap = new HashMap(); // keeps track of mapping mpx tasks to projity tasks
private HashMap resourceMap = new HashMap(); // keeps track of mappy mpx resources to projity resources
List allResources=null;
public static boolean ADD_SUMMARY_TASK = false; //Environment.isAddSummaryTask(); // whether to automatically add an extra project summary task or not //claur
private static final String ABORT = "Job aborted"; //$NON-NLS-1$
private String errorDescription = null;
private Exception lastException = null;
private JobRunnable jobRunnable = null;
protected Context context = new Context();
public MicrosoftImporter() {
System.out.println("-------MicrosoftImporter ctor");
}
@Override
public void importFile() throws Exception {
log.info("BEGIN: MicrosoftImporter.PrepareResources");
parse();
log.info("END: MicrosoftImporter.PrepareResources");
Environment.setImporting(false);
log.info("BEGIN: Finish import");
convertToProjity();
log.info("END: Finish import");
}
@Override
public Project loadProject(InputStream in) throws Exception{
log.info("BEGIN: MicrosoftImporter.PrepareResources");
parse(in, "xml");
log.info("END: MicrosoftImporter.PrepareResources");
Environment.setImporting(false);
log.info("BEGIN: Finish import");
convertToProjity();
log.info("END: Finish import");
return project;
}
@Override
public boolean saveProject(Project project,OutputStream out) throws Exception{
MSPDISerializer serializer = new MSPDISerializer();
return serializer.saveProject(project,out);
}
@Override
public void exportFile() throws Exception {
MSPDISerializer serializer = new MSPDISerializer();
//serializer.setJob(this);
serializer.saveProject(project,fileName);
}
private void setProgress(float p) {
if (jobRunnable == null)
log.info("Progress " + 100 * p + "%");
else
jobRunnable.setProgress(p);
}
public void importProject(Project p) throws Exception {
System.out.println("MicrosoftImporter.importProject()");
this.project = p;
parse();
convertToProjity();
}
public void parse(InputStream in, String extension) throws Exception {
System.out.println("MicrosoftImporter.parse()");
Environment.setImporting(true); // will avoid certain popups
setProgress(0.1f);
MspImporter plImporter=new MspImporter();
plProject=plImporter.importProject(in, extension, new MspImporter.ProgressClosure() {
@Override
public void updateProgress(float progress, String label) {
setProgress(progress*0.1f);
}
});
log.info(plProject.toString());
if (plProject == null) {
String errorText = (errorDescription == null) ? Messages.getString("Message.ImportError") : errorDescription; //$NON-NLS-1$
if (jobRunnable != null) {
jobRunnable.getJob().error(errorText,false);
jobRunnable.getJob().cancel();
}
Environment.setImporting(false); // will avoid certain popups
throw lastException == null ? new Exception("Failed to import file") : lastException; //$NON-NLS-1$
}
setProgress(0.2f);
setProgress(1f);
}
public void parse() throws Exception {
System.out.println("MicrosoftImporter.parse()");
Environment.setImporting(true); // will avoid certain popups
setProgress(0.1f);
MspImporter plImporter=new MspImporter();
plProject=plImporter.importProject(fileName, new MspImporter.ProgressClosure() {
@Override
public void updateProgress(float progress, String label) {
setProgress(progress*0.1f);
}
});
log.info(plProject.toString());
if (plProject == null) {
String errorText = (errorDescription == null) ? Messages.getString("Message.ImportError") : errorDescription; //$NON-NLS-1$
if (jobRunnable != null) {
jobRunnable.getJob().error(errorText,false);
jobRunnable.getJob().cancel();
}
Environment.setImporting(false); // will avoid certain popups
throw lastException == null ? new Exception("Failed to import file") : lastException; //$NON-NLS-1$
}
setProgress(0.2f);
setProgress(1f);
}
/**
* This method imports an entire mpx, mpp or xml file
*
* @param filename
* name of the inputfile
* @throws Exception
* on file read error
*/
public Job getImportFileJob(){
System.out.println("MicrosoftImporter.getImportFileJob()");
subprojects = new ArrayList();
errorDescription = null;
lastException = null;
Session session=SessionFactory.getInstance().getSession(resourceMapping==null);
Job job=new Job(session.getJobQueue(),"importFile",Messages.getString("MicrosoftImporter.Importing"),true); //$NON-NLS-1$ //$NON-NLS-2$
// job.addRunnable(new JobRunnable(Messages.getString("MicrosoftImporter.PrepareResources"),1.0f){ //$NON-NLS-1$
//
// public Object run() throws Exception{
// log.info("BEGIN: MicrosoftImporter.PrepareResources");
// //MicrosoftImporter.this.jobRunnable = this;
// importFile();
// log.info("END: MicrosoftImporter.PrepareResources");
// return null;
// }
// });
job.addRunnable(new JobRunnable(Messages.getString("MicrosoftImporter.PrepareResources"),1.0f){ //$NON-NLS-1$
public Object run() throws Exception{
log.info("BEGIN: MicrosoftImporter.PrepareResources");
MicrosoftImporter.this.jobRunnable = this;
parse();
log.info("END: MicrosoftImporter.PrepareResources");
return null;
}
});
job.addSwingRunnable(new JobRunnable("Import resources",1.0f){ //$NON-NLS-1$
public Object run() throws Exception{
log.info("BEGIN: Import resources");
ResourceMappingForm form=getResourceMapping();
if (form!=null&&form.isLocal()) //if form==null we are in a case were have no server access. popup not needed
if (!job.okCancel(Messages.getString("Message.ServerUnreacheableReadOnlyProject"),true)){ //$NON-NLS-1$
setProgress(1.0f);
errorDescription = ABORT;
Environment.setImporting(false); // will avoid certain popups
throw new Exception(ABORT);
}
// claur - Moved to convertToProjity after import Calendar because base calendar must be imported before resources
// log.info("import resources"); //$NON-NLS-1$
// if(!importResources()){
// setProgress(1.0f);
// errorDescription = ABORT;
// Environment.setImporting(false); // will avoid certain popups
// throw new Exception(ABORT);
// }
setProgress(1f);
log.info("END: Import resources");
return null;
}
});
job.addRunnable(new JobRunnable("Finish import",1.0f){ //$NON-NLS-1$
public Object run() throws Exception{
log.info("BEGIN: Finish import");
Object r=convertToProjity();
log.info("END: Finish import");
return r;
}
});
return job;
}
private Project convertToProjity() throws Exception {
log.info("import options"); //$NON-NLS-1$
importOptions();
setProgress(0.3f);
log.info("import calendars"); //$NON-NLS-1$
importCalendars();
setProgress(0.4f);
log.info("import resources"); //$NON-NLS-1$
//claur - moved here because calendars must be imported first
importLocalResources();
setProgress(0.5f);
log.info("import tasks"); //$NON-NLS-1$
importTasks();
setProgress(0.6f);
log.info("import project fields"); //$NON-NLS-1$
importProjectFields();
setProgress(0.7f);
log.info("import dependencies"); //$NON-NLS-1$
importDependencies();
setProgress(0.8f);
log.info("import assignments"); //$NON-NLS-1$
importAssignments();
setProgress(0.9f);
log.info("about to initialize"); //$NON-NLS-1$
if (project.getName() == null)
project.setName("error - name not set on import"); //$NON-NLS-1$
// CalendarService.getInstance().renameImportedBaseCalendars(project.getName());
try {
project.initialize(false,false); // will run critical path
} catch (RuntimeException e) {
if (e.getMessage()==CircularDependencyException.RUNTIME_EXCEPTION_TEXT) {
Environment.setImporting(false); // will avoid certain popups
Alert.error(e.getMessage());
plProject = null;
project = null;
throw new Exception(e.getMessage());
}
}
//project.setGroupDirty(!Environment.getStandAlone());
if (!Environment.getStandAlone()) project.setAllDirty();
project.setBoundsAfterReadProject();
if (plProject.getPropertyValue("scheduleFrom") == ScheduleFrom.FINISH) {
project.setForward(false);
}
Environment.setImporting(false); // will avoid certain popups
setProgress(1.0f);
plProject=null;// remove reference
// project.setWasImported(true); //claur
return project;
}
protected void importCalendars() throws Exception{
state.setCalendarManager(plProject.getCalendarManager());
for (WorkCalendar plCalendar : plProject.getCalendarManager()) {
WorkingCalendar openprojCalendar=WorkingCalendar.getStandardBasedInstance();
ProjectConverter.getInstance().convert("openproj",ProjectConverter.Type.CALENDAR,false,openprojCalendar,plCalendar,state);
if (CalendarService.findBaseCalendar(openprojCalendar.getName())!= null){
//rename imported calendar if a calendar with the same name exists
openprojCalendar.setName(openprojCalendar.getName() + "[Imported]");
}
CalendarService.getInstance().add(openprojCalendar);
state.mapBaseCalendar(plCalendar,openprojCalendar);
}
}
/**
* This method imports all resources defined in the file into the projity model
*
* @param file
* MPX file
*/
protected void importLocalResources(){
ResourcePool resourcePool = project.getResourcePool();
project.setLocal(true);
resourcePool.setLocal(true);
resourcePool.setMaster(false);
resourcePool.updateOutlineTypes();
ResourceImpl openprojResource;
OpenprojResourceConverter converter=new OpenprojResourceConverter();
for (com.projectlibre.pm.resources.Resource plResource : plProject.getResourcePool().getResources()){
openprojResource = resourcePool.newResourceInstance();
converter.to(openprojResource,plResource,state);
state.mapOpenprojResource(plResource, openprojResource);
// Add to resource hierarchy. MSProject does not actually have a hierarchy
Node openprojResourceNode = NodeFactory.getInstance().createNode(openprojResource); // get a node for this resource
resourcePool.addToDefaultOutline(null,openprojResourceNode);
state.mapOpenprojResourceNode(openprojResource, openprojResourceNode);
}
//insertResourceVoids();
}
protected boolean importResources() throws Exception{
return importResources(resourceMap,new Closure() {
public void execute(Object arg0) {
importLocalResources();
}
});
}
protected boolean importResources(HashMap resourceMap,Closure importLocalResources) throws Exception{
ResourceMappingForm form=getResourceMapping();
if (form==null||form.isLocal()){ //claur
importLocalResources.execute(null);
}else{
if (!form.execute()) return false;
if (form.isLocal()){
importLocalResources.execute(null);
return true;
}
com.projity.pm.resource.Resource projityResource=null;
int projityResourceCount=0;
ResourcePool resourcePool = project.getResourcePool();
project.setTemporaryLocal(true);
Object srcResource;
EnterpriseResourceData data;
Map enterpriseResourceDataMap=new HashMap();
for (Iterator i=form.getResources().iterator();i.hasNext();){
data=(EnterpriseResourceData)i.next();
if (data.isLocal()) {
projityResource=ResourceImpl.getUnassignedInstance();
} else {
// try {
projityResource=Serializer.deserializeResourceAndAddToPool(data,resourcePool,null);
//Handles only flat outlines
Node node=NodeFactory.getInstance().createNode(projityResource);
resourcePool.addToDefaultOutline(null,node,projityResourceCount++,false);
((ResourceImpl)projityResource).getGlobalResource().setResourcePool(resourcePool);
// } catch (Exception e) {}
}
enterpriseResourceDataMap.put(data,projityResource);
}
Iterator ir = form.getImportedResources().iterator();
Iterator sr = form.getSelectedResources().iterator();
while (ir.hasNext()) {
srcResource = ir.next();
data=(EnterpriseResourceData)sr.next();
projityResource=(com.projity.pm.resource.Resource)enterpriseResourceDataMap.get(data);
mapResource((long)projityResource.getUniqueId(),projityResource );
}
resourcePool.setMaster(false);
resourcePool.updateOutlineTypes();
project.setAccessControlPolicy(form.getAccessControlType());
project.resetRoles(form.getAccessControlType()==0);
}
return true;
}
protected void retrieveResourcesForMerge(List existingResources) throws Exception{
}
protected void importOptions() throws Exception{
ProjectConverter converter=ProjectConverter.getInstance();
CalendarOption openprojOptions=CalendarOption.getInstance();
CalendarOptions options=plProject.getCalendarOptions();
converter.convert("openproj", ProjectConverter.Type.OPTIONS, false, openprojOptions, options, state);
}
private void importProjectFields() {
OpenprojProjectConverter openprojConverter=new OpenprojProjectConverter();
openprojConverter.to(project, plProject, state);
}
/**
* This method imports all tasks defined in the file into the projity model
*
*/
private void importTasks() {
final OpenprojTaskConverter converter=new OpenprojTaskConverter();
plProject.getHierarchy().visit(new Hierarchy.Visitor(){ //pre-order visitor, parents must be treated before children
@Override
public void visit(HierarchyNode hierarchyNode) {
com.projectlibre.core.nodes.Node node=hierarchyNode.getNode();
if (!(node instanceof Task)) //ignore assignments present in task hierarchy
return;
Task task=(Task)node;
HierarchyNode parentHierarchyNode=hierarchyNode.getParent();
Task parentTask=null;
if (!parentHierarchyNode.isRoot())
parentTask=(Task)parentHierarchyNode.getNode();
//openproj task conversion
NormalTask openprojTask=project.newNormalTaskInstance(false);
openprojTask.setOwningProject(project);
openprojTask.setProjectId(project.getUniqueId());
converter.to(openprojTask, task, state);
//openproj task node conversion
Node openprojTaskNode=NodeFactory.getInstance().createNode(openprojTask);
//openproj node hierarchy
NormalTask openprojParentTask=parentTask==null? null : state.getOpenprojTask(parentTask);
Node openprojParentTaskNode=openprojParentTask==null? null : state.getOpenprojTaskNode(openprojParentTask);
project.addToDefaultOutline(openprojParentTaskNode,openprojTaskNode);
SnapshotList snapshots=task.getSnapshotList();
for (int snapshotId=0;snapshotId<SnapshotList.BASELINE_COUNT;snapshotId++){
TaskSnapshot s=snapshots.getSnapshot(snapshotId);
if (s!=null && s.getStart()!=null && s.getFinish()!=null){
com.projity.pm.task.TaskSnapshot openprojSnapshot=new com.projity.pm.task.TaskSnapshot();
openprojSnapshot.getHasAssignments(); //init hasAssignments
TaskSchedule schedule=new TaskSchedule();//(TaskSchedule)openprojTask.getCurrentSchedule().clone();
schedule.setStart(s.getStart().getTime());
schedule.setFinish(s.getFinish().getTime());
openprojSnapshot.setCurrentSchedule(schedule);
openprojTask.setSnapshot(snapshotId, openprojSnapshot);
}
}
state.mapOpenprojTask(task, openprojTask);
state.mapOpenprojTaskNode(openprojTask, openprojTaskNode);
}
});
}
/**
* Import dependencies. Must be done after importing tasks
*
* @throws Exception
*/
public void importDependencies() throws Exception {
// mpxj uses default options when importing link leads and lags, even when mpp format
CalendarOption oldOptions = CalendarOption.getInstance();
CalendarOption.setInstance(CalendarOption.getDefaultInstance());
final OpenprojDependencyConverter converter=new OpenprojDependencyConverter();
for (com.projectlibre.pm.tasks.Dependency plDependency : plProject.getDependencies()){
converter.to(plDependency,state);
}
CalendarOption.setInstance(oldOptions);
}
/**
* Import mpx assignments into projity model
*
*/
protected void importAssignments() {
OpenprojAssignmentConverter converter=new OpenprojAssignmentConverter();
for (Task task : plProject.getTasks()){
NormalTask openprojTask=state.getOpenprojTask(task);
for (com.projectlibre.pm.tasks.Assignment assignment : task.getAssignments()){
Assignment openprojAssignment=converter.to(assignment, state);
AssignmentService.getInstance().connect(openprojAssignment, null);
}
SnapshotList snapshots=task.getSnapshotList();
for (int snapshotId=0;snapshotId<SnapshotList.BASELINE_COUNT;snapshotId++){
TaskSnapshot s=snapshots.getSnapshot(snapshotId);
com.projity.pm.task.TaskSnapshot openprojSnapshot=(com.projity.pm.task.TaskSnapshot)openprojTask.getSnapshot(snapshotId);
if (s!=null && openprojSnapshot!=null){
for (com.projectlibre.pm.tasks.Assignment assignment : s.getAssignments()){
Assignment openprojAssignment=converter.to(assignment, state);
openprojSnapshot.addAssignment(openprojAssignment);
}
}
}
}
}
protected double assignmentPercentFactor() {
return 100.0;
}
/**
* Currently not implemented
*/
public Job getExportFileJob(){
Session session=SessionFactory.getInstance().getLocalSession();
Job job=new Job(session.getJobQueue(),"exportFile","Exporting...",true); //$NON-NLS-1$ //$NON-NLS-2$
job.addRunnable(new JobRunnable("Local: export",1.0f){ //$NON-NLS-1$
public Object run() throws Exception{
MSPDISerializer serializer = new MSPDISerializer();
serializer.setJob(this);
serializer.saveProject(project,fileName);
return null;
}
});
//session.schedule(job);
return job;
}
protected void makeValidResourceId(Resource res) {
}
protected void mapResource(Number id, Object value) {
// System.out.println("Mapping res " + id + " " + value);
resourceMap.put(id, value);
}
public HashMap getResourceMap() {
return resourceMap;
}
}