1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.connector.svn;
25
26 import java.util.Hashtable;
27 import java.util.List;
28 import java.util.Map;
29 import javax.naming.Context;
30 import javax.naming.Name;
31 import javax.naming.Reference;
32 import javax.naming.StringRefAddr;
33 import javax.naming.spi.ObjectFactory;
34 import net.jcip.annotations.ThreadSafe;
35 import org.modeshape.common.annotation.Category;
36 import org.modeshape.common.annotation.Description;
37 import org.modeshape.common.annotation.Label;
38 import org.modeshape.common.annotation.ReadOnly;
39 import org.modeshape.common.i18n.I18n;
40 import org.modeshape.common.util.CheckArg;
41 import org.modeshape.common.util.StringUtil;
42 import org.modeshape.connector.svn.SvnRepository.SvnTransaction;
43 import org.modeshape.graph.ExecutionContext;
44 import org.modeshape.graph.connector.RepositoryConnection;
45 import org.modeshape.graph.connector.RepositorySource;
46 import org.modeshape.graph.connector.RepositorySourceCapabilities;
47 import org.modeshape.graph.connector.RepositorySourceException;
48 import org.modeshape.graph.connector.base.AbstractRepositorySource;
49 import org.modeshape.graph.connector.base.Connection;
50 import org.modeshape.graph.connector.base.PathNode;
51 import org.modeshape.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
52
53
54
55
56
57
58
59 @ThreadSafe
60 public class SvnRepositorySource extends AbstractRepositorySource implements ObjectFactory {
61
62
63
64
65 private static final long serialVersionUID = 1L;
66
67 protected static final String SOURCE_NAME = "sourceName";
68 protected static final String SVN_REPOSITORY_ROOT_URL = "repositoryRootURL";
69 protected static final String SVN_USERNAME = "username";
70 protected static final String SVN_PASSWORD = "password";
71 protected static final String RETRY_LIMIT = "retryLimit";
72 protected static final String ROOT_NODE_UUID = "rootNodeUuid";
73 protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
74 protected static final String PREDEFINED_WORKSPACE_NAMES = "predefinedWorkspaceNames";
75 protected static final String ALLOW_CREATING_WORKSPACES = "allowCreatingWorkspaces";
76
77
78
79
80 protected static final boolean SUPPORTS_EVENTS = true;
81
82
83
84 protected static final boolean SUPPORTS_SAME_NAME_SIBLINGS = false;
85
86
87
88 protected static final boolean DEFAULT_SUPPORTS_CREATING_WORKSPACES = true;
89
90
91
92 public static final boolean DEFAULT_SUPPORTS_UPDATES = false;
93
94
95
96 public static final String DEFAULT_WORKSPACE_NAME = "trunk";
97
98
99
100
101 protected static final boolean SUPPORTS_REFERENCES = false;
102
103 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "repositoryRootUrlPropertyDescription" )
104 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "repositoryRootUrlPropertyLabel" )
105 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "repositoryRootUrlPropertyCategory" )
106 private volatile String repositoryRootUrl;
107
108 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "usernamePropertyDescription" )
109 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "usernamePropertyLabel" )
110 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "usernamePropertyCategory" )
111 private volatile String username;
112
113 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "passwordPropertyDescription" )
114 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "passwordPropertyLabel" )
115 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "passwordPropertyCategory" )
116 private volatile String password;
117
118 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "defaultWorkspaceNamePropertyDescription" )
119 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "defaultWorkspaceNamePropertyLabel" )
120 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "defaultWorkspaceNamePropertyCategory" )
121 private volatile String defaultWorkspace = DEFAULT_WORKSPACE_NAME;
122
123 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "predefinedWorkspacesPropertyDescription" )
124 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "predefinedWorkspacesPropertyLabel" )
125 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "predefinedWorkspacesPropertyCategory" )
126 private volatile String[] predefinedWorkspaces = new String[] {};
127
128 private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(
129 SUPPORTS_SAME_NAME_SIBLINGS,
130 DEFAULT_SUPPORTS_UPDATES,
131 SUPPORTS_EVENTS,
132 DEFAULT_SUPPORTS_CREATING_WORKSPACES,
133 SUPPORTS_REFERENCES);
134
135 private transient SvnRepository repository;
136
137 private ExecutionContext defaultContext = new ExecutionContext();
138
139
140
141
142 public SvnRepositorySource() {
143 }
144
145
146
147
148
149
150 public RepositorySourceCapabilities getCapabilities() {
151 return capabilities;
152 }
153
154
155
156
157 public String getRepositoryRootUrl() {
158 return this.repositoryRootUrl;
159 }
160
161
162
163
164
165
166
167 public synchronized void setRepositoryRootUrl( String url ) {
168 CheckArg.isNotEmpty(url, "RepositoryRootUrl");
169 this.repositoryRootUrl = url;
170 }
171
172 public String getUsername() {
173 return this.username;
174 }
175
176
177
178
179 public synchronized void setUsername( String username ) {
180 this.username = username;
181 }
182
183 public String getPassword() {
184 return this.password;
185 }
186
187
188
189
190 public synchronized void setPassword( String password ) {
191 this.password = password;
192 }
193
194
195
196
197
198
199 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "updatesAllowedPropertyDescription" )
200 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "updatesAllowedPropertyLabel" )
201 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "updatesAllowedPropertyCategory" )
202 @ReadOnly
203 public boolean getSupportsUpdates() {
204 return capabilities.supportsUpdates();
205 }
206
207
208
209
210
211
212
213
214
215
216 public String getDefaultWorkspaceName() {
217 return defaultWorkspace;
218 }
219
220
221
222
223
224
225
226
227
228
229 public synchronized void setDefaultWorkspaceName( String pathToDirectoryForDefaultWorkspace ) {
230 this.defaultWorkspace = pathToDirectoryForDefaultWorkspace;
231 }
232
233
234
235
236
237
238
239
240
241 public synchronized String[] getPredefinedWorkspaceNames() {
242 String[] copy = new String[predefinedWorkspaces.length];
243 System.arraycopy(predefinedWorkspaces, 0, copy, 0, predefinedWorkspaces.length);
244 return copy;
245 }
246
247
248
249
250
251
252
253
254
255
256 public synchronized void setPredefinedWorkspaceNames( String[] predefinedWorkspaceNames ) {
257 this.predefinedWorkspaces = predefinedWorkspaceNames;
258 }
259
260
261
262
263
264
265
266
267
268 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyDescription" )
269 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyLabel" )
270 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "creatingWorkspacesAllowedPropertyCategory" )
271 public boolean isCreatingWorkspacesAllowed() {
272 return capabilities.supportsCreatingWorkspaces();
273 }
274
275
276
277
278
279
280
281
282
283
284 public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
285 capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), capabilities.supportsUpdates(),
286 capabilities.supportsEvents(), allowWorkspaceCreation,
287 capabilities.supportsReferences());
288 }
289
290
291
292
293
294
295
296 @Description( i18n = SvnRepositoryConnectorI18n.class, value = "updatesAllowedPropertyDescription" )
297 @Label( i18n = SvnRepositoryConnectorI18n.class, value = "updatesAllowedPropertyLabel" )
298 @Category( i18n = SvnRepositoryConnectorI18n.class, value = "updatesAllowedPropertyCategory" )
299 @Override
300 public boolean areUpdatesAllowed() {
301 return capabilities.supportsUpdates();
302 }
303
304
305
306
307
308
309
310
311 public synchronized void setUpdatesAllowed( boolean allowUpdates ) {
312 capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), allowUpdates,
313 capabilities.supportsEvents(), capabilities.supportsCreatingWorkspaces(),
314 capabilities.supportsReferences());
315 }
316
317
318
319
320 @Override
321 public boolean equals( Object obj ) {
322 if (obj == this) return true;
323 if (obj instanceof SvnRepositorySource) {
324 SvnRepositorySource that = (SvnRepositorySource)obj;
325 if (this.getName() == null) {
326 if (that.getName() != null) return false;
327 } else {
328 if (!this.getName().equals(that.getName())) return false;
329 }
330 return true;
331 }
332 return false;
333 }
334
335 @Override
336 public int hashCode() {
337 return getName().hashCode();
338 }
339
340
341
342
343
344
345 public synchronized Reference getReference() {
346 String className = getClass().getName();
347 String factoryClassName = this.getClass().getName();
348 Reference ref = new Reference(className, factoryClassName, null);
349
350 if (getName() != null) {
351 ref.add(new StringRefAddr(SOURCE_NAME, getName()));
352 }
353 if (getRepositoryRootUrl() != null) {
354 ref.add(new StringRefAddr(SVN_REPOSITORY_ROOT_URL, getRepositoryRootUrl()));
355 }
356 if (getUsername() != null) {
357 ref.add(new StringRefAddr(SVN_USERNAME, getUsername()));
358 }
359 if (getPassword() != null) {
360 ref.add(new StringRefAddr(SVN_PASSWORD, getPassword()));
361 }
362 ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
363 ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuidObject().toString()));
364 ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName()));
365 ref.add(new StringRefAddr(ALLOW_CREATING_WORKSPACES, Boolean.toString(isCreatingWorkspacesAllowed())));
366 String[] workspaceNames = getPredefinedWorkspaceNames();
367 if (workspaceNames != null && workspaceNames.length != 0) {
368 ref.add(new StringRefAddr(PREDEFINED_WORKSPACE_NAMES, StringUtil.combineLines(workspaceNames)));
369 }
370 return ref;
371
372 }
373
374
375
376
377
378
379
380 public Object getObjectInstance( Object obj,
381 Name name,
382 Context nameCtx,
383 Hashtable<?, ?> environment ) throws Exception {
384 if (!(obj instanceof Reference)) return null;
385
386 Map<String, Object> values = valuesFrom((Reference)obj);
387
388 String sourceName = (String)values.get(SOURCE_NAME);
389 String repositoryRootUrl = (String)values.get(SVN_REPOSITORY_ROOT_URL);
390 String username = (String)values.get(SVN_USERNAME);
391 String password = (String)values.get(SVN_PASSWORD);
392 String retryLimit = (String)values.get(RETRY_LIMIT);
393 String rootNodeUuid = (String)values.get(ROOT_NODE_UUID);
394 String defaultWorkspace = (String)values.get(DEFAULT_WORKSPACE);
395 String createWorkspaces = (String)values.get(ALLOW_CREATING_WORKSPACES);
396
397 String combinedWorkspaceNames = (String)values.get(PREDEFINED_WORKSPACE_NAMES);
398 String[] workspaceNames = null;
399 if (combinedWorkspaceNames != null) {
400 List<String> paths = StringUtil.splitLines(combinedWorkspaceNames);
401 workspaceNames = paths.toArray(new String[paths.size()]);
402 }
403
404 SvnRepositorySource source = new SvnRepositorySource();
405 if (sourceName != null) source.setName(sourceName);
406 if (repositoryRootUrl != null && repositoryRootUrl.length() > 0) source.setRepositoryRootUrl(repositoryRootUrl);
407 if (username != null) source.setUsername(username);
408 if (password != null) source.setPassword(password);
409 if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
410 if (rootNodeUuid != null) source.setRootNodeUuidObject(rootNodeUuid);
411 if (defaultWorkspace != null) source.setDefaultWorkspaceName(defaultWorkspace);
412 if (createWorkspaces != null) source.setCreatingWorkspacesAllowed(Boolean.parseBoolean(createWorkspaces));
413 if (workspaceNames != null && workspaceNames.length != 0) source.setPredefinedWorkspaceNames(workspaceNames);
414 return source;
415 }
416
417
418
419
420
421
422 public synchronized RepositoryConnection getConnection() throws RepositorySourceException {
423
424 String sourceName = getName();
425 if (sourceName == null || sourceName.trim().length() == 0) {
426 I18n msg = SvnRepositoryConnectorI18n.propertyIsRequired;
427 throw new RepositorySourceException(getName(), msg.text("name"));
428 }
429
430 String sourceUsername = getUsername();
431 if (sourceUsername == null || sourceUsername.trim().length() == 0) {
432 I18n msg = SvnRepositoryConnectorI18n.propertyIsRequired;
433 throw new RepositorySourceException(getUsername(), msg.text("username"));
434 }
435
436 String sourcePassword = getPassword();
437 if (sourcePassword == null) {
438 I18n msg = SvnRepositoryConnectorI18n.propertyIsRequired;
439 throw new RepositorySourceException(getPassword(), msg.text("password"));
440 }
441
442 String repositoryRootURL = getRepositoryRootUrl();
443 if (repositoryRootURL == null || repositoryRootURL.trim().length() == 0) {
444 I18n msg = SvnRepositoryConnectorI18n.propertyIsRequired;
445 throw new RepositorySourceException(getRepositoryRootUrl(), msg.text("repositoryRootURL"));
446 }
447 repositoryRootURL = repositoryRootURL.trim();
448 if (repositoryRootURL.endsWith("/")) repositoryRootURL = repositoryRootURL + "/";
449
450 if (repository == null) {
451 repository = new SvnRepository(this);
452
453 ExecutionContext context = repositoryContext != null ? repositoryContext.getExecutionContext() : defaultContext;
454 SvnTransaction txn = repository.startTransaction(context, false);
455 try {
456
457 for (String initialName : getPredefinedWorkspaceNames()) {
458 repository.createWorkspace(txn, initialName, CreateConflictBehavior.DO_NOT_CREATE, null);
459 }
460 } finally {
461 txn.commit();
462 }
463
464 }
465 return new Connection<PathNode, SvnWorkspace>(this, repository);
466 }
467 }