com.evolveum.midpoint.init.InitialDataImport.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.init.InitialDataImport.java

Source

/*
 * Copyright (c) 2010-2013 Evolveum
 *
 * 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.
 */

package com.evolveum.midpoint.init;

import com.evolveum.midpoint.common.configuration.api.MidpointConfiguration;
import com.evolveum.midpoint.model.api.ModelExecuteOptions;
import com.evolveum.midpoint.model.api.ModelService;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ReportTypeUtil;
import com.evolveum.midpoint.security.api.Authorization;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.util.WebMiscUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ReportType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;

/**
 * @author lazyman
 */
public class InitialDataImport {

    private static final Trace LOGGER = TraceManager.getTrace(InitialDataImport.class);

    private static final String DOT_CLASS = InitialDataImport.class.getName() + ".";
    private static final String OPERATION_INITIAL_OBJECTS_IMPORT = DOT_CLASS + "initialObjectsImport";
    private static final String OPERATION_IMPORT_OBJECT = DOT_CLASS + "importObject";

    @Autowired
    private transient PrismContext prismContext;
    private ModelService model;
    private TaskManager taskManager;
    @Autowired
    private MidpointConfiguration configuration;

    public void setModel(ModelService model) {
        Validate.notNull(model, "Model service must not be null.");
        this.model = model;
    }

    public void setTaskManager(TaskManager taskManager) {
        Validate.notNull(taskManager, "Task manager must not be null.");
        this.taskManager = taskManager;
    }

