cancel
Showing results for 
Search instead for 
Did you mean: 

Automate Creation and Export/Import of Categories

lock999
Champ in-the-making
Champ in-the-making
Hi,

I have around 1500 categories and subcategories in an existing non-Alfresco project, and i need to create these 1500 categories and subcategories in Alfresco repository.

Question: Is there any way in Alfresco to create this huge number of categories and subcategories automatically using an existing Alfresco script or utility? We can generate the existing 1500 categories and subcategories in CSV or XML format. Is there any option to automate the category creation process against doing it manually?

Also, how to export/import categories from development repository to production repository? We may not want to export/import all the contents of the development repository and overwrite the production repository.

Thanks
18 REPLIES 18

kayan
Champ in-the-making
Champ in-the-making
Hi stevewickii,

Thanks a lot for the handy code.  It really heped a lot to import the categories.  But I face one problem when i tried to create a sub category with a "space" on the name e.g "Test Data".

Here is my .txt file contains:
# ABC Categories
/cm:ABC/cm:Test data/cm:Annaul Report


I got the following error on the console……. 

15-May-2008 23:22:57 CategoryImport runApp
INFO: Importing categories from C:\categories.txt
15-May-2008 23:22:57 CategoryImport setUp
INFO: Present…
15-May-2008 23:22:57 CategoryImport setUp
INFO: creating Alfresco web service client session with username 'admin' and password 'admin'.
Property file name is null
Endpoint address= http://localhost:8080/alfresco/api
### Path= /cm:ABC/cm:Test data/cm:Annaul Report
Endpoint address= http://localhost:8080/alfresco/api
### Path= /cm:ABC/cm:Test data
Endpoint address= http://localhost:8080/alfresco/api
### Path= /cm:ABC
Endpoint address= http://localhost:8080/alfresco/api
Endpoint address= http://localhost:8080/alfresco/api
15-May-2008 23:22:59 CategoryImport createCategory
INFO: creating category:/cm:ABC
Endpoint address= http://localhost:8080/alfresco/api
Endpoint address= http://localhost:8080/alfresco/api
Endpoint address= http://localhost:8080/alfresco/api
Endpoint address= http://localhost:8080/alfresco/api
15-May-2008 23:22:59 CategoryImport createCategory
INFO: creating category:/cm:ABC/cm:Test data
Endpoint address= http://localhost:8080/alfresco/api
### Path= /cm:ABC/cm:Test data
Endpoint address= http://localhost:8080/alfresco/api
Endpoint address= http://localhost:8080/alfresco/api
15-May-2008 23:22:59 CategoryImport createCategory
INFO: creating category:/cm:ABC/cm:Test data
Exception in thread "main" AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.generalException
faultSubcode:
faultString:
faultActor:
faultNode:
faultDetail:
   {http://www.alfresco.org/ws/service/repository/1.0}RepositoryFault:<ns1:errorCode>0</ns1:errorCode><ns1:message>org.alfresco.service.cmr.repository.DuplicateChildNodeNameException: Duplicate child name not allowed: Test data</ns1:message>
   {http://xml.apache.org/axis/}exceptionNameSmiley Surprisedrg.alfresco.repo.webservice.repository.RepositoryFault
   {http://xml.apache.org/axis/}stackTrace:
   at org.alfresco.repo.webservice.repository.RepositoryWebService.update(RepositoryWebService.java:341)
   at sun.reflect.GeneratedMethodAccessor534.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:585)
   at org.apache.axis.providers.java.RPCProvider.invokeMethod(RPCProvider.java:397)
   at org.apache.axis.providers.java.RPCProvider.processMessage(RPCProvider.java:186)
   at org.apache.axis.providers.java.JavaProvider.invoke(JavaProvider.java:323)
   at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
   at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
   at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
   at org.apache.axis.handlers.soap.SOAPService.invoke(SOAPService.java:454)
   at org.apache.axis.server.AxisServer.invoke(AxisServer.java:281)
   at org.apache.axis.transport.http.AxisServlet.doPost(AxisServlet.java:699)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
   at org.apache.axis.transport.http.AxisServletBase.service(AxisServletBase.java:327)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
   at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:210)
   at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
   at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
   at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
   at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
   at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
   at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:870)
   at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
   at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
   at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
   at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:685)
   at java.lang.Thread.run(Thread.java:595)

   {http://xml.apache.org/axis/}hostname:LLDNTECDT06R2J


   at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
   at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
   at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
   at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
   at java.lang.Class.newInstance0(Class.java:350)
   at java.lang.Class.newInstance(Class.java:303)
   at org.apache.axis.encoding.ser.BeanDeserializer.<init>(BeanDeserializer.java:104)
   at org.apache.axis.encoding.ser.BeanDeserializer.<init>(BeanDeserializer.java:90)
   at org.alfresco.webservice.repository.RepositoryFault.getDeserializer(RepositoryFault.java:147)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:585)
   at org.apache.axis.encoding.ser.BaseDeserializerFactory.getSpecialized(BaseDeserializerFactory.java:154)
   at org.apache.axis.encoding.ser.BaseDeserializerFactory.getDeserializerAs(BaseDeserializerFactory.java:84)
   at org.apache.axis.encoding.DeserializationContext.getDeserializer(DeserializationContext.java:464)
   at org.apache.axis.encoding.DeserializationContext.getDeserializerForType(DeserializationContext.java:547)
   at org.apache.axis.message.SOAPFaultDetailsBuilder.onStartChild(SOAPFaultDetailsBuilder.java:157)
   at org.apache.axis.encoding.DeserializationContext.startElement(DeserializationContext.java:1035)
   at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
   at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
   at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
   at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
   at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
   at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source)
   at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
   at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
   at org.apache.axis.Message.getSOAPEnvelope(Message.java:435)
   at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:62)
   at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
   at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
   at org.apache.axis.client.Call.invoke(Call.java:2767)
   at org.apache.axis.client.Call.invoke(Call.java:2443)
   at org.apache.axis.client.Call.invoke(Call.java:2366)
   at org.apache.axis.client.Call.invoke(Call.java:1812)
   at org.alfresco.webservice.repository.RepositoryServiceSoapBindingStub.update(RepositoryServiceSoapBindingStub.java:986)
   at CategoryImport.createCategory(CategoryImport.java:219)
   at CategoryImport.createCategory(CategoryImport.java:177)
   at CategoryImport.createCategory(CategoryImport.java:163)
   at CategoryImport.createCategories(CategoryImport.java:138)
   at CategoryImport.runApp(CategoryImport.java:99)
   at CategoryImport.main(CategoryImport.java:82)


