001/* 002 * (C) Copyright 2006-2016 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 * Florent Guillaume 019 */ 020package org.nuxeo.ecm.directory; 021 022import org.apache.commons.lang.StringUtils; 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025import org.nuxeo.common.xmap.annotation.XNode; 026import org.nuxeo.common.xmap.annotation.XNodeList; 027import org.nuxeo.common.xmap.annotation.XObject; 028 029/** 030 * Basic directory descriptor, containing the basic fields used by all directories. 031 * 032 * @since 8.2 033 */ 034@XObject(value = "directory") 035public class BaseDirectoryDescriptor implements Cloneable { 036 037 private static final Log log = LogFactory.getLog(BaseDirectoryDescriptor.class); 038 039 /** 040 * How directory semi-"fulltext" searches are matched with a query string. 041 * <p> 042 * Used for SQL and LDAP directories. 043 * 044 * @since 8.2 045 */ 046 public enum SubstringMatchType { 047 /** Matches initial substring. */ 048 subinitial, 049 /** Matches final substring. */ 050 subfinal, 051 /** Matches any substring. */ 052 subany; 053 } 054 055 public static final int CACHE_TIMEOUT_DEFAULT = 0; 056 057 public static final int CACHE_MAX_SIZE_DEFAULT = 0; 058 059 public static final boolean READ_ONLY_DEFAULT = false; 060 061 public static final SubstringMatchType SUBSTRING_MATCH_TYPE_DEFAULT = SubstringMatchType.subinitial; 062 063 @XNode("@name") 064 public String name; 065 066 @XNode("@remove") 067 public boolean remove; 068 069 @XNode("@template") 070 public boolean template; 071 072 @XNode("@extends") 073 public String extendz; 074 075 @XNode("parentDirectory") 076 public String parentDirectory; 077 078 @XNode("schema") 079 public String schemaName; 080 081 @XNode("idField") 082 public String idField; 083 084 @XNode("table") 085 public String tableName; 086 087 @XNode("readOnly") 088 public Boolean readOnly; 089 090 @XNode("passwordField") 091 public String passwordField; 092 093 @XNode("passwordHashAlgorithm") 094 public String passwordHashAlgorithm; 095 096 @XNodeList(value = "permissions/permission", type = PermissionDescriptor[].class, componentType = PermissionDescriptor.class) 097 public PermissionDescriptor[] permissions; 098 099 @XNode("cacheTimeout") 100 public Integer cacheTimeout; 101 102 @XNode("cacheMaxSize") 103 public Integer cacheMaxSize; 104 105 @XNode("cacheEntryName") 106 public String cacheEntryName; 107 108 @XNode("cacheEntryWithoutReferencesName") 109 public String cacheEntryWithoutReferencesName; 110 111 @XNode("negativeCaching") 112 public Boolean negativeCaching; 113 114 @XNode("substringMatchType") 115 public String substringMatchType; 116 117 public boolean isReadOnly() { 118 return readOnly == null ? READ_ONLY_DEFAULT : readOnly.booleanValue(); 119 } 120 121 public void setReadOnly(boolean readOnly) { 122 this.readOnly = Boolean.valueOf(readOnly); 123 } 124 125 public int getCacheTimeout() { 126 return cacheTimeout == null ? CACHE_TIMEOUT_DEFAULT : cacheTimeout.intValue(); 127 } 128 129 public int getCacheMaxSize() { 130 return cacheMaxSize == null ? CACHE_MAX_SIZE_DEFAULT : cacheMaxSize.intValue(); 131 } 132 133 public SubstringMatchType getSubstringMatchType() { 134 if (StringUtils.isBlank(substringMatchType)) { 135 return SUBSTRING_MATCH_TYPE_DEFAULT; 136 } 137 try { 138 return SubstringMatchType.valueOf(substringMatchType); 139 } catch (IllegalArgumentException e) { 140 log.error("Unknown value for <substringMatchType>: " + substringMatchType); 141 return SUBSTRING_MATCH_TYPE_DEFAULT; 142 } 143 } 144 145 /** 146 * Sub-classes MUST OVERRIDE and use a more specific return type. 147 * <p> 148 * Usually it's bad to use clone(), and a copy-constructor is preferred, but here we want the copy method to be 149 * inheritable so clone() is appropriate. 150 * <p> 151 * {@inheritDoc} 152 */ 153 @Override 154 public BaseDirectoryDescriptor clone() { 155 BaseDirectoryDescriptor clone; 156 try { 157 clone = (BaseDirectoryDescriptor) super.clone(); 158 } catch (CloneNotSupportedException e) { 159 throw new AssertionError(e); 160 } 161 // basic fields are already copied by super.clone() 162 if (permissions != null) { 163 clone.permissions = new PermissionDescriptor[permissions.length]; 164 for (int i = 0; i < permissions.length; i++) { 165 clone.permissions[i] = permissions[i].clone(); 166 } 167 } 168 return clone; 169 } 170 171 public void merge(BaseDirectoryDescriptor other) { 172 template = template || other.template; 173 174 if (other.parentDirectory != null) { 175 parentDirectory = other.parentDirectory; 176 } 177 if (other.schemaName != null) { 178 schemaName = other.schemaName; 179 } 180 if (other.idField != null) { 181 idField = other.idField; 182 } 183 if (other.tableName != null) { 184 tableName = other.tableName; 185 } 186 if (other.readOnly != null) { 187 readOnly = other.readOnly; 188 } 189 if (other.passwordField != null) { 190 passwordField = other.passwordField; 191 } 192 if (other.passwordHashAlgorithm != null) { 193 passwordHashAlgorithm = other.passwordHashAlgorithm; 194 } 195 if (other.permissions != null && other.permissions.length != 0) { 196 permissions = other.permissions; 197 } 198 if (other.cacheTimeout != null) { 199 cacheTimeout = other.cacheTimeout; 200 } 201 if (other.cacheMaxSize != null) { 202 cacheMaxSize = other.cacheMaxSize; 203 } 204 if (other.cacheEntryName != null) { 205 cacheEntryName = other.cacheEntryName; 206 } 207 if (other.cacheEntryWithoutReferencesName != null) { 208 cacheEntryWithoutReferencesName = other.cacheEntryWithoutReferencesName; 209 } 210 if (other.negativeCaching != null) { 211 negativeCaching = other.negativeCaching; 212 } 213 if (other.substringMatchType != null) { 214 substringMatchType = other.substringMatchType; 215 } 216 } 217 218 /** 219 * Creates a new {@link Directory} instance from this {@link DirectoryDescriptor). 220 */ 221 public Directory newDirectory() { 222 throw new UnsupportedOperationException("Cannot be instantiated as Directory: " + getClass().getName()); 223 } 224 225}