class OpearPackageMojo extends AbstractCommonMojo {

    File assembleOpear() throws Exception {
        final String prefix = "lib/";
        if (this.outputDirectory == null) {
            throw new IllegalStateException("outputDirectory should not be null");
        }
        final File finalFile = new File(this.outputDirectory, this.finalName + "." + OPEAR);

        final File planPrep = new File(this.outputDirectory, "plans-tmp-" + this.finalName);
        FileUtils.deleteDirectory(planPrep);
        planPrep.mkdirs();
        final Result<List<String>> planNames = this.shrinkWrapPlans(planPrep);
        planNames.throwCause(Exception.class);

        final MavenArchiveConfiguration conf = new MavenArchiveConfiguration();
        conf.addManifestEntry(Opear.MF_BUNDLE_SYMBOLICNAME, getBundleSymbolicName());
        conf.addManifestEntry(Opear.MF_OAKPAL_VERSION, getOakpalCoreVersion());
        conf.addManifestEntry(Opear.MF_OAKPAL_PLAN,
                Util.escapeManifestHeaderValues(planNames.getOrDefault(Collections.emptyList())));

        OpearArchiver opear = new OpearArchiver();
        opear.addFileSet(DefaultFileSet.fileSet(planPrep));

        List<File> embeddedFiles = new ArrayList<>();
        if ("jar".equals(project.getPackaging()) && project.getArtifact().getFile().exists()) {
            if (project.getArtifact().getFile().isDirectory()) {
                throw new Exception("cannot embed project artifact while it is a directory.");
            }
            embeddedFiles.add(project.getArtifact().getFile());
        } else if (OPEAR.equals(project.getPackaging())
                && new File(project.getBuild().getOutputDirectory()).isDirectory()) {
            embeddedFiles.add(new File(project.getBuild().getOutputDirectory()));
        }
        embeddedFiles.addAll(getEmbeddedLibraries());
        Map<String, File> destFiles = mapDestFileNames(new LinkedHashMap<>(), embeddedFiles, File::getName);
        final String scanClassPath = Util.escapeManifestHeaderValue(destFiles.entrySet().stream()
                .map(entry -> prefix + entry.getKey())
                .toArray(String[]::new));
        conf.addManifestEntry(Opear.MF_CLASS_PATH, scanClassPath);

        destFiles.entrySet().stream().filter(testValue(File::isFile)).forEachOrdered(entry -> {
            opear.addFile(entry.getValue(), prefix + entry.getKey());
        });

        destFiles.entrySet().stream().filter(testValue(File::isDirectory)).forEachOrdered(entry -> {
            opear.addFileSet(new DefaultFileSet(entry.getValue()).prefixed(prefix + entry.getKey() + "/"));
        });

        MavenArchiver mavenArchiver = new MavenArchiver();
        mavenArchiver.setArchiver(opear);
        mavenArchiver.setOutputFile(finalFile);
        mavenArchiver.createArchive(getSession(), project, conf);

        return finalFile;
    }

}