When I removed the space with say "underscore character" everything ran smoothely.

If you could throw some insight into this problem, it would be great help.

Thanks
Kayan.

stevewickii
Champ in-the-making
Champ in-the-making
Good catch Kayan!

The problem is, the code was not detecting that the category "/cm:ABC/cm:Test data" already existed, because Lucene requires that spaces be ISO9075 encoded.  ISO9075 would replace spaces with "_x0020_" in this case.

I modified the code in the original post to handle ISO9075 encoding, and I tested your example.  It looks like the problem is fixed.  Update your code, try importing your categories again, and let me know if you continue to have problems.

Thanks again Kayan!

kayan
Champ in-the-making
Champ in-the-making
Thanks a lot stevewickii.  Its working perfectly now.


Cheers
Kayan

gyro_gearless
Champ in-the-making
Champ in-the-making
FWIW,

i just made a slightly improved version of this tool - this one allows to attach descriptions to categories by appending them with two angleworms:


# Consultant Categories
/cm:Audience/cm:Consultants/cm:Regions/cm:USA/cm:AL
/cm:Audience/cm:Consultants/cm:Regions/cm:USA/cm:AK
/cm:Audience/cm:Consultants/cm:Regions/cm:USA/cm:AS
/cm:Audience/cm:Consultants/cm:Regions/cm:USA/cm:AZ~~Arizona
/cm:Audience/cm:Consultants/cm:Regions/cm:USA/cm:AR
/cm:Audience/cm:Consultants/cm:Regions/cm:USA/cm:CA~~California
/cm:Audience/cm:Consultants/cm:Regions/cm:USA/cm:CO~~Colorado

