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