Example usage for java.lang ThreadLocal get

List of usage examples for java.lang ThreadLocal get

Introduction

In this page you can find the example usage for java.lang ThreadLocal get.

Prototype

public T get() 

Source Link

Document

Returns the value in the current thread's copy of this thread-local variable.

Usage

From source file:ch.cyberduck.core.sftp.SFTPQuotaFeature.java

@Override
public Space get() throws BackgroundException {
    final ThreadLocal<Space> quota = new ThreadLocal<Space>() {
        @Override/*  www . ja  v a 2 s. c  o m*/
        protected Space initialValue() {
            return new Space(0L, Long.MAX_VALUE);
        }
    };
    final Path home = new SFTPHomeDirectoryService(session).find();
    new SFTPCommandFeature(session).send(String.format("df -Pk %s | awk '{print $3, $4}'", home.getAbsolute()),
            new DisabledProgressListener(), new TranscriptListener() {
                @Override
                public void log(final Type request, final String output) {
                    switch (request) {
                    case response:
                        final String[] numbers = StringUtils.split(output, ' ');
                        if (numbers.length == 2) {
                            try {
                                quota.set(new Space(Long.valueOf(numbers[0]) * 1000L,
                                        Long.valueOf(numbers[1]) * 1000L));
                            } catch (NumberFormatException e) {
                                log.warn(String.format("Ignore line %s", output));
                            }
                        } else {
                            log.warn(String.format("Ignore line %s", output));
                        }
                    }
                }
            });
    return quota.get();
}

From source file:com.qrmedia.commons.persistence.hibernate.clone.HibernateEntityGraphClonerTest.java

@SuppressWarnings("unchecked")
@Test/*from ww  w .j  a v  a  2s.  co m*/
public void clone_entities() throws IllegalAccessException {
    final StubHibernateEntity entity1 = new StubHibernateEntity();

    String property = "007";
    final StubHibernateEntity relatedEntity = new SimplePropertyEqualStubHibernateEntity(property);
    entity1.setNonSimpleBeanProperty(relatedEntity);

    Set<StubHibernateEntity> nonSimpleCollectionBeanProperty = new HashSet<StubHibernateEntity>();

    // reuse relatedEntity to check if its clone is used in both places
    nonSimpleCollectionBeanProperty.add(relatedEntity);
    entity1.setNonSimpleCollectionBeanProperty(nonSimpleCollectionBeanProperty);

    // the first call to the bean cloner creates a clone, adds a new entity and some commands
    final GraphWiringCommand graphWiringCommand1 = createMock(GraphWiringCommand.class);
    final GraphPostProcessingCommand graphPostProcessingCommand = createMock(GraphPostProcessingCommand.class);
    final StubHibernateEntity clone1 = new StubHibernateEntity();
    entityBeanCloner.visitNode(eq(new EntityPreserveIdFlagPair(entity1, false)), same(entityGraphCloner),
            (IdentityHashMap<Object, Object>) anyObject());
    expectLastCall()
            .andAnswer(new HibernateEntityBeanClonerActions(entity1, clone1, Arrays.asList(relatedEntity),
                    Arrays.asList(graphWiringCommand1), Arrays.asList(graphPostProcessingCommand)));

    // note that entity2 is equal to (but not identical to) relatedEntity!
    final GraphWiringCommand graphWiringCommand2 = createMock(GraphWiringCommand.class);
    final StubHibernateEntity entity2 = new SimplePropertyEqualStubHibernateEntity(property);
    entity2.setNonSimpleBeanProperty(entity1);
    final StubHibernateEntity clone2 = new SimplePropertyEqualStubHibernateEntity(property);
    entityBeanCloner.visitNode(eq(new EntityPreserveIdFlagPair(entity2, false)), same(entityGraphCloner),
            (IdentityHashMap<Object, Object>) anyObject());
    expectLastCall().andAnswer(new HibernateEntityBeanClonerActions(entity2, clone2, null,
            Arrays.asList(graphWiringCommand2), null));

    final StubHibernateEntity relatedEntityClone = new SimplePropertyEqualStubHibernateEntity(property);
    entityBeanCloner.visitNode(eq(new EntityPreserveIdFlagPair(relatedEntity, false)), same(entityGraphCloner),
            (IdentityHashMap<Object, Object>) anyObject());
    expectLastCall().andAnswer(new HibernateEntityBeanClonerActions(relatedEntity, relatedEntityClone));

    // use flags mutable for the mocks to track the order of calls
    final ThreadLocal<Integer> numGraphWiringCommandExecuted = new ThreadLocal<Integer>();
    numGraphWiringCommandExecuted.set(0);

    // the entity graph cloner should call the commands in the order they were added

    graphWiringCommand1.forEntities();
    expectLastCall().andReturn(Arrays.asList(entity1));
    graphWiringCommand1.execute(MapUtils.toMap(new IdentityHashMap<Object, Object>(), entity1, clone1));
    expectLastCall().andAnswer(new NumGraphWiringCommandsExecutedVerifier(numGraphWiringCommandExecuted, 0));

    graphWiringCommand2.forEntities();
    expectLastCall().andReturn(Arrays.asList(relatedEntity));
    graphWiringCommand2
            .execute(MapUtils.toMap(new IdentityHashMap<Object, Object>(), relatedEntity, relatedEntityClone));
    expectLastCall().andAnswer(new NumGraphWiringCommandsExecutedVerifier(numGraphWiringCommandExecuted, 1));

    // this *must* be called after all the wiring commands have been completed
    graphPostProcessingCommand.execute();
    expectLastCall().andAnswer(new IAnswer<Object>() {

        public Object answer() throws Throwable {

            if (!(numGraphWiringCommandExecuted.get() == 2)) {
                fail("Graph post-processing command executed before wiring was complete.");
            }

            return null;
        }

    });

    replay(entityBeanCloner, graphWiringCommand1, graphWiringCommand2, graphPostProcessingCommand);

    Map<StubHibernateEntity, StubHibernateEntity> clones = entityGraphCloner
            .clone(Arrays.asList(entity1, entity2));
    assertEquals(MapUtils.<StubHibernateEntity, StubHibernateEntity>toMap(entity1, clone1, entity2, clone2),
            clones);

    verify(entityBeanCloner, graphWiringCommand1, graphWiringCommand2, graphPostProcessingCommand);

    // check that any internal state maintained during the cloning has been cleaned up
    assertTrue(ReflectionUtils.<List<?>>getValue(entityGraphCloner, "graphWiringCommands").isEmpty());
    assertTrue(ReflectionUtils.<List<?>>getValue(entityGraphCloner, "graphPostProcessingCommands").isEmpty());

    /*
     * The actual wiring of the objects is *not* checked because that is the function
     * of the command objects, *not* the entity graph cloner.
     * As such, this is not within the scope of a unit test.
     */
}

From source file:com.blackducksoftware.integration.hub.jenkins.gradle.GradleBuildWrapper.java