Here is the modified class:


    package com.nkics.alfrescox.tool;

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.rmi.RemoteException;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    import java.util.Vector;

    import org.alfresco.webservice.authentication.AuthenticationFault;
    import org.alfresco.webservice.repository.QueryResult;
    import org.alfresco.webservice.repository.RepositoryFault;
    import org.alfresco.webservice.types.CML;
    import org.alfresco.webservice.types.CMLCreate;
    import org.alfresco.webservice.types.NamedValue;
    import org.alfresco.webservice.types.ParentReference;
    import org.alfresco.webservice.types.Query;
    import org.alfresco.webservice.types.Reference;
    import org.alfresco.webservice.types.ResultSet;
    import org.alfresco.webservice.types.ResultSetRow;
    import org.alfresco.webservice.types.Store;
    import org.alfresco.webservice.util.AuthenticationUtils;
    import org.alfresco.webservice.util.Constants;
    import org.alfresco.webservice.util.ISO9075;
    import org.alfresco.webservice.util.Utils;
    import org.alfresco.webservice.util.WebServiceFactory;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    /**
    * <pre>
    * Create a Category hierarchy in Alfresco from a plain text file.
    *
    * This Class uses the Alfresco Web Services Client to connect to an Alfresco CMS.
    *
    * <b>Usage:</b> java com.nkics.alfrescox.tool.CategoryImportTool &lt;filename&gt;
    * <ul>filename - the text file containing the categories to be created.</ul>
    *
    * The text file should contain one category path (hierarchy) per line.
    * Each category path is formatted like this: /cm:Parent/cm:SubCategory/cm:SubSubCategory
    * Parent categories that do not exist will be created automatically.
    *
    * This class logs messages using the Common Logging package.
    *
    * Many of the methods in this class were defined in a reusable manner.  In other words, You don't have to execute this class
    * from the command line.  Any of the public methods can be used to leverage all or part of the functionality provided by this tool.
    *
    * For example
    * <ul>
    * <li>To Create a Category: Simply create an instance of CategoryImportTool, and call createCategory(String path).
    * <li>To Create multiple Categories from any source: Simply create an instance of CategoryImportTool, and call createCategories(Collection categories).
    * </pre>
    * @author swick April 22, 2009
    */
    public class CategoryImportTool
    {
       public static final String ALFRESCO_USERNAME_PROPERTY = "repository.username";
       public static final String ALFRESCO_PASSWORD_PROPERTY = "repository.password";
       public static final String ALFRESCO_WEBSERVICECLIENT_PROPERTIES = "/alfresco/webserviceclient.properties";
       /** Delimiter for optional category description */
       public static final String DESCRIPTION_DELIMITER = "~~";

       private static final String ROOT_CATEGORY = "/cm:generalclassifiable";
       private final String SUBCATEGORIES = "subcategories"; // the propertyname of subcategories
       private final String SUBCATEGORIES_Q = Constants.createQNameString(Constants.NAMESPACE_CONTENT_MODEL, SUBCATEGORIES);
       private final String CATEGORY = "category"; // the propertyname of subcategories
       private final String CATEGORY_Q = Constants.createQNameString(Constants.NAMESPACE_CONTENT_MODEL, CATEGORY);
       private final Store STORE = new Store(Constants.WORKSPACE_STORE, "SpacesStore");
       /** Maps Parent Category Paths to Reference objects. Caches Parent Category lookups. **/
       private Map<String,Reference> ROOT_REFERENCE_CACHE = new HashMap<String,Reference>();
       private final Log logger = LogFactory.getLog(getClass());

       /**
        * Invoke the CategoryImportTool from the command line.
        *
        * @param args Command line arguments.  arg[0] should be the filename containing the categories to import.
        */
       public static void main(String[] args) throws Exception
       {
          if (args.length == 0)
             printUsage();

          CategoryImportTool migration = new CategoryImportTool();
          migration.runApp(args[0]);
       }

       /**
        * This method creates an Alfresco Web Service session {@link #setUp()}, reads the categories to
        * import from the filename provided {@link #readCategoriesFromFile(String)}, creates each category,
        * and ends the Alfresco web service session.
        * @param filename is the name of a file on the local filesystem to import.
        * @throws AuthenticationFault if there is a problem creating the Alfresco web service session.  (username/password is invalid, or alfresco/webserviceclient.properties cannot be found or cannot connect to the URL specified)
        * @throws RemoteException - There was a problem querying for or creating a category.
        * @throws IOException - There was a problem reading the import file, the file doesn't exist, or you don't have permission to read the file.
        */
       public void runApp(String filename) throws IOException
       {
          logger.info("Importing categories from "+filename);
          setUp();
          Collection<String> categories = readCategoriesFromFile(filename);
          createCategories(categories);
          tearDown();
          logger.info("Category import completed.");
       }

       /**
        * Read categories from a file into a Collection.
        * This method simply adds each line from the file into the Collection.
        * Blank lines and comments (lines starting with a # character) are ignored (they are not included in the Collection.
        * @param fileName is the full path to a file to open for reading.
        * @return a new Collection of Strings, one per line in the file.
        * @throws IOException if there is a problem reading the filename specified.
        */
       public Collection<String> readCategoriesFromFile(String fileName) throws IOException
       {
          BufferedReader in = new BufferedReader(new FileReader(fileName));
          Vector<String> categories = new Vector<String>();
          String str = null;
          while ((str = in.readLine()) != null)
          {
             if(str.trim().length()==0)
                continue; // skip blank lines
             if(str.trim().startsWith("#"))
                continue; // skip comments starting with the # character

             categories.add(str);
          }
          in.close();
          return categories;
       }

       /**
        * This method loops over the Collection provided and invokes {@link #createCategory(String)}
        * @param categories is a Collection of Strings, where each String is a category path to be created.  example: "/cm:CatA/cm:Cat1/cm:CatI"
        * @throws RemoteException is thrown from {@link #createCategory(String)} if there is a problem creating a category in Alfresco.
        */
       public void createCategories(Collection<String> categories) throws RemoteException
       {
          for (String category : categories)
             createCategory(category);
       }

       /**
        * <pre>
        * Create a Category in Alfresco.  This method will automatically create any parent categories if they do not exist.
        * If the Category already exist, it will be skipped without throwing an exception.
        *
        * The following messages are written using the Common Logging package
        * </pre>
        * <ul>
        * <li><em>category already exists: {path}</em> # Logged at the INFO level if the category already exists.
        * <li><em>creating category: {path}</em> # Logged at the INFO level if the category is being created (it does not exist).
        * </ul>
        * @param pathArg is a Category Path (hierarchy) like "/cm:CatA/cm:Cat1/cm:CatI"
        *        A description may be attached, separated by some well known delimiter (per default ~~)
        * @throws RemoteException from {@link #createCategory(String, ParentReference)} if Alfresco reports a problem creating the category.
        */
       public void createCategory(String pathArg) throws RemoteException
       {
           //
           // Check for optional category description
           //
           String path = pathArg;
           String description = "";
           int delimiterPos = pathArg.indexOf(DESCRIPTION_DELIMITER);
           if (delimiterPos >= 0)
           {
               path = pathArg.substring(0, delimiterPos);
               description = pathArg.substring(delimiterPos+DESCRIPTION_DELIMITER.length());
           }


          // Recursively create parent categories, if necessary.
          Reference rootRef = null;
          String parentCategoryPath = getParentCategoryPath(path);
          while((rootRef=getRootReference(parentCategoryPath))==null)
          {
             createCategory(parentCategoryPath);
          }

          // Make sure the category doesn't already exist in Alfresco.
          if(getCategory(path)!=null)
          {
             logger.info("category already exists: "+path);
             return;
          }

          // Create the category.
          logger.info("creating category:" + path + " with description '" + description + "'");
          String childCategoryName = getChildCategoryName(path);
          ParentReference parentRef = new ParentReference(STORE, rootRef.getUuid(), null, SUBCATEGORIES_Q, Constants.createQNameString(Constants.NAMESPACE_CONTENT_MODEL, childCategoryName));
          createCategory(childCategoryName, parentRef, description);
       }

       /**
        * Get the Parent categories from the category path provided.
        *
        * @param path a Category path like "/cm:CatA/cm:Cat1/cm:CatI"
        * @return all text up to the last / character, or null if there is no / character in the path provided.  ie: "/cm:CatA/cm:Cat1"
        */
       protected String getParentCategoryPath(String path)
       {
          if(path.lastIndexOf("/")<=0)
             return null;

          return path.substring(0, path.lastIndexOf("/"));
       }

       /**
        * Get the child category name from the category path provided.
        *
        * @param path a Category path like "/cm:CatA/cm:Cat1/cm:CatI"
        * @return all text from the last "/cm:" character sequence to the end of the path.  ie: "CatI"
        */
       protected String getChildCategoryName(String path)
       {
          return path.substring(path.lastIndexOf("/cm:")+4); // get the last category and strip off the "/cm:".
       }

       /**
        * Actually create the Category described by the parentRef and categoryName provided
        * @param categoryName is just the Name of the category to be created, without a namespace.  ie: "CatI"
        * @param parentRef is a reference to the parent category.  ie: "/cm:CatA/cm:Cat1"
        * @param description (optional) description to attach to new category
        * @throws RemoteException
        */
       protected void createCategory(String categoryName, ParentReference parentRef, String description) throws RemoteException
       {
          NamedValue[] properties = new NamedValue[]
          {
              Utils.createNamedValue(Constants.PROP_NAME, categoryName),
              Utils.createNamedValue(Constants.PROP_DESCRIPTION, String.valueOf(description))
          };

          CMLCreate create = new CMLCreate("1", parentRef, null, null, null, CATEGORY_Q, properties);
          CML cml = new CML();
          cml.setCreate(new CMLCreate[] { create });

          WebServiceFactory.getRepositoryService().update(cml);
       }

       /**
        * Get the Parent Category specified.  Root Categories are cached to improve performance and reduce load on the Alfresco server.
        * @param parentCategoryPath is a path relative to /cm:generalclassifiable (ROOT_CATEGORY).  Can be null, in which case ROOT_CATEGORY is returned.
        * @return a Reference to the Root Category
        * @throws RemoteException if {@link #getCategory(String)} throws this exception.
        * @throws RepositoryFault if {@link #getCategory(String)} throws this exception.
        * @see getCategory(String)
        */
       private Reference getRootReference(String parentCategoryPath) throws RepositoryFault, RemoteException
       {
          // Return Cached Reference, if available.
          if(ROOT_REFERENCE_CACHE.containsKey(parentCategoryPath))
             return ROOT_REFERENCE_CACHE.get(parentCategoryPath);

          // Get the Category from Alfresco, cache it, and return it.
          Reference r = getCategory(parentCategoryPath);
          if(r!=null)
             ROOT_REFERENCE_CACHE.put(parentCategoryPath, r); // Add Reference to cache.
          return r;
       }

       /**
        * Get a Category from Alfresco.
        * @param categoryPath is a path relative to /cm:generalclassifiable (ROOT_CATEGORY).  Can be null, in which case /cm:generalclassifiable is returned.
        * @return a Reference to the Category requested, or null if the category doesn't exist.
        * @throws RemoteException
        * @throws RepositoryFault
        */
       public Reference getCategory(String categoryPath) throws RepositoryFault, RemoteException
       {
          String luceneQueryString = "PATH:\""+ROOT_CATEGORY+(categoryPath==null?"":encodeCategoryPath(categoryPath))+"\"";
          Query query = new Query(Constants.QUERY_LANG_LUCENE, luceneQueryString);

          QueryResult result = WebServiceFactory.getRepositoryService().query(STORE, query, true);
          ResultSet rs = result.getResultSet();
          if(rs.getTotalRowCount()==0)
             return null;
          ResultSetRow[] rows = rs.getRows();
          String uuid = rows[0].getNode().getId();
          return new Reference(STORE, uuid, null);
       }

       /**
        * Apply ISO9075 encoding to the Category Path provided.
        *
        * @param categoryPath is a String like "/cm:Sports/cm:Water Polo"
        * @return the categoryPath provided with ISO9075 encoding applied to each category in the path, like "/cm:Sports/cm:Water_x0020_Polo".
        */
       public static final String encodeCategoryPath(String categoryPath)
       {
          categoryPath = categoryPath.substring(4); // Strip off the leading '/cm:'
          String[] categories = categoryPath.split("/cm:"); // Split the category path by the remaining '/cm:' strings.
          StringBuffer encodedCategoryPath = new StringBuffer();
          for(String category : categories)
          {
             encodedCategoryPath.append("/cm:");
             encodedCategoryPath.append(ISO9075.encode(category));
          }
          return encodedCategoryPath.toString();
       }

       /**
        * Creates an Alfresco web service session.  Called by {@link #runApp(String)}.
        * <p>
        * By default the username and password are "admin".  The default values can be overridden by adding the {@link #ALFRESCO_USERNAME_PROPERTY}
        * and {@link #ALFRESCO_PASSWORD_PROPERTY} to the {@link #ALFRESCO_WEBSERVICECLIENT_PROPERTIES} file, or by
        * specifying these properties on the Java command line with the "-D" command line argument.  System properties will take precedence
        * over {@link #ALFRESCO_WEBSERVICECLIENT_PROPERTIES}.
        * @see #ALFRESCO_USERNAME_PROPERTY
        * @see #ALFRESCO_PASSWORD_PROPERTY
        * @see #ALFRESCO_WEBSERVICECLIENT_PROPERTIES
        * @throws AuthenticationFault if there is a problem logging into the Alfresco web service with the username and password provided.
        * @throws IOException if there is a problem reading ALFRESCO_WEBSERVICECLIENT_PROPERTIES from the classloader.
        */
       public void setUp() throws AuthenticationFault, IOException
       {
          // Set the Default values.
          String username = "admin";
          String password = "admin";

          // Attempt to read the username and password from the Alfresco web service client properties file.
          InputStream is = getClass().getResourceAsStream(ALFRESCO_WEBSERVICECLIENT_PROPERTIES);
          if(is!=null)
          {
             Properties properties = new Properties();
             properties.load(is);
             username = getUsername(properties, username);
             password = getPassword(properties, password);
          }

          // Attempt to read the username and password from the System properties.
          username = getUsername(System.getProperties(), username);
          password = getPassword(System.getProperties(), password);

          logger.info("creating Alfresco web service client session with username '"+username+"' and password '"+password+"'.");

          AuthenticationUtils.startSession(username, password);
       }

       protected String getUsername(Properties p, String originalValue)
       {
          if(p.containsKey(ALFRESCO_USERNAME_PROPERTY))
             return p.getProperty(ALFRESCO_USERNAME_PROPERTY);
          return originalValue;
       }

       protected String getPassword(Properties p, String originalValue)
       {
          if(p.containsKey(ALFRESCO_PASSWORD_PROPERTY))
             return p.getProperty(ALFRESCO_PASSWORD_PROPERTY);
          return originalValue;
       }

       /**
        * Ends the Alfresco web service session.  Called by {@link #runApp(String)}.
        */
       public void tearDown()
       {
          AuthenticationUtils.endSession();
       }

       protected static void printUsage()
       {
          System.out.println("java "+CategoryImportTool.class.getName()+" <filename>");
       }
    }


