001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.ecm.directory.sql; 023 024import java.util.ArrayList; 025import java.util.List; 026 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029import org.nuxeo.common.xmap.annotation.XNode; 030import org.nuxeo.common.xmap.annotation.XNodeList; 031import org.nuxeo.common.xmap.annotation.XObject; 032import org.nuxeo.ecm.directory.DirectoryException; 033import org.nuxeo.ecm.directory.InverseReference; 034import org.nuxeo.ecm.directory.PermissionDescriptor; 035import org.nuxeo.ecm.directory.Reference; 036 037@XObject(value = "directory") 038public class SQLDirectoryDescriptor { 039 040 private static final Log log = LogFactory.getLog(SQLDirectoryDescriptor.class); 041 042 public enum SubstringMatchType { 043 subinitial, subfinal, subany 044 } 045 046 public static final int QUERY_SIZE_LIMIT_DEFAULT = 0; 047 048 public static final boolean AUTO_INCREMENT_ID_FIELD_DEFAULT = false; 049 050 public static final boolean READ_ONY_DEFAULT = false; 051 052 protected static final char DEFAULT_CHARACTER_SEPARATOR = ','; 053 054 private static final String[] SCRIPT_POLICIES = { "never", "on_missing_columns", "always", }; 055 056 private static final String DEFAULT_POLICY = "never"; 057 058 @XNode("@name") 059 public String name; 060 061 @XNode("schema") 062 public String schemaName; 063 064 @XNode("parentDirectory") 065 public String parentDirectory; 066 067 @XNode("dataSource") 068 public String dataSourceName; 069 070 @XNode("dbDriver") 071 public String dbDriver; 072 073 @XNode("dbUrl") 074 public String dbUrl; 075 076 @XNode("dbUser") 077 public String dbUser; 078 079 @XNode("dbPassword") 080 public String dbPassword; 081 082 @XNode("table") 083 public String tableName; 084 085 @XNodeList(value = "init-dependencies/dependency", type = ArrayList.class, componentType = String.class) 086 public List<String> initDependencies; 087 088 @XNode("idField") 089 public String idField; 090 091 @XNode("dataFile") 092 public String dataFileName; 093 094 @XNode(value = "dataFileCharacterSeparator", trim = false) 095 public String dataFileCharacterSeparator = ","; 096 097 public String createTablePolicy; 098 099 public SubstringMatchType substringMatchType; 100 101 @XNode("autoincrementIdField") 102 public Boolean autoincrementIdField; 103 104 @XNode("readOnly") 105 public Boolean readOnly; 106 107 @XNode("passwordField") 108 private String passwordField; 109 110 @XNode("passwordHashAlgorithm") 111 public String passwordHashAlgorithm; 112 113 @XNode("querySizeLimit") 114 private Integer querySizeLimit; 115 116 @XNodeList(value = "references/tableReference", type = TableReference[].class, componentType = TableReference.class) 117 private TableReference[] tableReferences; 118 119 @XNodeList(value = "references/inverseReference", type = InverseReference[].class, componentType = InverseReference.class) 120 private InverseReference[] inverseReferences; 121 122 @XNodeList(value = "permissions/permission", type = PermissionDescriptor[].class, componentType = PermissionDescriptor.class) 123 public PermissionDescriptor[] permissions = null; 124 125 @XNode("@remove") 126 private boolean remove = false; 127 128 @XNode("cacheEntryName") 129 public String cacheEntryName = null; 130 131 @XNode("cacheEntryWithoutReferencesName") 132 public String cacheEntryWithoutReferencesName = null; 133 134 @XNode("negativeCaching") 135 public Boolean negativeCaching; 136 137 @XNodeList(value = "filters/staticFilter", type = SQLStaticFilter[].class, componentType = SQLStaticFilter.class) 138 private SQLStaticFilter[] staticFilters; 139 140 @XNode("nativeCase") 141 public Boolean nativeCase; 142 143 @XNode("computeMultiTenantId") 144 private boolean computeMultiTenantId = true; 145 146 public String getDataSourceName() { 147 return dataSourceName; 148 } 149 150 public void setDataSourceName(String dataSourceName) { 151 this.dataSourceName = dataSourceName; 152 } 153 154 public void setIdField(String idField) { 155 this.idField = idField; 156 } 157 158 public String getName() { 159 return name; 160 } 161 162 public void setName(String name) { 163 this.name = name; 164 } 165 166 public String getSchemaName() { 167 return schemaName; 168 } 169 170 public void setSchemaName(String schemaName) { 171 this.schemaName = schemaName; 172 } 173 174 // XXX never used: is it supposed to help determining an entry full id 175 // using 176 // the parent directory id? 177 public String getParentDirectory() { 178 return parentDirectory; 179 } 180 181 public void setParentDirectory(String parentDirectory) { 182 this.parentDirectory = parentDirectory; 183 } 184 185 public String getTableName() { 186 return tableName; 187 } 188 189 public void setTableName(String tableName) { 190 this.tableName = tableName; 191 } 192 193 public String getDbDriver() { 194 return dbDriver; 195 } 196 197 public String getDbPassword() { 198 return dbPassword; 199 } 200 201 public String getDbUrl() { 202 return dbUrl; 203 } 204 205 public String getDbUser() { 206 return dbUser; 207 } 208 209 public String getDataFileName() { 210 return dataFileName; 211 } 212 213 public char getDataFileCharacterSeparator() { 214 if (dataFileCharacterSeparator == null || dataFileCharacterSeparator.length() == 0) { 215 log.info("Character separator not well set will " + "take the default value, \"" 216 + DEFAULT_CHARACTER_SEPARATOR + "\""); 217 return DEFAULT_CHARACTER_SEPARATOR; 218 } 219 220 if (dataFileCharacterSeparator.length() > 1) { 221 log.warn("More than one character found for character separator, " + "will take the first one \"" 222 + dataFileCharacterSeparator.charAt(0) + "\""); 223 } 224 225 return dataFileCharacterSeparator.charAt(0); 226 } 227 228 public String getPasswordField() { 229 return passwordField; 230 } 231 232 public void setPasswordField(String passwordField) { 233 this.passwordField = passwordField; 234 } 235 236 public String getIdField() { 237 return idField; 238 } 239 240 public String getCreateTablePolicy() { 241 return createTablePolicy; 242 } 243 244 @XNode("createTablePolicy") 245 public void setCreateTablePolicy(String createTablePolicy) throws DirectoryException { 246 if (createTablePolicy == null) { 247 this.createTablePolicy = DEFAULT_POLICY; 248 return; 249 } 250 createTablePolicy = createTablePolicy.toLowerCase(); 251 boolean validPolicy = false; 252 for (String policy : SCRIPT_POLICIES) { 253 if (createTablePolicy.equals(policy)) { 254 validPolicy = true; 255 break; 256 } 257 } 258 if (!validPolicy) { 259 throw new DirectoryException("invalid value for createTablePolicy: " + createTablePolicy 260 + ". It should be one of 'never', " + "'on_missing_columns', or 'always'."); 261 } 262 this.createTablePolicy = createTablePolicy; 263 } 264 265 @XNode("substringMatchType") 266 public void setSubstringMatchType(String substringMatchType) { 267 if (substringMatchType != null) { 268 try { 269 this.substringMatchType = Enum.valueOf(SubstringMatchType.class, substringMatchType); 270 } catch (IllegalArgumentException iae) { 271 log.error("Invalid substring match type: " + substringMatchType 272 + ". Valid options: subinitial, subfinal, subany"); 273 this.substringMatchType = SubstringMatchType.subinitial; 274 } 275 } 276 } 277 278 public Reference[] getInverseReferences() { 279 return inverseReferences; 280 } 281 282 public Reference[] getTableReferences() { 283 return tableReferences; 284 } 285 286 public Boolean getReadOnly() { 287 return readOnly == null ? Boolean.valueOf(READ_ONY_DEFAULT) : readOnly; 288 } 289 290 public void setReadOnly(Boolean readOnly) { 291 this.readOnly = readOnly; 292 } 293 294 public boolean isAutoincrementIdField() { 295 return autoincrementIdField == null ? AUTO_INCREMENT_ID_FIELD_DEFAULT : autoincrementIdField.booleanValue(); 296 } 297 298 public void setAutoincrementIdField(boolean autoincrementIdField) { 299 this.autoincrementIdField = Boolean.valueOf(autoincrementIdField); 300 } 301 302 public void setDbDriver(String dbDriver) { 303 this.dbDriver = dbDriver; 304 } 305 306 public void setDbPassword(String dbPassword) { 307 this.dbPassword = dbPassword; 308 } 309 310 public void setDbUrl(String dbUrl) { 311 this.dbUrl = dbUrl; 312 } 313 314 public void setDbUser(String dbUser) { 315 this.dbUser = dbUser; 316 } 317 318 public void setInverseReferences(InverseReference[] inverseReferences) { 319 this.inverseReferences = inverseReferences; 320 } 321 322 public void setDataFileName(String dataFile) { 323 this.dataFileName = dataFile; 324 } 325 326 public void setTableReferences(TableReference[] tableReferences) { 327 this.tableReferences = tableReferences; 328 } 329 330 public int getQuerySizeLimit() { 331 return querySizeLimit == null ? QUERY_SIZE_LIMIT_DEFAULT : querySizeLimit.intValue(); 332 } 333 334 public void setQuerySizeLimit(int querySizeLimit) { 335 this.querySizeLimit = Integer.valueOf(querySizeLimit); 336 } 337 338 public void setRemove(boolean delete) { 339 this.remove = delete; 340 } 341 342 public boolean getRemove() { 343 return this.remove; 344 } 345 346 public SubstringMatchType getSubstringMatchType() { 347 return substringMatchType == null ? SubstringMatchType.subinitial : substringMatchType; 348 } 349 350 public void setSubstringMatchType(SubstringMatchType substringMatchType) { 351 this.substringMatchType = substringMatchType; 352 } 353 354 public SQLStaticFilter[] getStaticFilters() { 355 if (staticFilters == null) { 356 return new SQLStaticFilter[0]; 357 } 358 return staticFilters; 359 } 360 361 /** 362 * Returns {@code true} if a multi tenant id should be computed for this directory, if the directory has support for 363 * multi tenancy, {@code false} otherwise. 364 * 365 * @since 5.6 366 */ 367 public boolean isComputeMultiTenantId() { 368 return computeMultiTenantId; 369 } 370 371 /** 372 * Merge re-written since 5.6 to comply to hot reload needs, omitting to merge properties initialized by xmap) 373 */ 374 public void merge(SQLDirectoryDescriptor other) { 375 merge(other, false); 376 } 377 378 public void merge(SQLDirectoryDescriptor other, boolean overwite) { 379 if (other.dataSourceName != null || overwite) { 380 dataSourceName = other.dataSourceName; 381 } 382 if (other.dbDriver != null || overwite) { 383 dbDriver = other.dbDriver; 384 } 385 if (other.dbUrl != null || overwite) { 386 dbUrl = other.dbUrl; 387 } 388 if (other.dbUser != null || overwite) { 389 dbUser = other.dbUser; 390 } 391 if (other.dbPassword != null || overwite) { 392 dbPassword = other.dbPassword; 393 } 394 if (other.tableName != null || overwite) { 395 tableName = other.tableName; 396 } 397 if (other.schemaName != null || overwite) { 398 schemaName = other.schemaName; 399 } 400 if (other.parentDirectory != null || overwite) { 401 parentDirectory = other.parentDirectory; 402 } 403 if ((other.initDependencies != null && other.initDependencies.size() != 0) || overwite) { 404 initDependencies = other.initDependencies; 405 } 406 if (other.idField != null || overwite) { 407 idField = other.idField; 408 } 409 if (other.dataFileName != null || overwite) { 410 dataFileName = other.dataFileName; 411 } 412 if (other.dataFileCharacterSeparator != null || overwite) { 413 dataFileCharacterSeparator = other.dataFileCharacterSeparator; 414 } 415 if (other.createTablePolicy != null || overwite) { 416 createTablePolicy = other.createTablePolicy; 417 } 418 if (other.substringMatchType != null || overwite) { 419 substringMatchType = other.substringMatchType; 420 } 421 if (other.autoincrementIdField != null || overwite) { 422 autoincrementIdField = other.autoincrementIdField; 423 } 424 if (other.readOnly != null || overwite) { 425 readOnly = other.readOnly; 426 } 427 if (other.passwordField != null || overwite) { 428 passwordField = other.passwordField; 429 } 430 if (other.passwordHashAlgorithm != null || overwite) { 431 passwordHashAlgorithm = other.passwordHashAlgorithm; 432 } 433 if (other.querySizeLimit != null || overwite) { 434 querySizeLimit = other.querySizeLimit; 435 } 436 437 if ((other.inverseReferences != null && other.inverseReferences.length != 0) || overwite) { 438 inverseReferences = other.inverseReferences; 439 } 440 if ((other.tableReferences != null && other.tableReferences.length != 0) || overwite) { 441 tableReferences = other.tableReferences; 442 } 443 if ((other.permissions != null && other.permissions.length != 0) || overwite) { 444 permissions = other.permissions; 445 } 446 447 remove = other.remove; 448 449 if (other.cacheEntryName != null || overwite) { 450 cacheEntryName = other.cacheEntryName; 451 } 452 if (other.cacheEntryWithoutReferencesName != null || overwite) { 453 cacheEntryWithoutReferencesName = other.cacheEntryWithoutReferencesName; 454 } 455 if (other.negativeCaching != null || overwite) { 456 negativeCaching = other.negativeCaching; 457 } 458 if ((other.staticFilters != null && other.staticFilters.length != 0) || overwite) { 459 staticFilters = other.staticFilters; 460 } 461 if (other.nativeCase != null || overwite) { 462 nativeCase = other.nativeCase; 463 } 464 465 computeMultiTenantId = other.computeMultiTenantId; 466 } 467 468 public SQLDirectoryDescriptor clone() { 469 SQLDirectoryDescriptor clone = new SQLDirectoryDescriptor(); 470 clone.name = name; 471 clone.schemaName = schemaName; 472 clone.parentDirectory = parentDirectory; 473 clone.dataSourceName = dataSourceName; 474 clone.dbDriver = dbDriver; 475 clone.dbUrl = dbUrl; 476 clone.dbUser = dbUser; 477 clone.dbPassword = dbPassword; 478 clone.tableName = tableName; 479 if (initDependencies != null) { 480 clone.initDependencies = new ArrayList<String>(initDependencies); 481 } 482 clone.idField = idField; 483 clone.dataFileName = dataFileName; 484 clone.dataFileCharacterSeparator = dataFileCharacterSeparator; 485 clone.createTablePolicy = createTablePolicy; 486 clone.substringMatchType = substringMatchType; 487 clone.autoincrementIdField = autoincrementIdField; 488 clone.readOnly = readOnly; 489 clone.passwordField = passwordField; 490 clone.passwordHashAlgorithm = passwordHashAlgorithm; 491 clone.querySizeLimit = querySizeLimit; 492 if (tableReferences != null) { 493 clone.tableReferences = new TableReference[tableReferences.length]; 494 for (int i = 0; i < tableReferences.length; i++) { 495 clone.tableReferences[i] = tableReferences[i].clone(); 496 } 497 } 498 if (inverseReferences != null) { 499 clone.inverseReferences = new InverseReference[inverseReferences.length]; 500 for (int i = 0; i < inverseReferences.length; i++) { 501 clone.inverseReferences[i] = inverseReferences[i].clone(); 502 } 503 } 504 if (permissions != null) { 505 clone.permissions = new PermissionDescriptor[permissions.length]; 506 for (int i = 0; i < permissions.length; i++) { 507 clone.permissions[i] = permissions[i].clone(); 508 } 509 } 510 clone.remove = remove; 511 clone.cacheEntryName = cacheEntryName; 512 clone.cacheEntryWithoutReferencesName = cacheEntryWithoutReferencesName; 513 clone.negativeCaching = negativeCaching; 514 if (staticFilters != null) { 515 clone.staticFilters = new SQLStaticFilter[staticFilters.length]; 516 for (int i = 0; i < staticFilters.length; i++) { 517 clone.staticFilters[i] = staticFilters[i].clone(); 518 } 519 } 520 clone.nativeCase = nativeCase; 521 clone.computeMultiTenantId = computeMultiTenantId; 522 return clone; 523 } 524}