@Override
public Environment setUp(final AbstractBuild build, final Launcher launcher, final BuildListener listener)
        throws IOException, InterruptedException {
    // no failure to report yet
    final HubJenkinsLogger buildLogger = new HubJenkinsLogger(listener);
    buildLogger.setLogLevel(LogLevel.TRACE);
    Gradle gradleBuilder = null;/*from  w  ww .j  a  va  2 s  . c o  m*/
    if (build.getProject() instanceof FreeStyleProject) {
        // Project should always be a FreeStyleProject, thats why we have the isApplicable() method
        final List<Builder> builders = ((FreeStyleProject) build.getProject()).getBuilders();

        if (builders == null || builders.isEmpty()) {
            // User didn't configure the job with a Builder
            buildLogger.error("No Builder found for this job.");
            buildLogger.error("Will not run the Hub Gradle Build wrapper.");
            build.setResult(Result.UNSTABLE);
            return new Environment() {
            }; // Continue with the rest of the Build
        }

        for (final Builder builder : builders) {
            if (builder instanceof Gradle) {
                gradleBuilder = (Gradle) builder;
            }
        }
        if (gradleBuilder == null) {
            // User didn't configure the job with a Gradle Builder
            buildLogger.error("This Wrapper should be run with a Gradle Builder");
            buildLogger.error("Will not run the Hub Gradle Build wrapper.");
            build.setResult(Result.UNSTABLE);
            return new Environment() {
            }; // Continue with the rest of the Build
        }
    } else {
        buildLogger.error("Cannot run the Hub Gradle Build Wrapper for this type of Project.");
        build.setResult(Result.UNSTABLE);
        return new Environment() {
        }; // Continue with the rest of the Build
    }
    if (validateConfiguration(buildLogger)) {
        buildLogger.info("Build Recorder enabled");
        buildLogger.info("Hub Jenkins Plugin version : " + getDescriptor().getPluginVersion());

    } else {
        build.setResult(Result.UNSTABLE);
        return new Environment() {
        }; // Continue with the rest of the Build
    }

    final ThreadLocal<String> originalSwitches = new ThreadLocal<String>();
    final ThreadLocal<String> originalTasks = new ThreadLocal<String>();

    if (gradleBuilder != null) {

        originalSwitches.set(gradleBuilder.getSwitches() + "");
        originalTasks.set(gradleBuilder.getTasks() + "");

        final BDGradleInitScriptWriter writer = new BDGradleInitScriptWriter(build, buildLogger);
        final FilePath workspace = build.getWorkspace();
        FilePath initScript;
        String initScriptPath;
        try {
            if (workspace == null) {
                buildLogger.error("Workspace: null");
            } else {
                initScript = workspace.createTextTempFile("init-blackduck", "gradle",
                        writer.generateInitScript(), false);
                if (initScript != null) {
                    initScriptPath = initScript.getRemote();
                    initScriptPath = initScriptPath.replace('\\', '/');

                    String newSwitches = originalSwitches.get();
                    String newTasks = originalTasks.get();

                    if (!originalSwitches.get().contains("--init-script ")
                            && !originalSwitches.get().contains("init-blackduck")) {
                        newSwitches = newSwitches + " --init-script " + initScriptPath;
                    }
                    if (!originalSwitches.get().contains(" -D" + BDGradleUtil.BUILD_ID_PROPERTY)) {
                        newSwitches = newSwitches + " -D" + BDGradleUtil.BUILD_ID_PROPERTY + "="
                                + build.getId();
                    }
                    if (!originalSwitches.get()
                            .contains(" -D" + BDGradleUtil.INCLUDED_CONFIGURATIONS_PROPERTY)) {
                        String configurations = getUserScopesToInclude();
                        configurations = configurations.replaceAll(" ", "");

                        newSwitches = newSwitches + " -D" + BDGradleUtil.INCLUDED_CONFIGURATIONS_PROPERTY + "="
                                + configurations;
                    }
                    // // Following used to generate the dependency tree
                    // // written to a file
                    // if (!originalSwitches.get().contains(" -D" +
                    // BDGradleUtil.DEPENDENCY_REPORT_OUTPUT)) {
                    // FilePath dependencyTreeFile = new FilePath(workspace, "dependencyTree.txt");
                    // newSwitches = newSwitches + " -D" +
                    // BDGradleUtil.DEPENDENCY_REPORT_OUTPUT + "='" +
                    // dependencyTreeFile.getRemote() + "'";
                    // }

                    if (!originalTasks.get().contains("bdCustomTask")) {
                        newTasks = newTasks + " bdCustomTask";
                    }

                    if (!originalTasks.get().contains("bdDependencyTree")) {
                        newTasks = newTasks + " bdDependencyTree";
                    }
                    setField(gradleBuilder, "switches", newSwitches);
                    setField(gradleBuilder, "tasks", newTasks);
                }
            }
        } catch (final Exception e) {
            listener.getLogger().println("Error occurred while writing Gradle Init Script: " + e.getMessage());
            build.setResult(Result.FAILURE);
        }

    }

    final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
    boolean changed = false;
    try {
        if (GradleBuildWrapper.class.getClassLoader() != originalClassLoader) {
            changed = true;
            Thread.currentThread().setContextClassLoader(GradleBuildWrapper.class.getClassLoader());
        }
        return new Environment() {
            @Override
            public boolean tearDown(final AbstractBuild build, final BuildListener listener)
                    throws IOException, InterruptedException {
                final HubJenkinsLogger buildLogger = new HubJenkinsLogger(listener);
                Gradle gradleBuilder = null;
                try {
                    if (build.getProject() instanceof FreeStyleProject) {
                        // Project should always be a FreeStyleProject, thats why we have the isApplicable() method
                        final List<Builder> builders = ((FreeStyleProject) build.getProject()).getBuilders();

                        for (final Builder builder : builders) {
                            if (builder instanceof Gradle) {
                                gradleBuilder = (Gradle) builder;
                            }
                        }
                    }
                    if (gradleBuilder != null) {
                        String rootBuildScriptDir = gradleBuilder.getRootBuildScriptDir();

                        if (StringUtils.startsWithIgnoreCase(rootBuildScriptDir, "${WORKSPACE}")
                                || StringUtils.startsWithIgnoreCase(rootBuildScriptDir, "$WORKSPACE")) {
                            final EnvVars variables = build.getEnvironment(listener);
                            rootBuildScriptDir = BuildHelper.handleVariableReplacement(variables,
                                    rootBuildScriptDir);
                        }

                        String fileSeparator = null;
                        try {
                            final VirtualChannel channel = build.getBuiltOn().getChannel();
                            if (channel == null) {
                                buildLogger.error("Channel build on: null");
                            } else {
                                fileSeparator = channel.call(new GetSeparator());
                            }
                        } catch (final IOException e) {
                            buildLogger.error(e.toString(), e);
                        } catch (final InterruptedException e) {
                            buildLogger.error(e.toString(), e);
                        }
                        if (StringUtils.isEmpty(fileSeparator)) {
                            fileSeparator = File.separator;
                        }

                        File workspaceFile = null;
                        if (build.getWorkspace() == null) {
                            // might be using custom workspace
                            workspaceFile = new File(build.getProject().getCustomWorkspace());
                        } else {
                            workspaceFile = new File(build.getWorkspace().getRemote());
                        }

                        String workingDirectory = "";
                        try {
                            workingDirectory = build.getBuiltOn().getChannel()
                                    .call(new GetCanonicalPath(workspaceFile));
                        } catch (final IOException e) {
                            buildLogger.error("Problem getting the working directory on this node. Error : "
                                    + e.getMessage(), e);
                        }

                        if (!StringUtils.startsWithIgnoreCase(rootBuildScriptDir, workingDirectory)) {
                            if (workingDirectory.endsWith(fileSeparator)) {
                                rootBuildScriptDir = workingDirectory + rootBuildScriptDir;
                            } else {
                                rootBuildScriptDir = workingDirectory + fileSeparator + rootBuildScriptDir;
                            }
                        }

                        FilePath buildInfo = null;
                        final Node buildOn = build.getBuiltOn();
                        if (buildOn == null) {
                            buildLogger.error("Node build on: null");
                        } else {
                            final VirtualChannel channel = buildOn.getChannel();
                            if (channel == null) {
                                buildLogger.error("Channel build on: null");
                            } else {
                                // buildInfoFile = new FilePath(channel, workspacePath);
                                buildInfo = new FilePath(channel, rootBuildScriptDir);
                                buildInfo = new FilePath(buildInfo, "build");
                                buildInfo = new FilePath(buildInfo, "BlackDuck");
                                buildInfo = new FilePath(buildInfo, BuildInfo.OUTPUT_FILE_NAME);

                            }
                        }

                        if (buildInfo != null) {

                            if (buildInfo.exists()) {
                                return universalTearDown(build, buildLogger, buildInfo, getDescriptor(),
                                        BuilderType.GRADLE);
                            } else {
                                buildLogger.error(
                                        "The " + BuildInfo.OUTPUT_FILE_NAME + " file does not exist at : "
                                                + buildInfo.getRemote() + ", on machine : "
                                                + (buildOn == null ? "null" : buildOn.getDisplayName()));
                                build.setResult(Result.UNSTABLE);
                                return true;
                            }
                        }
                        // }
                    } else {
                        buildLogger.error("[WARNING] no gradle build step found");
                        build.setResult(Result.UNSTABLE);
                        return true;
                    }
                } catch (final BDJenkinsHubPluginException e) {
                    buildLogger.error(e.getMessage(), e);
                    build.setResult(Result.UNSTABLE);
                    return true;
                } catch (final Exception e) {
                    buildLogger.error(e.getMessage(), e);
                    build.setResult(Result.UNSTABLE);
                    return true;
                } finally {
                    if (gradleBuilder != null) {
                        synchronized (this) {
                            try {
                                // restore the original configuration
                                setField(gradleBuilder, "switches", originalSwitches.get());
                                setField(gradleBuilder, "tasks", originalTasks.get());
                            } catch (final Exception e) {
                                buildLogger.error(e.getMessage(), e);
                                build.setResult(Result.UNSTABLE);
                                return true;
                            }
                        }
                    }
                }
                return true;
            }
        };
    } finally {
        if (changed) {
            Thread.currentThread().setContextClassLoader(originalClassLoader);
        }
    }
}