Great little tool, BTW!

Cheers
Gyro

cristian
Champ in-the-making
Champ in-the-making
..would be better exporting an xml output from the alfresco explorer, I think. An importing step of the exported xml file could enclose this feature (like alfresco does with spaces in *.acp files). Maybe categorization could be used widely trough different repositories.
Just an opinion.

piski
Champ on-the-rise
Champ on-the-rise
Hi all,

We want to do the same thing as you but I'm not very familiar with java & compilation.

I've already read tutorials about development and how to compile Java but it seems to be more difficult than I thought !

I've tried to use directly the cmd below :
javac -verbose CategoryImportTool.java_Full_Path

There are errors on "imports" java class because I probably don't tell Java where are the dependencies … and other stuffs maybe

If there is a "great soul" to tell me, step by step, how to compile this Java file … I'd really like to use your tool !

Thank you so much for your help !

piski
Champ on-the-rise
Champ on-the-rise
I have almost reached my goal, I'm close to it !

I have downloaded :
Eclipse 3.6
AlfrescoSDK 3.3
JDK 1.6.0_17 (already installed with Alfresco 3.3 Community)

I have added, within SDK FirstWebServiceClient/org.alfresco.sample the file CategoryImportTool.java
I have created a file CategoryImportTool.txt with my custom categories to import into Alfresco

