As I was working on the content template service for my last blog, I saw some things that neeeded to be done. There is an ImportBasedFactory hanging around since basically the beginning of the ContentTemplateService. It has never been implemented. Here’s how we’re gonna do it.

The ImportFactory

The goal of this factory will be to import some content from a file or a folder instead of a templateItem like we saw last week.

To create a new factory, I need a new class that implements the ContentFactory interface. A good thing to know is that there is an abstract class BaseContentFactory that implements the interface and gives a method to handle the CoreSession. So right now the ImportBasedFactory looks like this:

```java public class ImportBasedFactory extends BaseContentFactory {

public void createContentStructure(DocumentModel eventDoc) throws ClientException { throw new UnsupportedOperationException(); }

public boolean initFactory(Map options, List rootAcl, List template) { throw new UnsupportedOperationException(); }

} ```

We have two methods to implement. initFactory will be used to retrieve the path of the zip file from the options map. createContentStructure will be used to import the documents from the file.

Retrieve the file

I’m going to use the option map to get the file. I have many options. I can retrieve the file from the bundle resources, from Nuxeo’s data folder or from any path on the server. To represent these three options I could have a contribution like this:

xml <extension target="org.nuxeo.ecm.platform.content.template.service.ContentTemplateService" point="factoryBinding"><factorybinding name="RootFactory" factoryname="SimpleTemplateFactory" targettype="Root"><option name="path"></option> <option name="overwrite">false</option></factorybinding></extension>

My initFactory method will simply have to store the options on our factory. I will only use two options here: path and overwrite. path will be use to retrieve the file to import. I plan to have an address in one of these formats - or absolute:/home/nuxeo/zip/ or even The absolute path will reference a file on the server’s filesystem, nxData will reference a file inside the Nuxeo data folder and resource will reference a file in the bundle’s resources. I have used a Java enum for this. It has 3 different values: absolute, nxData and resource. I declare an abstract method getFile in the enum. This way I can implement a different getFile for each value. Then all I have to do is add a static method like getResource which takes a single String parameter. This parameter is split at the first ‘:’ char. This way, I can get the value using enum.valueOf and call its getFile method. If this file does not exist, initFactory will return false and the factory won’t be executed.

```java public class ImportBasedFactory extends BaseContentFactory {

private static final Log log = LogFactory.getLog(ImportBasedFactory.class);

public static final String IMPORT_FILE_PATH_OPTION = “path”;

public static final String IMPORT_OVERWRITE_OPTION = “overwrite”;

protected FileManager fileManager;

protected Map options;

protected File importedFile;

protected Boolean overwrite = false;

public enum PathOptions { resource { @Override public File getFile(String path) { return FileUtils.getResourceFileFromContext(path); } }, nxData { @Override public File getFile(String path) { File nxDdataFolder = Environment.getDefault().getData(); return new File(nxDdataFolder, path); } }, absolute { @Override public File getFile(String path) { return new File(path); } };

protected abstract File getFile(String path);

public static File getResource(String path) { String[] s = path.split(“:”, 2); String resourceType = s[0]; String resourcePath = s[1]; PathOptions option = valueOf(resourceType); if (option == null) { log.error(“Unsupported resource type: “ + resourceType); return null; } else { return option.getFile(resourcePath); } } }

@Override public boolean initFactory(Map options, List rootAcl, List template) { this.options = options; overwrite = Boolean.valueOf(options.get(IMPORT_OVERWRITE_OPTION)); String path = options.get(IMPORT_FILE_PATH_OPTION); File file = PathOptions.getResource(path); if (file != null) { if (file.exists()) { importedFile = file; return true; } else { log.warn(“Following file does not exist: “ + file.getAbsolutePath()); } } return false; }

### Creating the content

The _createContentStructure_ will use the [FileManager]( "FileManager JavaDoc") service to import the file. The first thing I do is call _initSession_ from the parent Class to make sure I have an open _coreSession_. Then check if the created document is a version or not. If not, I call the _importBlob_ method. This method uses the _fileManager_ to import files as documents. The first thing I do is check if the file is a directory. If it is, then I run _importBlob_ for its child files. If not, I use the simple _FileManagerService.createDocumentFromBlob_ method. This way I can import anything from a folder and its contents to a zip XML export from Nuxeo to a simple file like a picture or a pdf. It's then really easy to customize if you add different import plugins.

```java @Override public void createContentStructure(DocumentModel eventDoc) throws ClientException { initSession(eventDoc);

if (eventDoc.isVersion()) { return; } try { String parentPath = eventDoc.getPathAsString(); importBlob(importedFile, parentPath); } catch (Exception e) { throw new RuntimeException(e); }


/** * Use fileManager to import the given file. * * @param file to import * @param parentPath of the targetDocument * @throws Exception */ protected void importBlob(File file, String parentPath) throws Exception { if (file.isDirectory()) { DocumentModel createdFolder = getFileManagerService().createFolder( session, file.getAbsolutePath(), parentPath); File[] files = file.listFiles(); for (File childFile : files) { importBlob(childFile, createdFolder.getPathAsString()); } } else { Blob fb = new FileBlob(file); fb.setFilename(file.getName()); getFileManagerService().createDocumentFromBlob(session, fb, parentPath, overwrite, fb.getFilename()); } }

protected FileManager getFileManagerService() { if (fileManager == null) { try { fileManager = Framework.getService(FileManager.class); } catch (Exception e) { throw new RuntimeException( "Unable to get FileManager service ", e); } } return fileManager; } }

That’s of course a first step of improvement. Making this factory available outside a factoryBinding could be another. That’s it for today. See ya Friday!