jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r711238 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/ main/java/org/apache/jackrabbit/core/cluster/ main/java/org/apache/jackrabbit/core/config/ main/java/org/apache/jackrabbit/core/xml/ test/java/org/apa...
Date Tue, 04 Nov 2008 12:20:58 GMT
Author: jukka
Date: Tue Nov  4 04:20:58 2008
New Revision: 711238

URL: http://svn.apache.org/viewvc?rev=711238&view=rev
Log:
JCR-1677: Allow workspace creation over cluster

Patch by Matej Knopp

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceEventChannel.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceListener.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceRecord.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ClonedInputSource.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordDeserializer.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordProcessor.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/RepositoryConfigTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=711238&r1=711237&r2=711238&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
Tue Nov  4 04:20:58 2008
@@ -27,6 +27,8 @@
 import org.apache.jackrabbit.core.cluster.ClusterContext;
 import org.apache.jackrabbit.core.cluster.ClusterException;
 import org.apache.jackrabbit.core.cluster.ClusterNode;
+import org.apache.jackrabbit.core.cluster.WorkspaceEventChannel;
+import org.apache.jackrabbit.core.cluster.WorkspaceListener;
 import org.apache.jackrabbit.core.cluster.LockEventChannel;
 import org.apache.jackrabbit.core.cluster.UpdateEventChannel;
 import org.apache.jackrabbit.core.cluster.UpdateEventListener;
@@ -64,6 +66,7 @@
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.version.VersionManagerImpl;
+import org.apache.jackrabbit.core.xml.ClonedInputSource;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
 import org.apache.jackrabbit.spi.commons.namespace.RegistryNamespaceResolver;
@@ -89,6 +92,7 @@
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.StringReader;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.util.Arrays;
@@ -103,7 +107,7 @@
  * A <code>RepositoryImpl</code> ...
  */
 public class RepositoryImpl extends AbstractRepository
