biz.ganttproject.impex.msproject2.CustomPropertyMapping.java Source code

Java tutorial

Introduction

Here is the source code for biz.ganttproject.impex.msproject2.CustomPropertyMapping.java

Source

/*
Copyright 2017 Dmitry Barashev, BarD Software s.r.o
    
This file is part of GanttProject, an opensource project management tool.
    
GanttProject is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    
GanttProject is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with GanttProject.  If not, see <http://www.gnu.org/licenses/>.
*/
package biz.ganttproject.impex.msproject2;

import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.sf.mpxj.FieldType;
import net.sf.mpxj.MPXJException;
import net.sf.mpxj.ResourceField;
import net.sf.mpxj.TaskField;
import net.sourceforge.ganttproject.CustomPropertyDefinition;
import net.sourceforge.ganttproject.CustomPropertyManager;
import net.sourceforge.ganttproject.resource.HumanResourceManager;
import net.sourceforge.ganttproject.task.TaskManager;

import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;

/**
 * @author dbarashev@bardsoftware.com
 */
class CustomPropertyMapping {
    static final String MSPROJECT_TYPE = "MSPROJECT_TYPE";

    static Map<CustomPropertyDefinition, FieldType> buildMapping(TaskManager taskManager) throws MPXJException {
        final SortedSet<TaskField> taskFields = Sets.newTreeSet(new Comparator<TaskField>() {
            @Override
            public int compare(TaskField o1, TaskField o2) {
                return o1.ordinal() - o2.ordinal();
            }
        });
        taskFields.addAll(Arrays.asList(TaskField.values()));
        return buildMapping(taskManager.getCustomPropertyManager(), taskFields, TaskField.class);
    }

    static Map<CustomPropertyDefinition, FieldType> buildMapping(HumanResourceManager resourceManager)
            throws MPXJException {
        final SortedSet<ResourceField> taskFields = Sets.newTreeSet(new Comparator<ResourceField>() {
            @Override
            public int compare(ResourceField o1, ResourceField o2) {
                return o1.ordinal() - o2.ordinal();
            }
        });
        taskFields.addAll(Arrays.asList(ResourceField.values()));
        return buildMapping(resourceManager.getCustomPropertyManager(), taskFields, ResourceField.class);
    }

    private static <T extends Enum<T>, S extends FieldType> Map<CustomPropertyDefinition, FieldType> buildMapping(
            final CustomPropertyManager customPropertyManager, final SortedSet<S> mpxjFields,
            final Class<T> enumClass) throws MPXJException {

        final Map<CustomPropertyDefinition, FieldType> result = new HashMap<>();
        class Filter {
            private LinkedHashSet<CustomPropertyDefinition> allDefs = Sets
                    .newLinkedHashSet(customPropertyManager.getDefinitions());

            private void run(final Function<CustomPropertyDefinition, String> fxnFieldName) {
                run0(new Function<CustomPropertyDefinition, S>() {
                    @Override
                    public S apply(@Nullable CustomPropertyDefinition def) {
                        String msProjectType = fxnFieldName.apply(def);
                        return (msProjectType == null) ? null : (S) Enum.valueOf(enumClass, msProjectType);
                    }
                });
            }

            private void run0(Function<CustomPropertyDefinition, S> fxnTaskField) {
                for (Iterator<CustomPropertyDefinition> it = allDefs.iterator(); it.hasNext();) {
                    CustomPropertyDefinition def = it.next();
                    try {
                        FieldType tf = fxnTaskField.apply(def);
                        if (tf != null) {
                            result.put(def, tf);
                            mpxjFields.remove(tf);
                            it.remove();
                        }
                    } catch (IllegalArgumentException e) {
                        // That's somewhat okay. We have not found such value in the enum, but it might come from the future
                        // versions of MPXJ, so it is not the reason to fail
                    }
                }
            }
        }
        Filter f = new Filter();
        // First pass: search for saved MSPROJECT_TYPE attributes.
        f.run(new Function<CustomPropertyDefinition, String>() {
            @Override
            public String apply(@Nullable CustomPropertyDefinition def) {
                return def.getAttributes().get(MSPROJECT_TYPE);
            }
        });
        // Second pass: find properties with predefined names
        f.run(new Function<CustomPropertyDefinition, String>() {
            @Override
            public String apply(@Nullable CustomPropertyDefinition def) {
                return def.getName().toUpperCase();
            }
        });
        // Third pass: provide appropriate types for the remaining properties
        f.run0(new Function<CustomPropertyDefinition, S>() {
            @Override
            public S apply(@Nullable CustomPropertyDefinition def) {
                String name;
                switch (def.getPropertyClass()) {
                case BOOLEAN:
                    name = "FLAG";
                    break;
                case INTEGER:
                case DOUBLE:
                    name = "NUMBER";
                    break;
                case TEXT:
                    name = "TEXT";
                    break;
                case DATE:
                    name = "DATE";
                    break;
                default:
                    assert false : "Should not be here";
                    name = "TEXT";
                }
                for (int i = 1; i <= 30; i++) {
                    S tf1 = (S) Enum.valueOf(enumClass, name + String.valueOf(i));
                    if (mpxjFields.contains(tf1)) {
                        return tf1;
                    }
                }
                return null;
            }
        });
        if (!f.allDefs.isEmpty()) {
            List<String> remainingColumns = Lists
                    .newArrayList(Iterables.transform(f.allDefs, new Function<CustomPropertyDefinition, String>() {
                        @Override
                        public String apply(@Nullable CustomPropertyDefinition def) {
                            return def.getName();
                        }
                    }));
            throw new MPXJException(
                    String.format("Some of the custom columns failed to export: %s", remainingColumns));
        }
        return result;
    }
}