    public void init() throws SchemaException {
        LOGGER.info("Starting initial object import (if necessary).");

        OperationResult mainResult = new OperationResult(OPERATION_INITIAL_OBJECTS_IMPORT);
        Task task = taskManager.createTaskInstance(OPERATION_INITIAL_OBJECTS_IMPORT);
        task.setChannel(SchemaConstants.CHANNEL_GUI_INIT_URI);

        int count = 0;
        int errors = 0;

        File[] files = getInitialImportObjects();
        LOGGER.debug("Files to be imported: {}.", Arrays.toString(files));

        // We need to provide a fake Spring security context here.
        // We have to fake it because we do not have anything in the repository yet. And to get
        // something to the repository we need a context. Chicken and egg. So we fake the egg.
        SecurityContext securityContext = SecurityContextHolder.getContext();
        UserType userAdministrator = new UserType();
        prismContext.adopt(userAdministrator);
        userAdministrator.setName(new PolyStringType(new PolyString("initAdmin", "initAdmin")));
        MidPointPrincipal principal = new MidPointPrincipal(userAdministrator);
        AuthorizationType superAutzType = new AuthorizationType();
        prismContext.adopt(superAutzType, RoleType.class, new ItemPath(RoleType.F_AUTHORIZATION));
        superAutzType.getAction().add(AuthorizationConstants.AUTZ_ALL_URL);
        Authorization superAutz = new Authorization(superAutzType);
        Collection<Authorization> authorities = principal.getAuthorities();
        authorities.add(superAutz);
        Authentication authentication = new PreAuthenticatedAuthenticationToken(principal, null);
        securityContext.setAuthentication(authentication);

        for (File file : files) {
            try {
                LOGGER.debug("Considering initial import of file {}.", file.getName());
                PrismObject object = prismContext.parseObject(file);
                if (ReportType.class.equals(object.getCompileTimeClass())) {
                    ReportTypeUtil.applyDefinition(object, prismContext);
                }

                Boolean importObject = importObject(object, file, task, mainResult);
                if (importObject == null) {
                    continue;
                }
                if (importObject) {
                    count++;
                } else {
                    errors++;
                }
            } catch (Exception ex) {
                LoggingUtils.logException(LOGGER, "Couldn't import file {}", ex, file.getName());
                mainResult.recordFatalError("Couldn't import file '" + file.getName() + "'", ex);
            }
        }

        securityContext.setAuthentication(null);

        mainResult.recomputeStatus("Couldn't import objects.");

        LOGGER.info("Initial object import finished ({} objects imported, {} errors)", count, errors);
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Initialization status:\n" + mainResult.debugDump());
        }
    }

    /**
     * @param object
     * @param task
     * @param mainResult
     * @return null if nothing was imported, true if it was success, otherwise false
     */
    private Boolean importObject(PrismObject object, File file, Task task, OperationResult mainResult) {
        OperationResult result = mainResult.createSubresult(OPERATION_IMPORT_OBJECT);

        boolean importObject = true;
        try {
            model.getObject(object.getCompileTimeClass(), object.getOid(),
                    SelectorOptions.createCollection(GetOperationOptions.createAllowNotFound()), task, result);
            importObject = false;
            result.recordSuccess();
        } catch (ObjectNotFoundException ex) {
            importObject = true;
        } catch (Exception ex) {
            if (!importObject) {
                LoggingUtils.logException(LOGGER, "Couldn't get object with oid {} from model", ex,
                        object.getOid());
                result.recordWarning("Couldn't get object with oid '" + object.getOid() + "' from model", ex);
            }
        }

        if (!importObject) {
            return null;
        }

        ObjectDelta delta = ObjectDelta.createAddDelta(object);
        try {
            LOGGER.info("Starting initial import of file {}.", file.getName());
            model.executeChanges(WebMiscUtil.createDeltaCollection(delta), ModelExecuteOptions.createIsImport(),
                    task, result);
            result.recordSuccess();
            LOGGER.info("Created {} as part of initial import", object);
            return true;
        } catch (Exception e) {
            LoggingUtils.logException(LOGGER, "Couldn't import {} from file {}: ", e, object, file.getName(),
                    e.getMessage());
            result.recordFatalError(e);

            LOGGER.info("\n" + result.debugDump());
            return false;
        }
    }

    private File getResource(String name) {
        URI path;
        try {
            LOGGER.trace("getResource: name = {}", name);
            path = InitialDataImport.class.getClassLoader().getResource(name).toURI();
            LOGGER.trace("getResource: path = {}", path);
            //String updatedPath = path.toString().replace("zip:/", "jar:/");
            //LOGGER.trace("getResource: path updated = {}", updatedPath);
            //path = new URI(updatedPath);
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("parameter name = " + name, e);
        }
        return new File(path);
    }

    private File[] getInitialImportObjects() {
        URL path = InitialDataImport.class.getClassLoader().getResource("initial-objects");
        String resourceType = path.getProtocol();

        File[] files = null;
        File folder = null;

        if ("zip".equals(resourceType) || "jar".equals(resourceType)) {
            try {
                File tmpDir = new File(configuration.getMidpointHome() + "/tmp");
                if (!tmpDir.mkdir()) {
                    LOGGER.warn(
                            "Failed to create temporary directory for inital objects {}. Maybe it already exists",
                            configuration.getMidpointHome() + "/tmp");
                }

                tmpDir = new File(configuration.getMidpointHome() + "/tmp/initial-objects");
                if (!tmpDir.mkdir()) {
                    LOGGER.warn(
                            "Failed to create temporary directory for inital objects {}. Maybe it already exists",
                            configuration.getMidpointHome() + "/tmp/initial-objects");
                }

                //prerequisite: we are expecting that the files are store in the same archive as the source code that is loading it
                URI src = InitialDataImport.class.getProtectionDomain().getCodeSource().getLocation().toURI();
                LOGGER.trace("InitialDataImport code location: {}", src);
                Map<String, String> env = new HashMap<>();
                env.put("create", "false");
                URI normalizedSrc = new URI(src.toString().replaceFirst("file:", "jar:file:"));
                LOGGER.trace("InitialDataImport normalized code location: {}", normalizedSrc);
                try (FileSystem zipfs = FileSystems.newFileSystem(normalizedSrc, env)) {
                    Path pathInZipfile = zipfs.getPath("/initial-objects");
                    //TODO: use some well defined directory, e.g. midPoint home
                    final Path destDir = Paths.get(configuration.getMidpointHome() + "/tmp");
                    Files.walkFileTree(pathInZipfile, new SimpleFileVisitor<Path>() {
                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            final Path destFile = Paths.get(destDir.toString(), file.toString());
                            LOGGER.trace("Extracting file {} to {}", file, destFile);
                            Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
                            return FileVisitResult.CONTINUE;
                        }

                        @Override
                        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                                throws IOException {
                            final Path dirToCreate = Paths.get(destDir.toString(), dir.toString());
                            if (Files.notExists(dirToCreate)) {
                                LOGGER.trace("Creating directory {}", dirToCreate);
                                Files.createDirectory(dirToCreate);
                            }
                            return FileVisitResult.CONTINUE;
                        }
                    });

                }
                folder = new File(configuration.getMidpointHome() + "/tmp/initial-objects");
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Failed to copy initial objects file out of the archive to the temporary directory", ex);
            } catch (URISyntaxException ex) {
                throw new RuntimeException("Failed get URI for the source code bundled with initial objects", ex);
            }
        }

        if ("file".equals(resourceType)) {
            folder = getResource("initial-objects");
        }

        files = folder.listFiles(new FileFilter() {

            @Override
            public boolean accept(File pathname) {
                if (pathname.isDirectory()) {
                    return false;
                }

                return true;
            }
        });
        Arrays.sort(files, new Comparator<File>() {

            @Override
            public int compare(File o1, File o2) {
                int n1 = getNumberFromName(o1);
                int n2 = getNumberFromName(o2);

                return n1 - n2;
            }
        });

        return files;
    }

    private int getNumberFromName(File file) {
        String name = file.getName();
        String number = StringUtils.left(name, 3);
        if (number.matches("[\\d]+")) {
            return Integer.parseInt(number);
        }
        return 0;
    }
}