-        implements JackrabbitRepository, SessionListener, EventListener {
+        implements JackrabbitRepository, SessionListener, EventListener, WorkspaceListener
{
 
     private static Logger log = LoggerFactory.getLogger(RepositoryImpl.class);
 
@@ -230,6 +234,11 @@
     private final ItemStateCacheFactory cacheFactory = new ManagedMLRUItemStateCacheFactory(cacheMgr);
 
     /**
+     * Chanel for posting create workspace messages.
+     */
+    private WorkspaceEventChannel createWorkspaceEventChannel;
+
+    /**
      * private constructor
      *
      * @param repConfig
@@ -292,6 +301,9 @@
                 clusterNode = createClusterNode();
                 nsReg.setEventChannel(clusterNode);
                 ntReg.setEventChannel(clusterNode);
+                
+                createWorkspaceEventChannel = clusterNode;
+                clusterNode.setListener(this);
             }
 
             // init version manager
@@ -789,16 +801,35 @@
                         + workspaceName + "' already exists.");
             }
 
+            // needed to get newly created workspace config file content when runnin in clustered
environment
+            StringBuffer workspaceConfigContent = clusterNode != null ? new StringBuffer()
: null;
+
             // create the workspace configuration
-            WorkspaceConfig config = repConfig.createWorkspaceConfig(workspaceName);
+            WorkspaceConfig config = repConfig.createWorkspaceConfig(workspaceName, workspaceConfigContent);
             WorkspaceInfo info = createWorkspaceInfo(config);
             wspInfos.put(workspaceName, info);
+
+            if (workspaceConfigContent != null && createWorkspaceEventChannel !=
null) {
+                // notify other cluster node that workspace has been created
+                InputSource s = new InputSource(new StringReader(workspaceConfigContent.toString()));
+                createWorkspaceEventChannel.workspaceCreated(workspaceName, new ClonedInputSource(s));
+            }
         }
     }
 
+    public void externalWorkspaceCreated(String workspaceName,
+            InputSource configTemplate) throws RepositoryException {
+
+        createWorkspaceInternal(workspaceName, configTemplate);
+    }
+
     /**
      * Creates a workspace with the given name and given workspace configuration
      * template.
+     * 
+     * The difference between this method and {@link #createWorkspace(String, InputSource)}
+     * is that the later notifies the other cluster node that workspace has been created
+     * whereas this method only creates the workspace.
      *
      * @param workspaceName  name of the new workspace
      * @param configTemplate the workspace configuration template of the new
@@ -807,7 +838,7 @@
      *                             exists or if another error occurs
      * @see SessionImpl#createWorkspace(String,InputSource)
      */
-    protected void createWorkspace(String workspaceName,
+    private void createWorkspaceInternal(String workspaceName,
                                    InputSource configTemplate)
             throws RepositoryException {
         synchronized (wspInfos) {
@@ -822,6 +853,32 @@
             wspInfos.put(workspaceName, info);
         }
     }
+    
+    /**
+     * Creates a workspace with the given name and given workspace configuration
+     * template.
+     *
+     * @param workspaceName  name of the new workspace
+     * @param configTemplate the workspace configuration template of the new
+     *                       workspace
+     * @throws RepositoryException if a workspace with the given name already
+     *                             exists or if another error occurs
+     * @see SessionImpl#createWorkspace(String,InputSource)
+     */
+    protected void createWorkspace(String workspaceName,
+                                   InputSource configTemplate)
+            throws RepositoryException {
+
+        if (createWorkspaceEventChannel == null) {
+            createWorkspaceInternal(workspaceName, configTemplate);
+        }
+        else {
+        
+            ClonedInputSource template = new ClonedInputSource(configTemplate);
+            createWorkspaceInternal(workspaceName, template.cloneInputSource());
+            createWorkspaceEventChannel.workspaceCreated(workspaceName, template);
+        }
+    }
 
     SharedItemStateManager getWorkspaceStateManager(String workspaceName)
             throws NoSuchWorkspaceException, RepositoryException {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java?rev=711238&r1=711237&r2=711238&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
Tue Nov  4 04:20:58 2008
@@ -16,43 +16,45 @@
  */
 package org.apache.jackrabbit.core.cluster;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
 import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.cluster.WorkspaceRecord.CreateWorkspaceAction;
 import org.apache.jackrabbit.core.config.ClusterConfig;
 import org.apache.jackrabbit.core.config.ConfigurationException;
 import org.apache.jackrabbit.core.config.JournalConfig;
-import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.journal.AbstractJournal;
+import org.apache.jackrabbit.core.journal.InstanceRevision;
 import org.apache.jackrabbit.core.journal.Journal;
-import org.apache.jackrabbit.core.journal.RecordConsumer;
-import org.apache.jackrabbit.core.journal.Record;
 import org.apache.jackrabbit.core.journal.JournalException;
-import org.apache.jackrabbit.core.journal.InstanceRevision;
+import org.apache.jackrabbit.core.journal.Record;
+import org.apache.jackrabbit.core.journal.RecordConsumer;
 import org.apache.jackrabbit.core.journal.RecordProducer;
 import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
 import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
 import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.xml.ClonedInputSource;
 import org.apache.jackrabbit.uuid.UUID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import EDU.oswego.cs.dl.util.concurrent.Latch;
 import EDU.oswego.cs.dl.util.concurrent.Mutex;
 
-import javax.jcr.RepositoryException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Collection;
-
 /**
  * Default clustered node implementation.
  */
 public class ClusterNode implements Runnable,
         NamespaceEventChannel, NodeTypeEventChannel, RecordConsumer,
-        ClusterRecordProcessor  {
+        ClusterRecordProcessor, WorkspaceEventChannel  {
 
     /**
      * System property specifying a node id to use.
@@ -70,11 +72,6 @@
     private static final String PRODUCER_ID = "JR";
 
     /**
-     * Default stop delay.
-     */
-    private static final long DEFAULT_STOP_DELAY = 5000;
-
-    /**
      * Status constant.
      */
     private static final int NONE = 0;
@@ -160,6 +157,11 @@
     private NamespaceEventListener namespaceListener;
 
     /**
+     * Create workspace listener
+     */
+    private WorkspaceListener createWorkspaceListener;
+    
+    /**
      * Node type listener.
      */
     private NodeTypeEventListener nodeTypeListener;
@@ -939,6 +941,58 @@
         }
     }
 
+    public void process(WorkspaceRecord record) {
+        if (createWorkspaceListener == null) {
+            String msg = "Create Workspace listener unavailable.";
+            log.error(msg);
+            return;
+        }
+        try {
+            if (record.getActionType() == WorkspaceRecord.CREATE_WORKSPACE_ACTION_TYPE) {
+                CreateWorkspaceAction action = record.getCreateWorkspaceAction();
+                createWorkspaceListener.externalWorkspaceCreated(record.getWorkspace(), action.getInputSource());
+            }
+        } catch (RepositoryException e) {
+            String msg = "Unable to create workspace: "
+                    + e.getMessage();
+            log.error(msg);
+        }
+    }
+
+    // -----------------------------------------------< CreateWorkspaceChannel >
+
+    public void setListener(WorkspaceListener listener) {
+        createWorkspaceListener = listener;
+    }
+
+    public void workspaceCreated(String workspaceName,
+            ClonedInputSource inputSource) {
+        if (status != STARTED) {
+            log.info("not started: namespace operation ignored.");
+            return;
+        }
+        ClusterRecord record = null;
+        boolean succeeded = false;
+
+        try {
+            record = new WorkspaceRecord(workspaceName, inputSource, producer.append());
+            record.write();
+            record.update();
+            setRevision(record.getRevision());
+            succeeded = true;
+        } catch (JournalException e) {
+            String msg = "Unable to create log entry: " + e.getMessage();
+            log.error(msg);
+        } catch (Throwable e) {
+            String msg = "Unexpected error while creating log entry.";
+            log.error(msg, e);
+        } finally {
+            if (!succeeded && record != null) {
+                record.cancelUpdate();
+            }
+        }
+    }
+
     /**
      * Invoked when a cluster operation has ended. If <code>successful</code>,
      * attempts to fill the journal record and update it, otherwise cancels

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordDeserializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordDeserializer.java?rev=711238&r1=711237&r2=711238&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordDeserializer.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordDeserializer.java
Tue Nov  4 04:20:58 2008
@@ -55,6 +55,10 @@
             clusterRecord = new NodeTypeRecord(record);
             clusterRecord.read();
             break;
+        case WorkspaceRecord.IDENTIFIER:
+            clusterRecord = new WorkspaceRecord(record);
+            clusterRecord.read();
+            break;
         case ClusterRecord.END_MARKER:
             // JCR-1813: Invalid journal records during XATransactions
             // Some journal records may be empty due to JCR-1813 and other

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordProcessor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordProcessor.java?rev=711238&r1=711237&r2=711238&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordProcessor.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterRecordProcessor.java
Tue Nov  4 04:20:58 2008
@@ -52,4 +52,11 @@
      * @param record node type record
      */
     public void process(NodeTypeRecord record);
+
+    /**
+     * Process a workspace record
+     * @param record workspace record
+     */
+    public void process(WorkspaceRecord record);
+
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceEventChannel.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceEventChannel.java?rev=711238&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceEventChannel.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceEventChannel.java
Tue Nov  4 04:20:58 2008
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.cluster;
+
+import org.apache.jackrabbit.core.xml.ClonedInputSource;
+
+/**
+ * Event channel for reporting workspace change events.
+ */
+public interface WorkspaceEventChannel {
+
+    void workspaceCreated(String workspaceName, ClonedInputSource inputSource);
+
+    void setListener(WorkspaceListener listener);
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceListener.java?rev=711238&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceListener.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceListener.java
Tue Nov  4 04:20:58 2008
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.cluster;
+
+import javax.jcr.RepositoryException;
+
+import org.xml.sax.InputSource;
+
+/**
+ * Listener for external workspace changes.
+ */
+public interface WorkspaceListener {
+
+    /**
+     * Workspace created on another cluster node.
+     * 
+     * @param workspaceName
+     * @param configTemplate
+     * @throws RepositoryException
+     */
+    public void externalWorkspaceCreated(String workspaceName,
+            InputSource configTemplate) throws RepositoryException;
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceRecord.java?rev=711238&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceRecord.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/WorkspaceRecord.java
Tue Nov  4 04:20:58 2008
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.cluster;
+
+import java.io.ByteArrayInputStream;
+import java.io.CharArrayReader;
+
+import org.apache.jackrabbit.core.journal.JournalException;
+import org.apache.jackrabbit.core.journal.Record;
+import org.apache.jackrabbit.core.xml.ClonedInputSource;
+import org.xml.sax.InputSource;
+
+/**
+ * Record for propagating workspace modifications across the cluster. Currently
+ * only workspace creation is propagated because workspace deletion is not yet
+ * implemented.
+ */
+public class WorkspaceRecord extends ClusterRecord {
+
+    /**
+     * Identifier: NAMESPACE.
+     */
+    static final char IDENTIFIER = 'W';
+
+    /**
+     * Subtype for determining workspace action.
+     */
+    public static final int CREATE_WORKSPACE_ACTION_TYPE = 1;
+
+    /**
+     * Base workspace action
+     */
+    public static abstract class Action {
+        abstract int getType();
+
+        abstract void write(Record record) throws JournalException;
+
+        abstract void read(Record record) throws JournalException;
+    }
+
+    /**
+     * Action for workspace creation.
+     */
+    static final class CreateWorkspaceAction extends Action {
+        private InputSource inputSource;
+        private char charArray[];
+        private byte byteArray[];
+
+        int getType() {
+            return CREATE_WORKSPACE_ACTION_TYPE;
+        }
+
+        CreateWorkspaceAction() {
+
+        }
+
+        CreateWorkspaceAction(ClonedInputSource inputSource) {
+            this.inputSource = inputSource;
+            this.charArray = inputSource.getCharacterArray();
+            this.byteArray = inputSource.getByteArray();
+        }
+
+        void write(Record record) throws JournalException {
+            // store the input source
+            record.writeString(inputSource.getEncoding());
+            record.writeString(inputSource.getPublicId());
+            record.writeString(inputSource.getSystemId());
+
+            // save character array if present
+            if (charArray != null) {
+                record.writeBoolean(true);
+                record.writeString(new String(charArray));
+            } else {
+                record.writeBoolean(false);
+            }
+
+            // save the bytearray if present
+            if (byteArray != null) {
+                record.writeBoolean(true);
+                record.writeInt(byteArray.length);
+                record.write(byteArray);
+            } else {
+                record.writeBoolean(false);
+            }
+        }
+
+        void read(Record record) throws JournalException {
+            // restore the input source
+            inputSource = new InputSource();
+            inputSource.setEncoding(record.readString());
+            inputSource.setPublicId(record.readString());
+            inputSource.setSystemId(record.readString());
+
+            if (record.readBoolean()) {
+                charArray = record.readString().toCharArray();
+                inputSource.setCharacterStream(new CharArrayReader(charArray));
+            }
+            if (record.readBoolean()) {
+                final int size = record.readInt();
+                byteArray = new byte[size];
+                record.readFully(byteArray);
+                inputSource.setByteStream(new ByteArrayInputStream(byteArray));
+            }
+        }
+
+        public InputSource getInputSource() {
+            return inputSource;
+        }
+    }
+
+    // current action
+    private Action action;
+
+    /**
+     * Creates a new {@link WorkspaceRecord} for create workspace action.
+     * 
+     * @param workspace
+     *            workspace name
+     * @param inputSource
+     *            input source with configuration for the workspace
+     * @param record
+     *            journal record
+     */
+    protected WorkspaceRecord(String workspace, ClonedInputSource inputSource,
+            Record record) {
+        super(record, workspace);
+
+        action = new CreateWorkspaceAction(inputSource);
+    }
+
+    /**
+     * Creates a new empty {@link WorkspaceRecord}.
+     * 
+     * @param record
+     */
+    protected WorkspaceRecord(Record record) {
+        super(record);
+    }
+
+    protected void doRead() throws JournalException {
+
+        workspace = record.readString();
+
+        // determine type
+        int action = record.readInt();
+
+        if (action == CREATE_WORKSPACE_ACTION_TYPE) {
+            this.action = new CreateWorkspaceAction();
+        }
+
+        if (this.action != null) {
+            this.action.read(record);
+        } else {
+            throw new JournalException("Unknown workspace action type");
+        }
+    }
+
+    protected void doWrite() throws JournalException {
+
+        record.writeChar(IDENTIFIER);
+
+        record.writeString(workspace);
+
+        // store the type
+        record.writeInt(getActionType());
+
+        if (action != null) {
+            action.write(record);
+        } else {
+            throw new JournalException("Can not write empty workspace action");
+        }
+    }
+
+    public int getActionType() {
+        return action != null ? action.getType() : -1;
+    }
+
+    public CreateWorkspaceAction getCreateWorkspaceAction() {
+        return (CreateWorkspaceAction) action;
+    }
+
+    public void process(ClusterRecordProcessor processor) {
+        processor.process(this);
+    }
+
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java?rev=711238&r1=711237&r2=711238&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java
Tue Nov  4 04:20:58 2008
@@ -23,6 +23,7 @@
 import org.apache.jackrabbit.core.fs.FileSystemException;
 import org.apache.jackrabbit.core.fs.FileSystemFactory;
 import org.apache.jackrabbit.core.fs.FileSystemPathUtil;
+import org.apache.jackrabbit.core.xml.ClonedInputSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Element;
@@ -45,6 +46,8 @@
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
 import java.io.Writer;
 import java.net.URI;
 import java.util.Collection;
@@ -340,7 +343,7 @@
                         + "for default workspace: " + defaultWorkspace);
             }
             // create initial default workspace
-            createWorkspaceConfig(defaultWorkspace);
+            createWorkspaceConfig(defaultWorkspace, (StringBuffer)null);
         }
     }
 
@@ -460,12 +463,15 @@
      *
      * @param name workspace name
      * @param template the workspace template
+     * @param configContent optional stringbuffer that will have the content
+     *        of workspace configuration file written in
      * @return created workspace configuration
      * @throws ConfigurationException if creating the workspace configuration
      *                                failed
      */
     private synchronized WorkspaceConfig internalCreateWorkspaceConfig(String name,
-                                                                       Element template)
+                                                                       Element template,
+                                                                       StringBuffer configContent)
             throws ConfigurationException {
 
         // The physical workspace home directory on disk (TODO encode name?)
@@ -511,6 +517,7 @@
                 try {
                     // Create the directory
                     virtualFS.createFolder(configDir);
+
                     configWriter = new OutputStreamWriter(
                             virtualFS.getOutputStream(configFile));
                 } catch (FileSystemException e) {
@@ -537,8 +544,25 @@
                 TransformerFactory factory = TransformerFactory.newInstance();
                 Transformer transformer = factory.newTransformer();
                 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-                transformer.transform(
-                        new DOMSource(template), new StreamResult(configWriter));
+
+                if (configContent == null)
+                {
+                    transformer.transform(
+                            new DOMSource(template), new StreamResult(configWriter));
+                }
+                else
+                {
+                    StringWriter writer = new StringWriter();
+                    transformer.transform(
+                            new DOMSource(template), new StreamResult(writer));
+
+                    String s = writer.getBuffer().toString();
+                    configWriter.write(s);
+                    configContent.append(s);
+                }
+            } catch (IOException e) {
+                throw new ConfigurationException(
+                        "Cannot create a workspace configuration file", e);
             } catch (TransformerConfigurationException e) {
                 throw new ConfigurationException(
                         "Cannot create a workspace configuration writer", e);
@@ -585,14 +609,16 @@
      * the caller.
      *
      * @param name workspace name
+     * @param configContent optional StringBuffer that will have the content
+     *        of workspace configuration file written in
      * @return created workspace configuration
      * @throws ConfigurationException if creating the workspace configuration
      *                                failed
      */
-    public WorkspaceConfig createWorkspaceConfig(String name)
+    public WorkspaceConfig createWorkspaceConfig(String name, StringBuffer configContent)
             throws ConfigurationException {
         // use workspace template from repository.xml
-        return internalCreateWorkspaceConfig(name, template);
+        return internalCreateWorkspaceConfig(name, template, configContent);
     }
 
     /**
@@ -618,7 +644,7 @@
             throws ConfigurationException {
         ConfigurationParser parser = new ConfigurationParser(new Properties());
         Element workspaceTemplate = parser.parseXML(template);
-        return internalCreateWorkspaceConfig(name, workspaceTemplate);
+        return internalCreateWorkspaceConfig(name, workspaceTemplate, null);
     }
 
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ClonedInputSource.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ClonedInputSource.java?rev=711238&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ClonedInputSource.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/ClonedInputSource.java
Tue Nov  4 04:20:58 2008
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.xml;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import javax.jcr.RepositoryException;
+
+import org.xml.sax.InputSource;
+
+/**
+ * Input source that clones existing input source. After cloning the existing
+ * input source should not be used anymore. To make more copies call
+ * {@link #cloneInputSource()} method.
+ */
+public class ClonedInputSource extends InputSource {
+    private final char characterArray[];
+    private final byte byteArray[];
+
+    /**
+     * Clone existing input source.
+     * 
+     * @param input
+     * @throws RepositoryException
+     */
+    public ClonedInputSource(InputSource input) throws RepositoryException {
+
+        if (input == null) {
+            throw new IllegalArgumentException(
+                    "Argument 'input' may not be null.");
+        }
+
+        characterArray = read(input.getCharacterStream());
+        byteArray = read(input.getByteStream());
+
+        setEncoding(input.getEncoding());
+        setPublicId(input.getPublicId());
+        setSystemId(input.getSystemId());
+        if (characterArray != null) {
+            setCharacterStream(new CharArrayReader(characterArray));
+        }
+        if (byteArray != null) {
+            setByteStream(new ByteArrayInputStream(byteArray));
+        }
+    }
+
+    private ClonedInputSource(char characterArray[], byte byteArray[]) {
+        super();
+        this.characterArray = characterArray;
+        this.byteArray = byteArray;
+    }
+
+    public char[] getCharacterArray() {
+        return characterArray;
+    }
+
+    public byte[] getByteArray() {
+        return byteArray;
+    }
+
+    /**
+     * Make a clone if this input source. The input source being cloned is still
+     * valid after cloning.
+     * 
+     * @return input source clone.
+     */
+    public ClonedInputSource cloneInputSource() {
+
+        ClonedInputSource res = new ClonedInputSource(characterArray, byteArray);
+
+        res.setEncoding(getEncoding());
+        res.setPublicId(getPublicId());
+        res.setSystemId(getSystemId());
+
+        if (byteArray != null) {
+            res.setByteStream(new ByteArrayInputStream(byteArray));
+        }
+        if (characterArray != null) {
+            res.setCharacterStream(new CharArrayReader(characterArray));
+        }
+
+        return res;
+    }
+
+    private static byte[] read(InputStream stream) throws RepositoryException {
+        if (stream != null) {
+            try {
+                final int bufferSize = Math.min(stream.available(), 4096);
+                ByteArrayOutputStream s = new ByteArrayOutputStream(bufferSize);
+
+                byte buffer[] = new byte[bufferSize];
+                while (true) {
+                    int numRead = stream.read(buffer);
+                    if (numRead > 0) {
+                        s.write(buffer, 0, numRead);
+                    }
+                    if (numRead != bufferSize) {
+                        break;
+                    }
+                }
+
+                return s.toByteArray();
+            } catch (IOException e) {
+                throw new RepositoryException(e);
+            } finally {
+                try {
+                    stream.close();
+                } catch (IOException ignore) {
+
+                }
+            }
+        } else {
+            return null;
+        }
+    }
+
+    private static char[] read(Reader reader) throws RepositoryException {
+        if (reader != null) {
+            try {
+                final int bufferSize = 4096;
+                CharArrayWriter w = new CharArrayWriter(bufferSize);
+
+                char buffer[] = new char[bufferSize];
+                while (true) {
+                    int numRead = reader.read(buffer);
+                    if (numRead > 0) {
+                        w.write(buffer, 0, numRead);
+                    }
+                    if (numRead != bufferSize) {
+                        break;
+                    }
+                }
+                return w.toCharArray();
+            } catch (IOException e) {
+                throw new RepositoryException(e);
+            } finally {
+                try {
+                    reader.close();
+                } catch (IOException ignore) {
+
+                }
+            }
+        } else {
+            return null;
+        }
+
+    }
+}
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/RepositoryConfigTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/RepositoryConfigTest.java?rev=711238&r1=711237&r2=711238&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/RepositoryConfigTest.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/RepositoryConfigTest.java
Tue Nov  4 04:20:58 2008
@@ -220,7 +220,7 @@
     public void testCreateWorkspaceConfig() throws Exception {
         RepositoryConfig config =
             RepositoryConfig.create(REPOSITORY_XML, REPOSITORY_HOME);
-        config.createWorkspaceConfig("test-workspace");
+        config.createWorkspaceConfig("test-workspace", (StringBuffer)null);
         File workspaces_dir = new File(REPOSITORY_HOME, "workspaces");
         File workspace_dir = new File(workspaces_dir, "test-workspace");
         File workspace_xml = new File(workspace_dir, "workspace.xml");
@@ -231,7 +231,7 @@
         try {
             RepositoryConfig config =
                 RepositoryConfig.create(REPOSITORY_XML, REPOSITORY_HOME);
-            config.createWorkspaceConfig("default");
+            config.createWorkspaceConfig("default", (StringBuffer)null);
             fail("No exception thrown when creating a duplicate workspace");
         } catch (ConfigurationException e) {
             // test passed



Mime
View raw message