001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2015 ForgeRock AS. 016 */ 017 018package org.opends.quicksetup; 019 020import org.opends.quicksetup.util.Utils; 021 022import java.io.File; 023import java.io.FileReader; 024import java.io.BufferedReader; 025import java.io.IOException; 026import java.util.Set; 027import java.util.HashSet; 028 029/** 030 * Represents the contents of an OpenDS configuration file. 031 */ 032public class Configuration { 033 034 private String contents; 035 private String lowerCaseContents; 036 private Installation install; 037 private File file; 038 039 /** 040 * Create a Configuration from a file. 041 * @param install of which this configuration is part 042 * @param file config.ldif file 043 */ 044 public Configuration(Installation install, File file) { 045 if (install == null) { 046 throw new NullPointerException("config file cannot be null"); 047 } 048 if (file == null) { 049 throw new NullPointerException("config file cannot be null"); 050 } else if ( 051 // Leave open the possibility that the file might be 052 // config.ldif.<svn rev> 053 !file.getName().startsWith("config.ldif")) { 054 throw new IllegalArgumentException("file must be a config.ldif file"); 055 } 056 this.install = install; 057 this.file = file; 058 } 059 060 /** 061 * Returns the list of directory manager dns as they appear in the 062 * configuration file. 063 * 064 * @return the list of directory manager dns as they appear in the 065 * configuration file. 066 * @throws IOException if there were problems reading the information from 067 * the configuration file. 068 */ 069 public Set<String> getDirectoryManagerDns() throws IOException { 070 return getConfigurationValues("ds-cfg-alternate-bind-dn"); 071 } 072 073 /** 074 * Provides the LDAP port as is specified in the config.ldif file. 075 * 076 * @return the LDAP port specified in the config.ldif file. 077 * @throws IOException if there were problems reading the information from 078 * the configuration file. 079 */ 080 public int getPort() throws IOException { 081 return getLDAPPort("ds-cfg-listen-port"); 082 } 083 084 /** 085 * Provides the administration port as is specified in the config.ldif file. 086 * 087 * @return the administration port specified in the config.ldif file. 088 * @throws IOException if there were problems reading the information from 089 * the configuration file. 090 */ 091 public int getAdminConnectorPort() throws IOException 092 { 093 return getAdminConnectorPort("ds-cfg-listen-port"); 094 } 095 096 /** 097 * Tells whether this server is configured as a replication server or not. 098 * @return <CODE>true</CODE> if the server is configured as a Replication 099 * Server and <CODE>false</CODE> otherwise. 100 * @throws IOException if there were problems reading the information from 101 * the configuration file. 102 */ 103 public boolean isReplicationServer() throws IOException 104 { 105 return getReplicationPort() != -1; 106 } 107 108 /** 109 * Provides the Replication port as is specified in the config.ldif file. 110 * Returns -1 if this server is not a Replication Server. 111 * 112 * @return the Replication port specified in the config.ldif file. 113 * @throws IOException if there were problems reading the information from 114 * the configuration file. 115 */ 116 public int getReplicationPort() throws IOException { 117 int port = -1; 118 String contents = getLowerCaseContents(); 119 int index = contents.indexOf("cn=replication server"); 120 121 if (index != -1) { 122 String attrWithPoints = "ds-cfg-replication-port:"; 123 int index1 = contents.indexOf(attrWithPoints, index); 124 if (index1 != -1) { 125 int index2 = 126 contents.indexOf(Constants.LINE_SEPARATOR, index1); 127 if (index2 != -1) { 128 String sPort = 129 contents.substring(attrWithPoints.length() + 130 index1, 131 index2).trim(); 132 try { 133 port = Integer.parseInt(sPort); 134 } catch (NumberFormatException nfe) { 135 // do nothing; 136 } 137 } 138 } 139 } 140 return port; 141 } 142 143 /** 144 * Returns the list of paths where the logs files are located as they appear 145 * in the configuration file. 146 * 147 * @return the list of paths where the logs files are located as they appear 148 * in the configuration file. 149 * @throws IOException if there were problems reading the information from 150 * the configuration file. 151 */ 152 public Set<String> getLogPaths() throws IOException { 153 return getConfigurationValues("ds-cfg-log-file"); 154 } 155 156 private int extractPort(String portAttr, int index) 157 { 158 int port = -1; 159 String attrWithPoints = portAttr + ":"; 160 int index1 = contents.indexOf(attrWithPoints, index); 161 if (index1 != -1) { 162 int index2 = 163 contents.indexOf(Constants.LINE_SEPARATOR, index1); 164 if (index2 != -1) { 165 String sPort = 166 contents.substring(attrWithPoints.length() + 167 index1, index2).trim(); 168 try { 169 port = Integer.parseInt(sPort); 170 } catch (NumberFormatException nfe) { 171 // do nothing; 172 } 173 } 174 } 175 return port; 176 } 177 178 179 private int getLDAPPort(String portAttr) throws IOException { 180 String contents = getLowerCaseContents(); 181 int index = contents.indexOf("cn=ldap connection handler"); 182 if (index != -1) { 183 return extractPort (portAttr, index); 184 } 185 return -1; 186 } 187 188 private int getAdminConnectorPort(String portAttr) throws IOException { 189 String contents = getLowerCaseContents(); 190 int index = contents.indexOf("cn=administration connector"); 191 if (index != -1) { 192 return extractPort(portAttr, index); 193 } 194 return -1; 195 } 196 197 /** 198 * Indicates whether the config.ldif file has been modified (compared to what 199 * we had in the zip file). This is used to know if we have configured the 200 * current binaries or not. 201 * 202 * @return <CODE>true</CODE> if the config.ldif file has been modified, or 203 * <CODE>false</CODE> if not. 204 * @throws IOException if there were problems reading the information from 205 * the configuration file. 206 */ 207 public boolean hasBeenModified() throws IOException { 208 boolean isConfigFileModified = getPort() != 389; 209 210 if (!isConfigFileModified) { 211 // TODO: this is not really stable 212 // Note: a better way might be to diff this file with 213 // /config/ldif/upgrade/config.ldif.<svn rev> 214 isConfigFileModified = !getLowerCaseContents().contains( 215 "# The contents of this file are subject to the terms of the Common Development".toLowerCase()); 216 } 217 218 return isConfigFileModified; 219 } 220 221 /** 222 * Returns a Set of relative paths containing the log paths outside the 223 * installation. 224 * @return a Set of relative paths containing the log paths outside the 225 * installation. 226 * @throws IOException if there is trouble reading the config file 227 */ 228 public Set<String> getOutsideLogs() 229 throws IOException 230 { 231 return getOutsidePaths(getLogPaths()); 232 } 233 234 /** 235 * Returns a Set of relative paths containing the db paths outside the 236 * installation. 237 * @return a Set of relative paths containing the db paths outside the 238 * installation. 239 * @throws IOException if there is trouble reading the config file 240 */ 241 public Set<String> getOutsideDbs() 242 throws IOException 243 { 244 return getOutsidePaths(getDatabasePaths()); 245 } 246 247 private Set<String> getOutsidePaths(Set<String> paths) { 248 Set<String> outsidePaths = new HashSet<>(); 249 for (String path : paths) { 250 File fullDbPath; 251 File pathFile = new File(path); 252 if (pathFile.isAbsolute()) { 253 fullDbPath = pathFile; 254 } else { 255 fullDbPath = new File(install.getInstanceDirectory(), path); 256 } 257 258 if (!Utils.isDescendant(fullDbPath, install.getInstanceDirectory())) { 259 outsidePaths.add(Utils.getPath(fullDbPath)); 260 } 261 } 262 return outsidePaths; 263 } 264 265 /** 266 * Provides the contents of the config.ldif file in a String. 267 * 268 * @return a String representing the contents of the config.ldif file. 269 * @throws IOException if there was a problem reading the file 270 */ 271 public String getContents() throws IOException { 272 if (contents == null) { 273 load(); 274 } 275 return contents; 276 } 277 278 /** 279 * Provides the contents of the config.ldif file in a lower case String. 280 * 281 * @return a lower case String representing the contents of the config.ldif 282 * file. 283 * @throws IOException if there was a problem reading the file 284 */ 285 public String getLowerCaseContents() throws IOException { 286 if (lowerCaseContents == null) { 287 load(); 288 } 289 return lowerCaseContents; 290 } 291 292 /** 293 * Returns the list of paths where the databases are installed as they appear 294 * in the configuration file. 295 * 296 * @return the list of paths where the databases are installed as they appear 297 * in the configuration file. 298 * @throws IOException if there is a problem reading the config file. 299 */ 300 public Set<String> getDatabasePaths() throws IOException { 301 return getConfigurationValues("ds-cfg-db-directory"); 302 } 303 304 /** 305 * Returns the list of base dns as they appear in the configuration file. 306 * 307 * @return the list of base dns as they appear in the configuration file. 308 * @throws IOException if there is a problem reading the config file. 309 */ 310 public Set<String> getBaseDNs() throws IOException { 311 return getConfigurationValues("ds-cfg-base-dn"); 312 } 313 314 /** 315 * Loads the contents of the configuration file into memory. 316 * @throws IOException if there were problems loading the file 317 */ 318 public void load() throws IOException { 319 StringBuilder buf = new StringBuilder(); 320 FileReader reader = new FileReader(file); 321 BufferedReader in = new BufferedReader(reader); 322 String line; 323 // We do not care about encoding: we are just interested in the ports 324 while ((line = in.readLine()) != null) { 325 buf.append(line).append(Constants.LINE_SEPARATOR); 326 } 327 reader.close(); 328 contents = buf.toString(); 329 lowerCaseContents = contents.toLowerCase(); 330 } 331 332 private Set<String> getConfigurationValues(String attrName) 333 throws IOException 334 { 335 Set<String> set = new HashSet<>(); 336 attrName += ":"; 337 String lowerCaseContents = getLowerCaseContents(); 338 String contents = getContents(); 339 int index1 = lowerCaseContents.indexOf(attrName); 340 while (index1 != -1) { 341 int index2 = lowerCaseContents.indexOf(Constants.LINE_SEPARATOR, index1); 342 String value; 343 if (index2 > index1 + attrName.length()) { 344 value = contents.substring(attrName.length() + index1, index2).trim(); 345 } else if (lowerCaseContents.length() > index1 + attrName.length()) { 346 // Assume end of file 347 value = contents.substring(attrName.length() + index1).trim(); 348 } else { 349 value = null; 350 } 351 352 if (value != null && value.length() > 0) { 353 set.add(value); 354 } 355 356 index1 = lowerCaseContents.indexOf(attrName, 357 index1 + attrName.length()); 358 } 359 return set; 360 } 361}