When I run the program from Eclipse, it creates very well my categories … great !

I can build the project without errors and everything goes … I create the jar file with cmd :
C:\AlfrescoSDK\samples\FirstWebServiceClient\build>jar -cvf C:\CategoryImportTool.jar *.*

The jar file is correctly created and, when I open it, the content is :
/alfresco … webserviceclient.properties
/META-INF … MANIFEST.MF
/org … /alfresco/sample/CategoryImportTool.class and /alfresco/sample/FirstWebServiceClient.class

When I try to launch the jar, with cmd :
java -jar C:\CategoryImportTool.jar C:\CategoryImportTool.txt

I get this error :
C:\AlfrescoSDK\samples\FirstWebServiceClient\build>java -jar C:\CategoryImportTool.jar C:\CategoryImportTool.txt
Failed to load Main-Class manifest attribute from C:\CategoryImportTool.jar

So I've added, within the jar, into the file MANIFEST.MF, the line
Main-Class: CategoryImportTool
.

Now I get this error and I don't know how to get rid of it :
C:\AlfrescoSDK\samples\FirstWebServiceClient\build>java -jar C:\CategoryImportTool.jar C:\CategoryImportTool.txt
Exception in thread "main" java.lang.NoClassDefFoundError: CategoryImportTool
Caused by: java.lang.ClassNotFoundException: CategoryImportTool
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
Could not find the main class: CategoryImportTool. Program will exit.

