View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.connector.infinispan;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.ByteArrayOutputStream;
28  import java.io.FileInputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.ObjectInputStream;
32  import java.io.ObjectOutputStream;
33  import java.util.Enumeration;
34  import java.util.HashMap;
35  import java.util.Hashtable;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.UUID;
39  import javax.naming.BinaryRefAddr;
40  import javax.naming.Context;
41  import javax.naming.InitialContext;
42  import javax.naming.NamingException;
43  import javax.naming.RefAddr;
44  import javax.naming.Reference;
45  import javax.naming.Referenceable;
46  import javax.naming.StringRefAddr;
47  import javax.naming.spi.ObjectFactory;
48  import net.jcip.annotations.ThreadSafe;
49  import org.infinispan.Cache;
50  import org.infinispan.manager.CacheManager;
51  import org.infinispan.manager.DefaultCacheManager;
52  import org.modeshape.common.i18n.I18n;
53  import org.modeshape.common.util.HashCode;
54  import org.modeshape.common.util.StringUtil;
55  import org.modeshape.graph.cache.CachePolicy;
56  import org.modeshape.graph.connector.RepositoryConnection;
57  import org.modeshape.graph.connector.RepositoryContext;
58  import org.modeshape.graph.connector.RepositorySource;
59  import org.modeshape.graph.connector.RepositorySourceCapabilities;
60  import org.modeshape.graph.connector.RepositorySourceException;
61  import org.modeshape.graph.connector.base.BaseRepositorySource;
62  import org.modeshape.graph.connector.base.Connection;
63  import org.modeshape.graph.observe.Observer;
64  
65  /**
66   * A repository source that uses an Infinispan instance to manage the content. This source is capable of using an existing
67   * {@link CacheManager} or creating a new cache manager. This process is controlled entirely by the JavaBean properties of the
68   * InfinispanSource instance.
69   * <p>
70   * This source first attempts to find an existing cache manager found in {@link #getCacheManagerJndiName() JNDI} (or the
71   * {@link DefaultCacheManager} if no such manager is available) and the {@link #getCacheConfigurationName() cache configuration
72   * name} if supplied or the default configuration if not set.
73   * </p>
74   * <p>
75   * Like other {@link RepositorySource} classes, instances of JBossCacheSource can be placed into JNDI and do support the creation
76   * of {@link Referenceable JNDI referenceable} objects and resolution of references into JBossCacheSource.
77   * </p>
78   */
79  @ThreadSafe
80  public class InfinispanSource implements BaseRepositorySource, ObjectFactory {
81  
82      private static final long serialVersionUID = 2L;
83      /**
84       * The default limit is {@value} for retrying {@link RepositoryConnection connection} calls to the underlying source.
85       */
86      public static final int DEFAULT_RETRY_LIMIT = 0;
87  
88      /**
89       * The initial {@link #getDefaultWorkspaceName() name of the default workspace} is "{@value} ", unless otherwise specified.
90       */
91      public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default";
92  
93      /**
94       * The initial value for whether updates are allowed is "{@value} ", unless otherwise specified.
95       */
96      public static final boolean DEFAULT_UPDATES_ALLOWED = true;
97  
98      protected static final String ROOT_NODE_UUID = "rootNodeUuid";
99      protected static final String SOURCE_NAME = "sourceName";
100     protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
101     protected static final String CACHE_CONFIGURATION_NAME = "cacheConfigurationName";
102     protected static final String CACHE_FACTORY_JNDI_NAME = "cacheManagerJndiName";
103     protected static final String RETRY_LIMIT = "retryLimit";
104     protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
105     protected static final String PREDEFINED_WORKSPACE_NAMES = "predefinedWorkspaceNames";
106     protected static final String ALLOW_CREATING_WORKSPACES = "allowCreatingWorkspaces";
107     protected static final String UPDATES_ALLOWED = "updatesAllowed";
108 
109     private volatile String name;
110     private volatile UUID rootNodeUuid = UUID.fromString("cafebabe-cafe-babe-cafe-babecafebabe");
111     private volatile CachePolicy defaultCachePolicy;
112     private volatile String cacheConfigurationName;
113     private volatile String cacheManagerJndiName;
114     private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
115     private volatile String defaultWorkspace;
116     private volatile boolean updatesAllowed = DEFAULT_UPDATES_ALLOWED;
117     private volatile String[] predefinedWorkspaces = new String[] {};
118     private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true, false);
119     private transient InfinispanRepository repository;
120     private transient Context jndiContext;
121     private transient RepositoryContext repositoryContext;
122 
123     /**
124      * Create a repository source instance.
125      */
126     public InfinispanSource() {
127     }
128 
129     /**
130      * {@inheritDoc}
131      * 
132      * @see org.modeshape.graph.connector.RepositorySource#initialize(org.modeshape.graph.connector.RepositoryContext)
133      */
134     public void initialize( RepositoryContext context ) throws RepositorySourceException {
135         this.repositoryContext = context;
136     }
137 
138     /**
139      * {@inheritDoc}
140      */
141     public String getName() {
142         return this.name;
143     }
144 
145     /**
146      * {@inheritDoc}
147      * 
148      * @see org.modeshape.graph.connector.RepositorySource#getCapabilities()
149      */
150     public RepositorySourceCapabilities getCapabilities() {
151         return capabilities;
152     }
153 
154     /**
155      * {@inheritDoc}
156      * 
157      * @see org.modeshape.graph.connector.RepositorySource#getRetryLimit()
158      */
159     public int getRetryLimit() {
160         return retryLimit;
161     }
162 
163     /**
164      * {@inheritDoc}
165      * 
166      * @see org.modeshape.graph.connector.RepositorySource#setRetryLimit(int)
167      */
168     public synchronized void setRetryLimit( int limit ) {
169         retryLimit = limit < 0 ? 0 : limit;
170     }
171 
172     /**
173      * Set the name of this source
174      * 
175      * @param name the name for this source
176      */
177     public synchronized void setName( String name ) {
178         if (this.name == name || this.name != null && this.name.equals(name)) return; // unchanged
179         this.name = name;
180     }
181 
182     /**
183      * Get the default cache policy for this source, or null if the global default cache policy should be used
184      * 
185      * @return the default cache policy, or null if this source has no explicit default cache policy
186      */
187     public CachePolicy getDefaultCachePolicy() {
188         return defaultCachePolicy;
189     }
190 
191     /**
192      * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
193      */
194     public synchronized void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
195         if (this.defaultCachePolicy == defaultCachePolicy || this.defaultCachePolicy != null
196             && this.defaultCachePolicy.equals(defaultCachePolicy)) return; // unchanged
197         this.defaultCachePolicy = defaultCachePolicy;
198     }
199 
200     /**
201      * Get the name in JNDI of a {@link CacheManager} instance that should be used to create the cache for this source.
202      * <p>
203      * This source first attempts to find a cache instance using the {@link CacheManager} found in
204      * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
205      * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
206      * </p>
207      * 
208      * @return the JNDI name of the {@link CacheManager} instance that should be used, or null if the {@link DefaultCacheManager}
209      *         should be used if a cache is to be created
210      * @see #setCacheManagerJndiName(String)
211      * @see #getCacheConfigurationName()
212      */
213     public String getCacheManagerJndiName() {
214         return cacheManagerJndiName;
215     }
216 
217     /**
218      * Set the name in JNDI of a {@link CacheManager} instance that should be used to obtain the {@link Cache} instance used by
219      * this source.
220      * <p>
221      * This source first attempts to find a cache instance using the {@link CacheManager} found in
222      * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
223      * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
224      * </p>
225      * 
226      * @param jndiName the JNDI name of the {@link CacheManager} instance that should be used, or null if the
227      *        {@link DefaultCacheManager} should be used if a cache is to be created
228      * @see #setCacheManagerJndiName(String)
229      * @see #getCacheConfigurationName()
230      */
231     public synchronized void setCacheManagerJndiName( String jndiName ) {
232         if (this.cacheManagerJndiName == jndiName || this.cacheManagerJndiName != null
233             && this.cacheManagerJndiName.equals(jndiName)) return; // unchanged
234         this.cacheManagerJndiName = jndiName;
235     }
236 
237     /**
238      * Get the name of the configuration that should be used if a {@link Cache cache} is to be created using the
239      * {@link CacheManager} found in JNDI or the {@link DefaultCacheManager} if needed.
240      * <p>
241      * This source first attempts to find a cache instance using the {@link CacheManager} found in
242      * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
243      * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
244      * </p>
245      * 
246      * @return the name of the configuration that should be passed to the {@link CacheManager}, or null if the default
247      *         configuration should be used
248      * @see #setCacheConfigurationName(String)
249      * @see #getCacheManagerJndiName()
250      */
251     public String getCacheConfigurationName() {
252         return cacheConfigurationName;
253     }
254 
255     /**
256      * Get the name of the configuration that should be used if a {@link Cache cache} is to be created using the
257      * {@link CacheManager} found in JNDI or the {@link DefaultCacheManager} if needed.
258      * <p>
259      * This source first attempts to find a cache instance using the {@link CacheManager} found in
260      * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
261      * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
262      * </p>
263      * 
264      * @param cacheConfigurationName the name of the configuration that should be passed to the {@link CacheManager}, or null if
265      *        the default configuration should be used
266      * @see #getCacheConfigurationName()
267      * @see #getCacheManagerJndiName()
268      */
269     public synchronized void setCacheConfigurationName( String cacheConfigurationName ) {
270         if (this.cacheConfigurationName == cacheConfigurationName || this.cacheConfigurationName != null
271             && this.cacheConfigurationName.equals(cacheConfigurationName)) return; // unchanged
272         this.cacheConfigurationName = cacheConfigurationName;
273     }
274 
275     /**
276      * Get the UUID of the root node for the cache. If the cache exists, this UUID is not used but is instead set to the UUID of
277      * the existing root node.
278      * 
279      * @return the UUID of the root node for the cache.
280      */
281     public String getRootNodeUuid() {
282         return this.rootNodeUuid.toString();
283     }
284 
285     /**
286      * Get the UUID of the root node for the cache. If the cache exists, this UUID is not used but is instead set to the UUID of
287      * the existing root node.
288      * 
289      * @return the UUID of the root node for the cache.
290      */
291     public UUID getRootNodeUuidObject() {
292         return this.rootNodeUuid;
293     }
294 
295     /**
296      * Set the UUID of the root node in this repository. If the cache exists, this UUID is not used but is instead set to the UUID
297      * of the existing root node.
298      * 
299      * @param rootNodeUuid the UUID of the root node for the cache, or null if the UUID should be randomly generated
300      */
301     public synchronized void setRootNodeUuid( String rootNodeUuid ) {
302         UUID uuid = null;
303         if (rootNodeUuid == null) uuid = UUID.randomUUID();
304         else uuid = UUID.fromString(rootNodeUuid);
305         if (this.rootNodeUuid.equals(uuid)) return; // unchanged
306         this.rootNodeUuid = uuid;
307     }
308 
309     /**
310      * Get the name of the default workspace.
311      * 
312      * @return the name of the workspace that should be used by default; never null
313      */
314     public String getDefaultWorkspaceName() {
315         return defaultWorkspace;
316     }
317 
318     /**
319      * Set the name of the workspace that should be used when clients don't specify a workspace.
320      * 
321      * @param nameOfDefaultWorkspace the name of the workspace that should be used by default, or null if the
322      *        {@link #DEFAULT_NAME_OF_DEFAULT_WORKSPACE default name} should be used
323      */
324     public synchronized void setDefaultWorkspaceName( String nameOfDefaultWorkspace ) {
325         this.defaultWorkspace = nameOfDefaultWorkspace != null ? nameOfDefaultWorkspace : DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
326     }
327 
328     /**
329      * Gets the names of the workspaces that are available when this source is created.
330      * 
331      * @return the names of the workspaces that this source starts with, or null if there are no such workspaces
332      * @see #setPredefinedWorkspaceNames(String[])
333      * @see #setCreatingWorkspacesAllowed(boolean)
334      */
335     public synchronized String[] getPredefinedWorkspaceNames() {
336         String[] copy = new String[predefinedWorkspaces.length];
337         System.arraycopy(predefinedWorkspaces, 0, copy, 0, predefinedWorkspaces.length);
338         return copy;
339     }
340 
341     /**
342      * Sets the names of the workspaces that are available when this source is created.
343      * 
344      * @param predefinedWorkspaceNames the names of the workspaces that this source should start with, or null if there are no
345      *        such workspaces
346      * @see #setCreatingWorkspacesAllowed(boolean)
347      * @see #getPredefinedWorkspaceNames()
348      */
349     public synchronized void setPredefinedWorkspaceNames( String[] predefinedWorkspaceNames ) {
350         if (predefinedWorkspaceNames != null && predefinedWorkspaceNames.length == 1) {
351             predefinedWorkspaceNames = predefinedWorkspaceNames[0].split("\\s*,\\s*");
352         }
353         this.predefinedWorkspaces = predefinedWorkspaceNames;
354     }
355 
356     /**
357      * Get whether this source allows workspaces to be created dynamically.
358      * 
359      * @return true if this source allows workspaces to be created by clients, or false if the
360      *         {@link #getPredefinedWorkspaceNames() set of workspaces} is fixed
361      * @see #setPredefinedWorkspaceNames(String[])
362      * @see #getPredefinedWorkspaceNames()
363      * @see #setCreatingWorkspacesAllowed(boolean)
364      */
365     public boolean isCreatingWorkspacesAllowed() {
366         return capabilities.supportsCreatingWorkspaces();
367     }
368 
369     /**
370      * Set whether this source allows workspaces to be created dynamically.
371      * 
372      * @param allowWorkspaceCreation true if this source allows workspaces to be created by clients, or false if the
373      *        {@link #getPredefinedWorkspaceNames() set of workspaces} is fixed
374      * @see #setPredefinedWorkspaceNames(String[])
375      * @see #getPredefinedWorkspaceNames()
376      * @see #isCreatingWorkspacesAllowed()
377      */
378     public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
379         capabilities = new RepositorySourceCapabilities(true, capabilities.supportsUpdates(), false, allowWorkspaceCreation,
380                                                         capabilities.supportsReferences());
381     }
382 
383     private CacheManager createCacheManager() {
384         CacheManager cacheManager;
385 
386         String configName = getCacheConfigurationName();
387         if (configName == null) {
388             cacheManager = new DefaultCacheManager();
389         } else {
390             /*
391             * First try treating the config name as a classpath resource, then as a file name.
392             */
393             InputStream configStream = getClass().getResourceAsStream(configName);
394             try {
395                 if (configStream == null) {
396                     configStream = new FileInputStream(configName);
397                 }
398             } catch (IOException ioe) {
399                 I18n msg = InfinispanConnectorI18n.configFileNotFound;
400                 throw new RepositorySourceException(this.name, msg.text(configName), ioe);
401             }
402 
403             try {
404                 cacheManager = new DefaultCacheManager(configStream);
405             } catch (IOException ioe) {
406                 I18n msg = InfinispanConnectorI18n.configFileNotValid;
407                 throw new RepositorySourceException(this.name, msg.text(configName), ioe);
408             } finally {
409                 try {
410                     configStream.close();
411                 } catch (IOException ioe) {
412                 }
413             }
414         }
415 
416         return cacheManager;
417     }
418 
419     final CacheManager cacheManager() {
420         return repository.getCacheManager();
421     }
422 
423     /**
424      * {@inheritDoc}
425      * 
426      * @see org.modeshape.graph.connector.RepositorySource#getConnection()
427      */
428     public synchronized RepositoryConnection getConnection() throws RepositorySourceException {
429         if (getName() == null) {
430             I18n msg = InfinispanConnectorI18n.propertyIsRequired;
431             throw new RepositorySourceException(getName(), msg.text("name"));
432         }
433         if (this.repository == null) {
434             Context context = getContext();
435             if (context == null) {
436                 try {
437                     context = new InitialContext();
438                 } catch (NamingException err) {
439                     throw new RepositorySourceException(name, err);
440                 }
441             }
442 
443             // Look for a cache manager in JNDI ...
444             CacheManager cacheManager = null;
445             String jndiName = getCacheManagerJndiName();
446             if (jndiName != null && jndiName.trim().length() != 0) {
447                 Object object = null;
448                 try {
449                     object = context.lookup(jndiName);
450                     if (object != null) cacheManager = (CacheManager)object;
451                 } catch (ClassCastException err) {
452                     I18n msg = InfinispanConnectorI18n.objectFoundInJndiWasNotCacheManager;
453                     String className = object != null ? object.getClass().getName() : "null";
454                     throw new RepositorySourceException(getName(), msg.text(jndiName, this.getName(), className), err);
455                 } catch (Throwable err) {
456                     if (err instanceof RuntimeException) throw (RuntimeException)err;
457                     throw new RepositorySourceException(getName(), err);
458                 }
459             }
460             if (cacheManager == null) {
461                 cacheManager = createCacheManager();
462             }
463 
464             // Now create the repository ...
465             this.repository = new InfinispanRepository(this, cacheManager);
466         }
467 
468         return new Connection<InfinispanNode, InfinispanWorkspace>(this, repository);
469     }
470 
471     /**
472      * {@inheritDoc}
473      * 
474      * @see org.modeshape.graph.connector.RepositorySource#close()
475      */
476     public synchronized void close() {
477         if (this.repository != null) {
478             try {
479                 this.repository.shutdown();
480             } finally {
481                 this.repository = null;
482             }
483         }
484     }
485 
486     /**
487      * @return repositoryContext
488      */
489     public RepositoryContext getRepositoryContext() {
490         return repositoryContext;
491     }
492 
493     protected Observer getObserver() {
494         return repositoryContext != null ? repositoryContext.getObserver() : null;
495     }
496 
497     protected synchronized Context getContext() {
498         return this.jndiContext;
499     }
500 
501     protected synchronized void setContext( Context context ) {
502         this.jndiContext = context;
503     }
504 
505     public boolean areUpdatesAllowed() {
506         return this.updatesAllowed;
507     }
508 
509     public void setUpdatesAllowed( boolean updatesAllowed ) {
510         this.updatesAllowed = updatesAllowed;
511     }
512 
513     /**
514      * {@inheritDoc}
515      */
516     @Override
517     public boolean equals( Object obj ) {
518         if (obj == this) return true;
519         if (obj instanceof InfinispanSource) {
520             InfinispanSource that = (InfinispanSource)obj;
521             if (this.getName() == null) {
522                 if (that.getName() != null) return false;
523             } else {
524                 if (!this.getName().equals(that.getName())) return false;
525             }
526             return true;
527         }
528         return false;
529     }
530 
531     @Override
532     public int hashCode() {
533         return HashCode.compute(getName());
534     }
535 
536     /**
537      * {@inheritDoc}
538      */
539     public synchronized Reference getReference() {
540         String className = getClass().getName();
541         String managerClassName = this.getClass().getName();
542         Reference ref = new Reference(className, managerClassName, null);
543 
544         ref.add(new StringRefAddr(SOURCE_NAME, getName()));
545         ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuid().toString()));
546         ref.add(new StringRefAddr(CACHE_FACTORY_JNDI_NAME, getCacheManagerJndiName()));
547         ref.add(new StringRefAddr(CACHE_CONFIGURATION_NAME, getCacheConfigurationName()));
548         ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
549         ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName()));
550         ref.add(new StringRefAddr(UPDATES_ALLOWED, String.valueOf(areUpdatesAllowed())));
551         ref.add(new StringRefAddr(ALLOW_CREATING_WORKSPACES, Boolean.toString(isCreatingWorkspacesAllowed())));
552         String[] workspaceNames = getPredefinedWorkspaceNames();
553         if (workspaceNames != null && workspaceNames.length != 0) {
554             ref.add(new StringRefAddr(PREDEFINED_WORKSPACE_NAMES, StringUtil.combineLines(workspaceNames)));
555         }
556         if (getDefaultCachePolicy() != null) {
557             ByteArrayOutputStream baos = new ByteArrayOutputStream();
558             CachePolicy policy = getDefaultCachePolicy();
559             try {
560                 ObjectOutputStream oos = new ObjectOutputStream(baos);
561                 oos.writeObject(policy);
562                 ref.add(new BinaryRefAddr(DEFAULT_CACHE_POLICY, baos.toByteArray()));
563             } catch (IOException e) {
564                 I18n msg = InfinispanConnectorI18n.errorSerializingCachePolicyInSource;
565                 throw new RepositorySourceException(getName(), msg.text(policy.getClass().getName(), getName()), e);
566             }
567         }
568         return ref;
569     }
570 
571     /**
572      * {@inheritDoc}
573      */
574     public Object getObjectInstance( Object obj,
575                                      javax.naming.Name name,
576                                      Context nameCtx,
577                                      Hashtable<?, ?> environment ) throws Exception {
578         if (obj instanceof Reference) {
579             Map<String, Object> values = new HashMap<String, Object>();
580             Reference ref = (Reference)obj;
581             Enumeration<?> en = ref.getAll();
582             while (en.hasMoreElements()) {
583                 RefAddr subref = (RefAddr)en.nextElement();
584                 if (subref instanceof StringRefAddr) {
585                     String key = subref.getType();
586                     Object value = subref.getContent();
587                     if (value != null) values.put(key, value.toString());
588                 } else if (subref instanceof BinaryRefAddr) {
589                     String key = subref.getType();
590                     Object value = subref.getContent();
591                     if (value instanceof byte[]) {
592                         // Deserialize ...
593                         ByteArrayInputStream bais = new ByteArrayInputStream((byte[])value);
594                         ObjectInputStream ois = new ObjectInputStream(bais);
595                         value = ois.readObject();
596                         values.put(key, value);
597                     }
598                 }
599             }
600             String sourceName = (String)values.get(SOURCE_NAME);
601             String rootNodeUuidString = (String)values.get(ROOT_NODE_UUID);
602             String cacheManagerJndiName = (String)values.get(CACHE_FACTORY_JNDI_NAME);
603             String cacheConfigurationName = (String)values.get(CACHE_CONFIGURATION_NAME);
604             Object defaultCachePolicy = values.get(DEFAULT_CACHE_POLICY);
605             String retryLimit = (String)values.get(RETRY_LIMIT);
606             String defaultWorkspace = (String)values.get(DEFAULT_WORKSPACE);
607             String createWorkspaces = (String)values.get(ALLOW_CREATING_WORKSPACES);
608             String updatesAllowed = (String)values.get(UPDATES_ALLOWED);
609 
610             String combinedWorkspaceNames = (String)values.get(PREDEFINED_WORKSPACE_NAMES);
611             String[] workspaceNames = null;
612             if (combinedWorkspaceNames != null) {
613                 List<String> paths = StringUtil.splitLines(combinedWorkspaceNames);
614                 workspaceNames = paths.toArray(new String[paths.size()]);
615             }
616 
617             // Create the source instance ...
618             InfinispanSource source = new InfinispanSource();
619             if (sourceName != null) source.setName(sourceName);
620             if (rootNodeUuidString != null) source.setRootNodeUuid(rootNodeUuidString);
621             if (cacheManagerJndiName != null) source.setCacheManagerJndiName(cacheManagerJndiName);
622             if (cacheConfigurationName != null) source.setCacheConfigurationName(cacheConfigurationName);
623             if (defaultCachePolicy instanceof CachePolicy) {
624                 source.setDefaultCachePolicy((CachePolicy)defaultCachePolicy);
625             }
626             if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
627             if (defaultWorkspace != null) source.setDefaultWorkspaceName(defaultWorkspace);
628             if (createWorkspaces != null) source.setCreatingWorkspacesAllowed(Boolean.parseBoolean(createWorkspaces));
629             if (workspaceNames != null && workspaceNames.length != 0) source.setPredefinedWorkspaceNames(workspaceNames);
630             if (updatesAllowed != null) source.setUpdatesAllowed(Boolean.valueOf(updatesAllowed));
631             return source;
632         }
633         return null;
634     }
635 }