From source file:org.jsweet.transpiler.JSweetTranspiler.java

private Map<String, Object> getExportedVarMap() throws Exception {
    Field f = Thread.currentThread().getContextClassLoader().loadClass("jsweet.util.Globals")
            .getDeclaredField("EXPORTED_VARS");
    f.setAccessible(true);/*from  ww w.  j a v  a  2 s.  c om*/
    @SuppressWarnings("unchecked")
    ThreadLocal<Map<String, Object>> exportedVars = (ThreadLocal<Map<String, Object>>) f.get(null);
    return new HashMap<>(exportedVars.get());
}

From source file:org.exoplatform.social.core.storage.impl.ActivityStreamStorageImpl.java

@Override
public void update(ProcessContext ctx) {
    final ReentrantLock lock = new ReentrantLock();
    ThreadLocal<Set<String>> idLocal = new ThreadLocal<Set<String>>();
    try {/*from w  ww. j  a  v  a  2s . c om*/

        StreamProcessContext streamCtx = ObjectHelper.cast(StreamProcessContext.class, ctx);
        ExoSocialActivity activity = streamCtx.getActivity();
        ActivityEntity activityEntity = _findById(ActivityEntity.class, activity.getId());

        lock.lock(); // block until condition holds

        Collection<ActivityRef> references = activityEntity.getActivityRefs();
        Set<String> ids = new ConcurrentSkipListSet<String>();

        for (ActivityRef ref : references) {
            ids.add(ref.getId());
        }

        idLocal.set(ids);

        Set<String> idList = idLocal.get();
        if (idList.size() > 0) {
            for (String id : idList) {
                ActivityRef old = _findById(ActivityRef.class, id);
                LOG.debug("ActivityRef will be deleted: " + old.toString());
                ActivityRefListEntity refList = old.getDay().getMonth().getYear().getList();
                //
                if (refList.isOnlyUpdate(old, activity.getUpdated().getTime())) {
                    old.setName("" + activity.getUpdated().getTime());
                    old.setLastUpdated(activity.getUpdated().getTime());
                } else {
                    ActivityRef newRef = refList.getOrCreated(activity.getUpdated().getTime());
                    newRef.setLastUpdated(activity.getUpdated().getTime());
                    newRef.setActivityEntity(activityEntity);
                    getSession().remove(old);
                }

            }
        }

        // mentioners
        addMentioner(streamCtx.getMentioners(), activityEntity);
        //turnOffLock to get increase perf
        //turnOnUpdateLock = false;
    } catch (NodeNotFoundException ex) {
        LOG.warn("Probably was updated activity reference by another session");
        LOG.debug(ex.getMessage(), ex);
        //turnOnLock to avoid next exception
    } catch (ChromatticException ex) {
        Throwable throwable = ex.getCause();
        if (throwable instanceof ItemExistsException || throwable instanceof InvalidItemStateException
                || throwable instanceof PathNotFoundException) {
            LOG.warn("Probably was updated activity reference by another session");
            LOG.debug(ex.getMessage(), ex);
            //turnOnLock to avoid next exception
        } else {
            LOG.warn("Probably was updated activity reference by another session", ex);
            LOG.debug(ex.getMessage(), ex);
        }

    } finally {
        getSession().save();
        lock.unlock();
    }
}

From source file:de.tudarmstadt.lt.seg.app.Segmenter.java

private void run_parallel() throws Exception {

    InputStream in = System.in;
    if (!"-".equals(_filename_in))
        in = new FileInputStream(_filename_in);
    Stream<String> liter = new BufferedReader(new InputStreamReader(in, Charset.defaultCharset())).lines();

    ThreadLocal<ISentenceSplitter> sentenceSplitter = ThreadLocal.withInitial(() -> {
        try {//from  ww w.  ja  v  a  2  s . c o m
            return newSentenceSplitter();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    });
    ThreadLocal<ITokenizer> tokenizer = ThreadLocal.withInitial(() -> {
        try {
            return newTokenizer();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    });

    final PrintWriter[] w = new PrintWriter[_parallelism];
    // init writers
    for (int i = 0; i < _parallelism; i++) {
        OutputStream out = System.out;
        if (!"-".equals(_filename_out)) {
            out = new FileOutputStream(String.format("%s_%d", _filename_out, i));
        }
        w[i] = new PrintWriter(new OutputStreamWriter(out, Charset.defaultCharset()));
    }

    BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(_parallelism * 2, true);
    ExecutorService es = new ThreadPoolExecutor(_parallelism, _parallelism, 0L, TimeUnit.MILLISECONDS, queue);

    AtomicLong lc = new AtomicLong(0);
    liter.forEach((line) -> {
        // don't try to submit new threads, wait until the thread queue has some capacity again
        while (queue.remainingCapacity() == 0)
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                /**/}
        es.submit(() -> {
            final long docid = lc.incrementAndGet();
            if (docid % 1000 == 0)
                System.err.format("Processing line %d ('%s')%n", docid, _filename_in);
            final int w_i = (int) (docid % _parallelism);
            split_and_tokenize(new StringReader(line.trim()), String.format("%s:%d", _filename_in, docid),
                    sentenceSplitter.get(), tokenizer.get(), _level_filter, _level_normalize, _merge_types,
                    _merge_tokens, _separator_sentence, _separator_token, _separator_desc, w[w_i]);

        });
    });
    es.shutdown();
    es.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);

    // TODO: the stream parallelism version does not work because it submits too many threads at once
    //      AtomicLong lc = new AtomicLong(0);
    //      ForkJoinPool forkJoinPool = new ForkJoinPool(_parallelism);
    //      forkJoinPool.submit(() -> 
    //         liter.parallel().forEach((line) -> {
    //            final long docid = lc.incrementAndGet();
    //            if(docid % 1000 == 0)
    //               System.err.format("Processing line %d ('%s')%n", docid, _filename_in);
    //   
    //            String l = line.replace("\\t", "\t").replace("\\n", "\n");
    //            split_and_tokenize(
    //                  new StringReader(l),
    //                  String.format("%s:%d", _filename_in, docid),
    //                  sentenceSplitter.get(), 
    //                  tokenizer.get(), 
    //                  _level_filter,
    //                  _level_normalize,
    //                  _merge_types,
    //                  _merge_tokens,
    //                  _separator_sentence,
    //                  _separator_token,
    //                  _separator_desc,
    //                  w);
    //      })).get();

}

From source file:org.exoplatform.social.core.storage.impl.RelationshipStorageImpl.java

private String[] getRelationships(String id) {
    ThreadLocal<String[]> identityIdsLocal = new ThreadLocal<String[]>();

    String[] relationshipIds = new String[0];
    identityIdsLocal.set(relationshipIds);

    try {//ww  w  . j  a va 2  s . c o  m

        IdentityEntity identityEntity = _findById(IdentityEntity.class, id);

        StringBuffer sb = new StringBuffer().append("SELECT * FROM soc:relationshipdefinition WHERE ");
        sb.append(JCRProperties.path.getName()).append(" LIKE '")
                .append(identityEntity.getPath() + StorageUtils.SLASH_STR + StorageUtils.PERCENT_STR)
                .append("'");
        //
        sb.append(" ORDER BY ").append(RelationshipEntity.createdTime.getName()).append(" DESC ");

        synchronized (lock) {

            NodeIterator it = nodes(sb.toString());

            while (it.hasNext()) {
                Node node = (Node) it.next();

                RelationshipEntity currentRelationshipEntity = _findById(RelationshipEntity.class,
                        node.getUUID());

                IdentityEntity gotIdentityEntity;
                if (currentRelationshipEntity.isReceiver()) {
                    gotIdentityEntity = currentRelationshipEntity.getFrom();
                } else {
                    gotIdentityEntity = currentRelationshipEntity.getTo();
                }
                identityIdsLocal
                        .set((String[]) ArrayUtils.add(identityIdsLocal.get(), gotIdentityEntity.getId()));
            }

        }
    } catch (Exception e) {
        throw new RelationshipStorageException(RelationshipStorageException.Type.FAILED_TO_GET_RELATIONSHIP,
                e.getMessage());
    }

    return identityIdsLocal.get();
}