… OK I build, from Eclipse, with ant my build.xml file and I make the JAR through ant by using cmd
ant jar

My build.xml :
<?xml version="1.0"?>

<project name="First Web Service Client" default="compile" basedir=".">
   
   <property name="project.dir" value="."/>
   <property name="build.dir" value="${project.dir}/build"/>
   
   <path id="class.path">
      <dirset dir="${build.dir}" />
      <fileset dir="../../lib/remote" includes="**/*.jar"/>
   </path>
  
   <target name="compile">
      <mkdir dir="${build.dir}" />
      <javac classpathref="class.path" srcdir="${project.dir}/source" destdir="${build.dir}" />
   </target>

   <target name="jar" depends="compile">
      <delete file="CategoryImportTool.jar"/>
      <delete file="MANIFEST.MF"/>
      <manifest file="MANIFEST.MF">
          <attribute name="Built-By" value="${user.name}"/>
          <attribute name="Main-Class" value="org.alfresco.sample.CategoryImportTool"/>
        </manifest>
      <jar destfile="CategoryImportTool.jar"
         basedir="build/."
         includes="**/*.class,**/*.properties"
          manifest="MANIFEST.MF"
      />
   </target>
   
</project>   

Everything is OK (without errors) but when I run my JAR, I get these errors …

C:\AlfrescoSDK\samples\FirstWebServiceClient>java -jar CategoryImportTool.jar C:
\CategoryImportTool.txt
Exception in thread "main" java.lang.NoClassDefFoundError: org/alfresco/webservi
ce/util/Constants
        at org.alfresco.sample.CategoryImportTool.<init>(CategoryImportTool.java
:69)
        at org.alfresco.sample.CategoryImportTool.main(CategoryImportTool.java:8
7)
Caused by: java.lang.ClassNotFoundException: org.alfresco.webservice.util.Consta
nts
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
        … 2 more

Please someone could help me !

piski
Champ on-the-rise
Champ on-the-rise
I've finally made it !

My categoryimporttool.jar works standalone (by import jar dependencies) … Great !

I can run it with cmd below :
java -jar categoryimporttool.jar categoryimporttool.txt

Now, I want to deploy my jar within Alfresco. I've read here (http://wiki.alfresco.com/wiki/Packaging_And_Deploying_Extensions#Tomcat) that I have to copy my file in <tomcat-home>/webapps/alfresco/WEB-INF/lib and restart Tomcat.

I want, if it's possible, to execute the jar from any Alfresco client (which has not the JDK installed) …
How to do this ? by Webscripts available through http:// ?

Thanks for your help !

shubhada
Champ in-the-making
Champ in-the-making
The above code helped to automate creation of categories. Category is having Name and description fields.I am trying to add another property field like Title or other custom properties to the category. 
Can anyone suggest me how to proceed for this implementation.?

Thank you
Getting started

Tags


Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.