From source file:com.moviejukebox.MovieJukebox.java

private void generateLibrary() throws Throwable {

    /**//  w  w  w .  j ava  2 s.co m
     * ******************************************************************************
     * @author Gabriel Corneanu
     *
     * The tools used for parallel processing are NOT thread safe (some operations are, but not all) therefore all are added to
     * a container which is instantiated one per thread
     *
     * - xmlWriter looks thread safe<br>
     * - htmlWriter was not thread safe<br>
     * - getTransformer is fixed (simple workaround)<br>
     * - MovieImagePlugin : not clear, made thread specific for safety<br>
     * - MediaInfoScanner : not sure, made thread specific
     *
     * Also important: <br>
     * The library itself is not thread safe for modifications (API says so) it could be adjusted with concurrent versions, but
     * it needs many changes it seems that it is safe for subsequent reads (iterators), so leave for now...
     *
     * - DatabasePluginController is also fixed to be thread safe (plugins map for each thread)
     *
     */
    class ToolSet {

        private final MovieImagePlugin imagePlugin = MovieJukebox
                .getImagePlugin(getProperty("mjb.image.plugin", "com.moviejukebox.plugin.DefaultImagePlugin"));
        private final MovieImagePlugin backgroundPlugin = MovieJukebox.getBackgroundPlugin(
                getProperty("mjb.background.plugin", "com.moviejukebox.plugin.DefaultBackgroundPlugin"));
        private final MediaInfoScanner miScanner = new MediaInfoScanner();
        private final OpenSubtitlesPlugin subtitlePlugin = new OpenSubtitlesPlugin();
        private final TrailerScanner trailerScanner = new TrailerScanner();
        // FANART.TV TV Artwork Scanners
        private final ArtworkScanner clearArtScanner = new FanartTvScanner(ArtworkType.CLEARART);
        private final ArtworkScanner clearLogoScanner = new FanartTvScanner(ArtworkType.CLEARLOGO);
        private final ArtworkScanner tvThumbScanner = new FanartTvScanner(ArtworkType.TVTHUMB);
        private final ArtworkScanner seasonThumbScanner = new FanartTvScanner(ArtworkType.SEASONTHUMB);
        // FANART.TV Movie Artwork Scanners
        private final ArtworkScanner movieArtScanner = new FanartTvScanner(ArtworkType.MOVIEART);
        private final ArtworkScanner movieLogoScanner = new FanartTvScanner(ArtworkType.MOVIELOGO);
        private final ArtworkScanner movieDiscScanner = new FanartTvScanner(ArtworkType.MOVIEDISC);
    }

    final ThreadLocal<ToolSet> threadTools = new ThreadLocal<ToolSet>() {
        @Override
        protected ToolSet initialValue() {
            return new ToolSet();
        }
    };

    final MovieJukeboxXMLReader xmlReader = new MovieJukeboxXMLReader();
    final MovieJukeboxXMLWriter xmlWriter = new MovieJukeboxXMLWriter();
    final MovieJukeboxHTMLWriter htmlWriter = new MovieJukeboxHTMLWriter();

    File mediaLibraryRoot = new File(movieLibraryRoot);
    final File jukeboxDetailsRootFile = new FileTools.FileEx(jukebox.getJukeboxRootLocationDetails());

    MovieListingPlugin listingPlugin = getListingPlugin(
            getProperty("mjb.listing.plugin", "com.moviejukebox.plugin.MovieListingPluginBase"));

    videoimageDownload = PropertiesUtil.getBooleanProperty("mjb.includeVideoImages", Boolean.FALSE);
    bannerDownload = PropertiesUtil.getBooleanProperty("mjb.includeWideBanners", Boolean.FALSE);
    photoDownload = PropertiesUtil.getBooleanProperty("mjb.includePhoto", Boolean.FALSE);
    backdropDownload = PropertiesUtil.getBooleanProperty("mjb.includeBackdrop", Boolean.FALSE);
    boolean processExtras = PropertiesUtil.getBooleanProperty("filename.extras.process", Boolean.TRUE);
    boolean moviejukeboxListing = PropertiesUtil.getBooleanProperty("mjb.listing.generate", Boolean.FALSE);

    // Multi-thread: Processing thread settings
    maxThreadsProcess = Integer.parseInt(getProperty("mjb.MaxThreadsProcess", "0"));
    if (maxThreadsProcess <= 0) {
        maxThreadsProcess = Runtime.getRuntime().availableProcessors();
    }

    maxThreadsDownload = Integer.parseInt(getProperty("mjb.MaxThreadsDownload", "0"));
    if (maxThreadsDownload <= 0) {
        maxThreadsDownload = maxThreadsProcess;
    }

    LOG.info("Using {} processing threads and {} downloading threads...", maxThreadsProcess,
            maxThreadsDownload);
    if (maxThreadsDownload + maxThreadsProcess == 2) {
        // Display the note about the performance, otherwise assume that the user knows how to change
        // these parameters as they aren't set to the minimum
        LOG.info("See README.TXT for increasing performance using these settings.");
    }

    /*
     * ******************************************************************************
     *
     * PART 1 : Preparing the temporary environment
     *
     */
    SystemTools.showMemory();

    LOG.info("Preparing environment...");

    // create the ".mjbignore" and ".no_photo.nmj" file in the jukebox folder
    try {
        FileTools.makeDirs(jukebox.getJukeboxRootLocationDetailsFile());
        new File(jukebox.getJukeboxRootLocationDetailsFile(), ".mjbignore").createNewFile();
        FileTools.addJukeboxFile(".mjbignore");

        if (getBooleanProperty("mjb.nmjCompliant", Boolean.FALSE)) {
            new File(jukebox.getJukeboxRootLocationDetailsFile(), ".no_photo.nmj").createNewFile();
            FileTools.addJukeboxFile(".no_photo.nmj");
        }
    } catch (IOException error) {
        LOG.error("Failed creating jukebox directory. Ensure this directory is read/write!");
        LOG.error(SystemTools.getStackTrace(error));
        return;
    }

    // Delete the existing filecache.txt
    try {
        (new File("filecache.txt")).delete();
    } catch (Exception error) {
        LOG.error("Failed to delete the filecache.txt file.");
        LOG.error(SystemTools.getStackTrace(error));
        return;
    }

    // Save the current state of the preferences to the skin directory for use by the skin
    // The forceHtmlOverwrite is set by the user or by the JukeboxProperties if there has been a skin change
    if (PropertiesUtil.getBooleanProperty("mjb.forceHTMLOverwrite", Boolean.FALSE)
            || !(new File(PropertiesUtil.getPropertiesFilename(Boolean.TRUE))).exists()) {
        PropertiesUtil.writeProperties();
    }

    SystemTools.showMemory();

    LOG.info("Initializing...");
    try {
        FileTools.deleteDir(jukebox.getJukeboxTempLocation());
    } catch (Exception error) {
        LOG.error(
                "Failed deleting the temporary jukebox directory ({}), please delete this manually and try again",
                jukebox.getJukeboxTempLocation());
        return;
    }

    // Try and create the temp directory
    LOG.debug("Creating temporary jukebox location: {}", jukebox.getJukeboxTempLocation());
    FileTools.makeDirs(jukebox.getJukeboxTempLocationDetailsFile());

    /*
     * ******************************************************************************
     *
     * PART 2 : Scan movie libraries for files...
     *
     */
    SystemTools.showMemory();

    LOG.info("Scanning library directory {}", mediaLibraryRoot);
    LOG.info("Jukebox output goes to {}", jukebox.getJukeboxRootLocation());
    if (PropertiesUtil.getBooleanProperty("mjb.dirHash", Boolean.FALSE)) {
        // Add all folders 2 deep to the fileCache
        FileTools.fileCache.addDir(jukeboxDetailsRootFile, 2);
        /*
         * TODO: Need to watch for any issues when we have scanned the whole
         * jukebox, such as the watched folder, NFO folder, etc now existing
         * in the cache
         */
    } else {
        // If the dirHash is not needed, just scan to the root level plus the watched and people folders
        FileTools.fileCache.addDir(jukeboxDetailsRootFile, 0);

        // Add the watched folder
        File watchedFileHandle = new FileTools.FileEx(
                jukebox.getJukeboxRootLocationDetails() + File.separator + "Watched");
        FileTools.fileCache.addDir(watchedFileHandle, 0);

        // Add the people folder if needed
        if (isValidString(peopleFolder)) {
            File peopleFolderHandle = new FileTools.FileEx(
                    jukebox.getJukeboxRootLocationDetails() + File.separator + peopleFolder);
            FileTools.fileCache.addDir(peopleFolderHandle, 0);
        }
    }

    ThreadExecutor<Void> tasks = new ThreadExecutor<>(maxThreadsProcess, maxThreadsDownload);

    final Library library = new Library();
    for (final MediaLibraryPath mediaLibraryPath : mediaLibraryPaths) {
        // Multi-thread parallel processing
        tasks.submit(new Callable<Void>() {
            @Override
            public Void call() {
                LOG.debug("Scanning media library {}", mediaLibraryPath.getPath());
                MovieDirectoryScanner mds = new MovieDirectoryScanner();
                // scan uses synchronized method Library.addMovie
                mds.scan(mediaLibraryPath, library);
                System.out.print("\n");
                return null;
            }
        });
    }
    tasks.waitFor();

    SystemTools.showMemory();

    // If the user asked to preserve the existing movies, scan the output directory as well
    if (isJukeboxPreserve()) {
        LOG.info("Scanning output directory for additional videos");
        OutputDirectoryScanner ods = new OutputDirectoryScanner(jukebox.getJukeboxRootLocationDetails());
        ods.scan(library);
    }

    // Now that everything's been scanned, add all extras to library
    library.mergeExtras();

    LOG.info("Found {} videos in your media library", library.size());
    LOG.info("Stored {} files in the info cache", FileTools.fileCache.size());

    if (enableWatchTraktTv) {
        // if Trakt.TV watched is enabled then refresh if necessary and preLoad watched data
        TraktTV.getInstance().initialize().refreshIfNecessary().preloadWatched();
    }

    JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.SCAN_END, System.currentTimeMillis());
    JukeboxStatistics.setStatistic(JukeboxStatistic.VIDEOS, library.size());

    tasks.restart();
    if (!library.isEmpty()) {
        // Issue 1882: Separate index files for each category
        boolean separateCategories = PropertiesUtil.getBooleanProperty("mjb.separateCategories", Boolean.FALSE);

        LOG.info("Searching for information on the video files...");
        int movieCounter = 0;
        for (final Movie movie : library.values()) {
            // Issue 997: Skip the processing of extras if not required
            if (movie.isExtra() && !processExtras) {
                continue;
            }

            final int count = ++movieCounter;

            final String movieTitleExt = movie.getOriginalTitle()
                    + (movie.isTVShow() ? (" [Season " + movie.getSeason() + "]") : "")
                    + (movie.isExtra() ? " [Extra]" : "");

            if (movie.isTVShow()) {
                JukeboxStatistics.increment(JukeboxStatistic.TVSHOWS);
            } else {
                JukeboxStatistics.increment(JukeboxStatistic.MOVIES);
            }

            // Multi-thread parallel processing
            tasks.submit(new Callable<Void>() {
                @Override
                public Void call() throws FileNotFoundException, XMLStreamException {

                    ToolSet tools = threadTools.get();

                    // Change the output message depending on the existance of the XML file
                    boolean xmlExists = FileTools.fileCache
                            .fileExists(StringTools.appendToPath(jukebox.getJukeboxRootLocationDetails(),
                                    movie.getBaseName()) + EXT_DOT_XML);
                    if (xmlExists) {
                        LOG.info("Checking existing video: {}", movieTitleExt);
                        JukeboxStatistics.increment(JukeboxStatistic.EXISTING_VIDEOS);
                    } else {
                        LOG.info("Processing new video: {}", movieTitleExt);
                        JukeboxStatistics.increment(JukeboxStatistic.NEW_VIDEOS);
                    }

                    if (ScanningLimit.getToken()) {

                        // First get movie data (title, year, director, genre, etc...)
                        library.toggleDirty(
                                updateMovieData(xmlReader, tools.miScanner, jukebox, movie, library));

                        if (!movie.getMovieType().equals(Movie.REMOVE)) {
                            // Check for watched and unwatched files
                            if (enableWatchScanner || enableWatchTraktTv) { // Issue 1938
                                library.toggleDirty(WatchedScanner.checkWatched(jukebox, movie));
                            }

                            // Get subtitle
                            tools.subtitlePlugin.generate(movie);

                            // Get Trailers
                            if (trailersScannerEnable) {
                                tools.trailerScanner.getTrailers(movie);
                            }

                            // Then get this movie's poster
                            LOG.debug("Updating poster for: {}", movieTitleExt);
                            updateMoviePoster(jukebox, movie);

                            // Download episode images if required
                            if (videoimageDownload) {
                                VideoImageScanner.scan(tools.imagePlugin, jukebox, movie);
                            }

                            // Get FANART only if requested
                            // Note that the FanartScanner will check if the file is newer / different
                            if ((fanartMovieDownload && !movie.isTVShow())
                                    || (fanartTvDownload && movie.isTVShow())) {
                                FanartScanner.scan(tools.backgroundPlugin, jukebox, movie);
                            }

                            // Get BANNER if requested and is a TV show
                            if (bannerDownload && movie.isTVShow()) {
                                if (!BannerScanner.scan(tools.imagePlugin, jukebox, movie)) {
                                    updateTvBanner(jukebox, movie, tools.imagePlugin);
                                }
                            }

                            // Get ClearART/LOGOS/etc
                            if (movie.isTVShow()) {
                                // Only scan using the TV Show artwork scanners
                                tools.clearArtScanner.scan(jukebox, movie);
                                tools.clearLogoScanner.scan(jukebox, movie);
                                tools.tvThumbScanner.scan(jukebox, movie);
                                tools.seasonThumbScanner.scan(jukebox, movie);
                            } else {
                                // Only scan using the Movie artwork scanners
                                tools.movieArtScanner.scan(jukebox, movie);
                                tools.movieDiscScanner.scan(jukebox, movie);
                                tools.movieLogoScanner.scan(jukebox, movie);
                            }

                            for (int i = 0; i < footerCount; i++) {
                                if (FOOTER_ENABLE.get(i)) {
                                    updateFooter(jukebox, movie, tools.imagePlugin, i,
                                            forceFooterOverwrite || movie.isDirty());
                                }
                            }

                            // If we are multipart, we need to make sure all archives have expanded names.
                            if (PropertiesUtil.getBooleanProperty("mjb.scanner.mediainfo.rar.extended.url",
                                    Boolean.FALSE)) {

                                Collection<MovieFile> partsFiles = movie.getFiles();
                                for (MovieFile mf : partsFiles) {
                                    String filename;

                                    filename = mf.getFile().getAbsolutePath();

                                    // Check the filename is a mediaInfo extension (RAR, ISO) ?
                                    if (tools.miScanner.extendedExtension(filename) == Boolean.TRUE) {

                                        if (mf.getArchiveName() == null) {
                                            LOG.debug("MovieJukebox: Attempting to get archive name for {}",
                                                    filename);
                                            String archive = tools.miScanner.archiveScan(filename);
                                            if (archive != null) {
                                                LOG.debug("MovieJukebox: Setting archive name to {}", archive);
                                                mf.setArchiveName(archive);
                                            } // got archivename
                                        } // not already set
                                    } // is extension
                                } // for all files
                            } // property is set
                            if (!movie.isDirty()) {
                                ScanningLimit.releaseToken();
                            }
                        } else {
                            ScanningLimit.releaseToken();
                            library.remove(movie);
                        }
                        LOG.info(LOG_FINISHED, movieTitleExt, count, library.size());
                    } else {
                        movie.setSkipped(true);
                        JukeboxProperties.setScanningLimitReached(Boolean.TRUE);
                        LOG.info("Skipped: {} ({}/{})", movieTitleExt, count, library.size());
                    }
                    // Show memory every (processing count) movies
                    if (showMemory && (count % maxThreadsProcess) == 0) {
                        SystemTools.showMemory();
                    }

                    return null;
                }
            });
        }
        tasks.waitFor();

        // Add the new extra files (like trailers that were downloaded) to the library and to the corresponding movies
        library.mergeExtras();

        OpenSubtitlesPlugin.logOut();
        AniDbPlugin.anidbClose();

        JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.PROCESSING_END,
                System.currentTimeMillis());

        if (peopleScan && peopleScrape && !ScanningLimit.isLimitReached()) {
            LOG.info("Searching for people information...");
            int peopleCounter = 0;
            Map<String, Person> popularPeople = new TreeMap<>();
            for (Movie movie : library.values()) {
                // Issue 997: Skip the processing of extras if not required
                if (movie.isExtra() && !processExtras) {
                    continue;
                }

                if (popularity > 0) {
                    for (Filmography person : movie.getPeople()) {
                        boolean exists = Boolean.FALSE;
                        String name = person.getName();
                        for (Map.Entry<String, Person> entry : popularPeople.entrySet()) {
                            if (entry.getKey().substring(3).equalsIgnoreCase(name)) {
                                entry.getValue().addDepartment(person.getDepartment());
                                entry.getValue().popularityUp(movie);
                                exists = Boolean.TRUE;
                            }
                        }

                        if (!exists) {
                            Person p = new Person(person);
                            p.addDepartment(p.getDepartment());
                            String key = String.format("%03d", person.getOrder()) + person.getName();
                            popularPeople.put(key, p);
                            popularPeople.get(key).popularityUp(movie);
                        }
                    }
                } else {
                    peopleCounter += movie.getPeople().size();
                }
            }

            tasks.restart();
            if (popularity > 0) {
                List<Person> as = new ArrayList<>(popularPeople.values());

                Collections.sort(as, new PersonComparator());

                List<Person> stars = new ArrayList<>();
                Iterator<Person> itr = as.iterator();

                while (itr.hasNext()) {
                    if (peopleCounter >= peopleMax) {
                        break;
                    }

                    Person person = itr.next();

                    if (popularity > person.getPopularity()) {
                        break;
                    }

                    stars.add(person);
                    peopleCounter++;
                }

                final int peopleCount = peopleCounter;
                peopleCounter = 0;
                for (final Person person : stars) {
                    final int count = ++peopleCounter;
                    final String personName = person.getName();
                    final Person p = new Person(person);

                    // Multi-thread parallel processing
                    tasks.submit(new Callable<Void>() {
                        @Override
                        public Void call() throws FileNotFoundException, XMLStreamException {

                            ToolSet tools = threadTools.get();

                            // Get person data (name, birthday, etc...), download photo
                            updatePersonData(xmlReader, jukebox, p, tools.imagePlugin);
                            library.addPerson(p);

                            LOG.info(LOG_FINISHED, personName, count, peopleCount);

                            // Show memory every (processing count) movies
                            if (showMemory && (count % maxThreadsProcess) == 0) {
                                SystemTools.showMemory();
                            }

                            return null;
                        }
                    });
                }
            } else {
                final int peopleCount = peopleCounter;
                peopleCounter = 0;
                for (Movie movie : library.values()) {
                    // Issue 997: Skip the processing of extras if not required
                    if (movie.isExtra() && !processExtras) {
                        continue;
                    }
                    Map<String, Integer> typeCounter = new TreeMap<>();
                    for (Filmography person : movie.getPeople()) {
                        final int count = ++peopleCounter;
                        String job = person.getJob();
                        if (!typeCounter.containsKey(job)) {
                            typeCounter.put(job, 1);
                        } else if (typeCounter.get(job) == peopleMax) {
                            continue;
                        } else {
                            typeCounter.put(job, typeCounter.get(job) + 1);
                        }
                        final Person p = new Person(person);
                        final String personName = p.getName();

                        // Multi-thread parallel processing
                        tasks.submit(new Callable<Void>() {
                            @Override
                            public Void call() throws FileNotFoundException, XMLStreamException {

                                ToolSet tools = threadTools.get();

                                // Get person data (name, birthday, etc...), download photo and put to library
                                updatePersonData(xmlReader, jukebox, p, tools.imagePlugin);
                                library.addPerson(p);

                                LOG.info(LOG_FINISHED, personName, count, peopleCount);

                                // Show memory every (processing count) movies
                                if (showMemory && (count % maxThreadsProcess) == 0) {
                                    SystemTools.showMemory();
                                }

                                return null;
                            }
                        });
                    }
                }
            }
            tasks.waitFor();

            LOG.info("Add/update people information to the videos...");
            boolean dirty;
            for (Movie movie : library.values()) {
                // Issue 997: Skip the processing of extras if not required
                if (movie.isExtra() && !processExtras) {
                    continue;
                }

                for (Filmography person : movie.getPeople()) {
                    dirty = Boolean.FALSE;
                    for (Person p : library.getPeople()) {
                        if (Filmography.comparePersonName(person, p) || comparePersonId(person, p)) {
                            if (!person.getFilename().equals(p.getFilename())
                                    && isValidString(p.getFilename())) {
                                person.setFilename(p.getFilename());
                                dirty = Boolean.TRUE;
                            }
                            if (!person.getUrl().equals(p.getUrl()) && isValidString(p.getUrl())) {
                                person.setUrl(p.getUrl());
                                dirty = Boolean.TRUE;
                            }
                            for (Map.Entry<String, String> e : p.getIdMap().entrySet()) {
                                if (isNotValidString(e.getValue())) {
                                    continue;
                                }

                                if (person.getId(e.getKey()).equals(e.getValue())) {
                                    continue;
                                }

                                person.setId(e.getKey(), e.getValue());
                                dirty = Boolean.TRUE;
                            }

                            if (!person.getPhotoFilename().equals(p.getPhotoFilename())
                                    && isValidString(p.getPhotoFilename())) {
                                person.setPhotoFilename(p.getPhotoFilename());
                                dirty = Boolean.TRUE;
                            }

                            break;
                        }
                    }

                    if (dirty) {
                        movie.setDirty(DirtyFlag.INFO, Boolean.TRUE);
                    }
                }

                for (Person p : library.getPeople()) {
                    for (Filmography film : p.getFilmography()) {
                        if (Filmography.compareMovieAndFilm(movie, film)) {
                            film.setFilename(movie.getBaseName());
                            film.setTitle(movie.getTitle());
                            if (film.isDirty()) {
                                p.setDirty();
                            }
                            break;
                        }
                    }
                }
            }

            for (Person p : library.getPeople()) {
                for (Filmography film : p.getFilmography()) {
                    if (film.isDirty() || StringTools.isNotValidString(film.getFilename())) {
                        continue;
                    }
                    dirty = Boolean.FALSE;
                    for (Movie movie : library.values()) {
                        if (movie.isExtra() && !processExtras) {
                            continue;
                        }
                        dirty = Filmography.compareMovieAndFilm(movie, film);
                        if (dirty) {
                            break;
                        }
                    }
                    if (!dirty) {
                        film.clearFilename();
                        p.setDirty();
                    }
                }
            }

            JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.PEOPLE_END,
                    System.currentTimeMillis());
        }

        /*
         * ******************************************************************************
         *
         * PART 3 : Indexing the library
         *
         */
        SystemTools.showMemory();

        // This is for programs like NMTServer where they don't need the indexes.
        if (skipIndexGeneration) {
            LOG.info("Indexing of libraries skipped.");
        } else {
            LOG.info("Indexing libraries...");
            library.buildIndex(tasks);
            JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.INDEXING_END,
                    System.currentTimeMillis());
            SystemTools.showMemory();
        }

        /*
         * ******************************************************************************
         *
         * PART 3B - Indexing masters
         */
        LOG.info("Indexing masters...");
        /*
         * This is kind of a hack -- library.values() are the movies that
         * were found in the library and library.getMoviesList() are the
         * ones that are there now. So the movies that are in getMoviesList
         * but not in values are the index masters.
         */
        List<Movie> indexMasters = new ArrayList<>(library.getMoviesList());
        indexMasters.removeAll(library.values());

        JukeboxStatistics.setStatistic(JukeboxStatistic.SETS, indexMasters.size());

        // Multi-thread: Parallel Executor
        tasks.restart();
        final boolean autoCollection = PropertiesUtil.getBooleanProperty("themoviedb.collection",
                Boolean.FALSE);
        final TheMovieDbPlugin tmdb = new TheMovieDbPlugin();

        for (final Movie movie : indexMasters) {
            // Multi-tread: Start Parallel Processing
            tasks.submit(new Callable<Void>() {
                @Override
                public Void call() throws FileNotFoundException, XMLStreamException {
                    ToolSet tools = threadTools.get();

                    String safeSetMasterBaseName = FileTools.makeSafeFilename(movie.getBaseName());

                    /*
                     * The master's movie XML is used for generating the
                     * playlist it will be overwritten by the index XML
                     */
                    LOG.debug("Updating set artwork for: {}...", movie.getOriginalTitle());
                    // If we can find a set artwork file, use it; otherwise, stick with the first movie's artwork
                    String oldArtworkFilename = movie.getPosterFilename();

                    // Set a default poster name in case it's not found during the scan
                    movie.setPosterFilename(safeSetMasterBaseName + "." + posterExtension);
                    if (isNotValidString(PosterScanner.scan(jukebox, movie))) {
                        LOG.debug("Local set poster ({}) not found.", safeSetMasterBaseName);

                        String collectionId = movie.getId(TheMovieDbPlugin.CACHE_COLLECTION);
                        if (autoCollection && StringUtils.isNumeric(collectionId)) {
                            LOG.debug("MovieDb Collection detected with ID {}", collectionId);

                            movie.setPosterURL(tmdb.getCollectionPoster(Integer.parseInt(collectionId)));
                            movie.setFanartURL(tmdb.getCollectionFanart(Integer.parseInt(collectionId)));

                            updateMoviePoster(jukebox, movie);
                        } else {
                            movie.setPosterFilename(oldArtworkFilename);
                        }
                    }

                    // If this is a TV Show and we want to download banners, then also check for a banner Set file
                    if (movie.isTVShow() && bannerDownload) {
                        // Set a default banner filename in case it's not found during the scan
                        movie.setBannerFilename(safeSetMasterBaseName + bannerToken + "." + bannerExtension);
                        movie.setWideBannerFilename(
                                safeSetMasterBaseName + wideBannerToken + "." + bannerExtension);
                        if (!BannerScanner.scan(tools.imagePlugin, jukebox, movie)) {
                            updateTvBanner(jukebox, movie, tools.imagePlugin);
                            LOG.debug("Local set banner ({}{}.*) not found.", safeSetMasterBaseName,
                                    bannerToken);
                        } else {
                            LOG.debug("Local set banner found, using {}", movie.getBannerFilename());
                        }
                    }

                    // Check for Set FANART
                    if (setIndexFanart) {
                        // Set a default fanart filename in case it's not found during the scan
                        movie.setFanartFilename(safeSetMasterBaseName + fanartToken + "." + fanartExtension);
                        if (!FanartScanner.scan(tools.backgroundPlugin, jukebox, movie)) {
                            LOG.debug("Local set fanart ({}{}.*) not found.", safeSetMasterBaseName,
                                    fanartToken);
                        } else {
                            LOG.debug("Local set fanart found, using {}", movie.getFanartFilename());
                        }
                    }

                    StringBuilder artworkFilename = new StringBuilder(safeSetMasterBaseName);
                    artworkFilename.append(thumbnailToken).append(".").append(thumbnailExtension);
                    movie.setThumbnailFilename(artworkFilename.toString());

                    artworkFilename = new StringBuilder(safeSetMasterBaseName);
                    artworkFilename.append(posterToken).append(".").append(posterExtension);
                    movie.setDetailPosterFilename(artworkFilename.toString());

                    // Generate footer filenames
                    for (int inx = 0; inx < footerCount; inx++) {
                        if (FOOTER_ENABLE.get(inx)) {
                            artworkFilename = new StringBuilder(safeSetMasterBaseName);
                            if (FOOTER_NAME.get(inx).contains("[")) {
                                artworkFilename.append(footerToken).append("_").append(inx);
                            } else {
                                artworkFilename.append(".").append(FOOTER_NAME.get(inx));
                            }
                            artworkFilename.append(".").append(FOOTER_EXTENSION.get(inx));
                            movie.setFooterFilename(artworkFilename.toString(), inx);
                        }
                    }

                    // No playlist for index masters
                    // htmlWriter.generatePlaylist(jukeboxDetailsRoot, tempJukeboxDetailsRoot, movie);
                    // Add all the movie files to the exclusion list
                    FileTools.addMovieToJukeboxFilenames(movie);

                    return null;
                }
            });
        }
        tasks.waitFor();

        // Clear the cache if we've used it
        CacheMemory.clear();
        JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.MASTERS_END,
                System.currentTimeMillis());
        SystemTools.showMemory();

        // Issue 1886: Html indexes recreated every time
        StringBuilder indexFilename;
        for (Movie setMovie : library.getMoviesList()) {
            if (setMovie.isSetMaster()) {
                indexFilename = new StringBuilder(jukebox.getJukeboxRootLocationDetails());
                indexFilename.append(File.separator).append(setMovie.getBaseName()).append(EXT_DOT_XML);
                File xmlFile = FileTools.fileCache.getFile(indexFilename.toString());
                if (xmlFile.exists()) {
                    xmlReader.parseSetXML(xmlFile, setMovie, library.getMoviesList());
                }
            }
        }

        // Issue 1882: Separate index files for each category
        List<String> categoriesList = Arrays.asList(
                getProperty("mjb.categories.indexList", "Other,Genres,Title,Certification,Year,Library,Set")
                        .split(","));

        if (!skipIndexGeneration) {
            LOG.info("Writing Indexes XML...");
            xmlWriter.writeIndexXML(jukebox, library, tasks);

            // Issue 2235: Update artworks after masterSet changed
            ToolSet tools = threadTools.get();
            StringBuilder idxName;
            boolean createPosters = PropertiesUtil.getBooleanProperty("mjb.sets.createPosters", Boolean.FALSE);

            for (IndexInfo idx : library.getGeneratedIndexes()) {
                if (!idx.canSkip && idx.categoryName.equals(Library.INDEX_SET)) {
                    idxName = new StringBuilder(idx.categoryName);
                    idxName.append("_").append(FileTools.makeSafeFilename(idx.key)).append("_1");

                    for (Movie movie : indexMasters) {
                        if (!movie.getBaseName().equals(idxName.toString())) {
                            continue;
                        }

                        if (createPosters) {
                            // Create/update a detail poster for setMaster
                            LOG.debug("Create/update detail poster for set: {}", movie.getBaseName());
                            createPoster(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie,
                                    Boolean.TRUE);
                        }

                        // Create/update a thumbnail for setMaster
                        LOG.debug("Create/update thumbnail for set: {}, isTV: {}, isHD: {}",
                                movie.getBaseName(), movie.isTVShow(), movie.isHD());
                        createThumbnail(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie,
                                Boolean.TRUE);

                        for (int inx = 0; inx < footerCount; inx++) {
                            if (FOOTER_ENABLE.get(inx)) {
                                LOG.debug("Create/update footer for set: {}, footerName: {}",
                                        movie.getBaseName(), FOOTER_NAME.get(inx));
                                updateFooter(jukebox, movie, tools.imagePlugin, inx, Boolean.TRUE);
                            }
                        }
                    }
                }
            }

            LOG.info("Writing Category XML...");
            library.setDirty(library.isDirty() || forceIndexOverwrite);
            xmlWriter.writeCategoryXML(jukebox, library, "Categories", library.isDirty());

            // Issue 1882: Separate index files for each category
            if (separateCategories) {
                for (String categoryName : categoriesList) {
                    xmlWriter.writeCategoryXML(jukebox, library, categoryName, library.isDirty());
                }
            }
        }

        SystemTools.showMemory();

        LOG.info("Writing Library data...");
        // Multi-thread: Parallel Executor
        tasks.restart();

        int totalCount = library.values().size();
        int currentCount = 1;

        for (final Movie movie : library.values()) {
            System.out.print("\r    Processing library #" + currentCount++ + "/" + totalCount);

            // Issue 997: Skip the processing of extras if not required
            if (movie.isExtra() && !processExtras) {
                continue;
            }

            if (movie.isSkipped()) {
                continue;
            }

            // Multi-tread: Start Parallel Processing
            tasks.submit(new Callable<Void>() {
                @Override
                public Void call() throws FileNotFoundException, XMLStreamException {
                    ToolSet tools = threadTools.get();
                    // Update movie XML files with computed index information
                    LOG.debug("Writing index data to movie: {}", movie.getBaseName());
                    xmlWriter.writeMovieXML(jukebox, movie, library);

                    // Create a detail poster for each movie
                    LOG.debug("Creating detail poster for movie: {}", movie.getBaseName());
                    createPoster(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie,
                            forcePosterOverwrite);

                    // Create a thumbnail for each movie
                    LOG.debug("Creating thumbnails for movie: {}", movie.getBaseName());
                    createThumbnail(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie,
                            forceThumbnailOverwrite);

                    if (!skipIndexGeneration && !skipHtmlGeneration) {
                        // write the movie details HTML
                        LOG.debug("Writing detail HTML to movie: {}", movie.getBaseName());
                        htmlWriter.generateMovieDetailsHTML(jukebox, movie);

                        // write the playlist for the movie if needed
                        if (!skipPlaylistGeneration) {
                            FileTools.addJukeboxFiles(htmlWriter.generatePlaylist(jukebox, movie));
                        }
                    }
                    // Add all the movie files to the exclusion list
                    FileTools.addMovieToJukeboxFilenames(movie);

                    return null;
                }
            });
        }
        tasks.waitFor();
        System.out.print("\n");

        SystemTools.showMemory();
        JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.WRITE_INDEX_END,
                System.currentTimeMillis());

        if (peopleScan) {
            LOG.info("Writing people data...");
            // Multi-thread: Parallel Executor
            tasks.restart();

            totalCount = library.getPeople().size();
            currentCount = 1;
            for (final Person person : library.getPeople()) {
                // Multi-tread: Start Parallel Processing
                System.out.print("\r    Processing person #" + currentCount++ + "/" + totalCount);
                tasks.submit(new Callable<Void>() {
                    @Override
                    public Void call() throws FileNotFoundException, XMLStreamException {
                        // ToolSet tools = threadTools.get();
                        // Update person XML files with computed index information
                        LOG.debug("Writing index data to person: {}", person.getName());
                        xmlWriter.writePersonXML(jukebox, person);

                        if (!skipIndexGeneration && !skipHtmlGeneration) {
                            // write the person details HTML
                            htmlWriter.generatePersonDetailsHTML(jukebox, person);
                        }

                        return null;
                    }
                });
            }
            tasks.waitFor();
            System.out.print("\n");

            SystemTools.showMemory();
            JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.WRITE_PEOPLE_END,
                    System.currentTimeMillis());
        }

        if (!skipIndexGeneration) {
            if (!skipHtmlGeneration) {
                LOG.info("Writing Indexes HTML...");
                LOG.info("  Video indexes...");
                htmlWriter.generateMoviesIndexHTML(jukebox, library, tasks);
                LOG.info("  Category indexes...");
                htmlWriter.generateMoviesCategoryHTML(jukebox, "Categories", "categories.xsl",
                        library.isDirty());

                // Issue 1882: Separate index files for each category
                if (separateCategories) {
                    LOG.info("  Separate category indexes...");
                    for (String categoryName : categoriesList) {
                        htmlWriter.generateMoviesCategoryHTML(jukebox, categoryName, "category.xsl",
                                library.isDirty());
                    }
                }
            }

            /*
             * Generate the index file.
             *
             * Do not skip this part as it's the index that starts the jukebox
             */
            htmlWriter.generateMainIndexHTML(jukebox, library);
            JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.WRITE_HTML_END,
                    System.currentTimeMillis());

            /*
             Generate extra pages if required
             */
            String pageList = PropertiesUtil.getProperty("mjb.customPages", "");
            if (StringUtils.isNotBlank(pageList)) {
                List<String> newPages = new ArrayList<>(Arrays.asList(pageList.split(",")));
                for (String page : newPages) {
                    LOG.info("Transforming skin custom page '{}'", page);
                    htmlWriter.transformXmlFile(jukebox, page);
                }
            }
        }

        if (enableCompleteMovies) {
            CompleteMoviesWriter.generate(library, jukebox);
        }

        /**
         * ******************************************************************************
         *
         * PART 4 : Copy files to target directory
         *
         */
        SystemTools.showMemory();

        LOG.info("Copying new files to Jukebox directory...");
        String index = getProperty("mjb.indexFile", "index.htm");

        FileTools.copyDir(jukebox.getJukeboxTempLocationDetails(), jukebox.getJukeboxRootLocationDetails(),
                Boolean.TRUE);
        FileTools.copyFile(new File(jukebox.getJukeboxTempLocation() + File.separator + index),
                new File(jukebox.getJukeboxRootLocation() + File.separator + index));

        String skinDate = jukebox.getJukeboxRootLocationDetails() + File.separator + "pictures" + File.separator
                + "skin.date";
        File skinFile = new File(skinDate);
        File propFile = new File(userPropertiesName);

        // Only check the property file date if the jukebox properties are not being monitored.
        boolean copySkin = JukeboxProperties.isMonitor() ? Boolean.FALSE
                : FileTools.isNewer(propFile, skinFile);

        // If forceSkinOverwrite is set, the skin file doesn't exist, the user properties file doesn't exist or is newer than the skin.date file
        if (forceSkinOverwrite || !skinFile.exists() || !propFile.exists()
                || (SkinProperties.getFileDate() > skinFile.lastModified()) || copySkin) {
            if (forceSkinOverwrite) {
                LOG.info("Copying skin files to Jukebox directory (forceSkinOverwrite)...");
            } else if (SkinProperties.getFileDate() > skinFile.lastModified()) {
                LOG.info("Copying skin files to Jukebox directory (Skin is newer)...");
            } else if (!propFile.exists()) {
                LOG.info("Copying skin files to Jukebox directory (No property file)...");
            } else if (FileTools.isNewer(propFile, skinFile)) {
                LOG.info("Copying skin files to Jukebox directory ({} is newer)...", propFile.getName());
            } else {
                LOG.info("Copying skin files to Jukebox directory...");
            }

            StringTokenizer st = new StringTokenizer(PropertiesUtil.getProperty("mjb.skin.copyDirs", "html"),
                    " ,;|");

            while (st.hasMoreTokens()) {
                String skinDirName = st.nextToken();
                String skinDirFull = StringTools.appendToPath(SkinProperties.getSkinHome(), skinDirName);

                if ((new File(skinDirFull).exists())) {
                    LOG.info("Copying the {} directory...", skinDirName);
                    FileTools.copyDir(skinDirFull, jukebox.getJukeboxRootLocationDetails(), Boolean.TRUE);
                }
            }

            if (skinFile.exists()) {
                skinFile.setLastModified(JukeboxStatistics.getTime(JukeboxStatistics.JukeboxTimes.START));
            } else {
                FileTools.makeDirsForFile(skinFile);
                skinFile.createNewFile();
            }
        } else {
            LOG.info("Skin copying skipped.");
            LOG.debug("Use mjb.forceSkinOverwrite=true to force the overwitting of the skin files");
        }

        FileTools.fileCache.saveFileList("filecache.txt");
        JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.COPYING_END,
                System.currentTimeMillis());

        /**
         * ******************************************************************************
         *
         * PART 5: Clean-up the jukebox directory
         *
         */
        SystemTools.showMemory();

        // Clean the jukebox folder of unneeded files
        cleanJukeboxFolder();

        if (moviejukeboxListing) {
            LOG.info("Generating listing output...");
            listingPlugin.generate(jukebox, library);
        }

        LOG.info("Clean up temporary files");
        File rootIndex = new File(appendToPath(jukebox.getJukeboxTempLocation(), index));
        rootIndex.delete();

        FileTools.deleteDir(jukebox.getJukeboxTempLocation());

        // clean up extracted attachments
        AttachmentScanner.cleanUp();
    }

    // Set the end time
    JukeboxStatistics.setTimeEnd(System.currentTimeMillis());

    // Write the jukebox details file at the END of the run (Issue 1830)
    JukeboxProperties.writeFile(jukebox, library, mediaLibraryPaths);

    // Output the statistics
    JukeboxStatistics.writeFile(jukebox, library, mediaLibraryPaths);

    LOG.info("");
    LOG.info("MovieJukebox process completed at {}", new Date());
    LOG.info("Processing took {}", JukeboxStatistics.getProcessingTime());
}