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-2016 ForgeRock AS. 016 */ 017package org.opends.quicksetup; 018 019import java.io.BufferedReader; 020import java.io.File; 021import java.io.FileReader; 022import java.io.IOException; 023import java.util.HashSet; 024import java.util.Set; 025 026import org.opends.quicksetup.util.Utils; 027 028/** 029 * Represents the contents of an OpenDS configuration file. 030 */ 031public class Configuration { 032 033 private String contents; 034 private String lowerCaseContents; 035 private final Installation install; 036 private final File file; 037 038 /** 039 * Create a Configuration from a file. 040 * @param install of which this configuration is part 041 * @param file config.ldif file 042 */ 043 public Configuration(Installation install, File file) { 044 if (install == null) { 045 throw new NullPointerException("config file cannot be null"); 046 } 047 if (file == null) { 048 throw new NullPointerException("config file cannot be null"); 049 } else if ( 050 // Leave open the possibility that the file might be 051 // config.ldif.<svn rev> 052 !file.getName().startsWith("config.ldif")) { 053 throw new IllegalArgumentException("file must be a config.ldif file"); 054 } 055 this.install = install; 056 this.file = file; 057 } 058 059 /** 060 * Returns the list of directory manager dns as they appear in the 061 * configuration file. 062 * 063 * @return the list of directory manager dns as they appear in the 064 * configuration file. 065 * @throws IOException if there were problems reading the information from 066 * the configuration file. 067 */ 068 public Set<String> getDirectoryManagerDns() throws IOException { 069 return getConfigurationValues("ds-cfg-alternate-bind-dn"); 070 } 071 072 /** 073 * Provides the LDAP port as is specified in the config.ldif file. 074 * 075 * @return the LDAP port specified in the config.ldif file. 076 * @throws IOException if there were problems reading the information from 077 * the configuration file. 078 */ 079 public int getPort() throws IOException { 080 return getLDAPPort("ds-cfg-listen-port"); 081 } 082 083 /** 084 * Provides the administration port as is specified in the config.ldif file. 085 * 086 * @return the administration 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 getAdminConnectorPort() throws IOException 091 { 092 return getAdminConnectorPort("ds-cfg-listen-port"); 093 } 094 095 /** 096 * Tells whether this server is configured as a replication server or not. 097 * @return <CODE>true</CODE> if the server is configured as a Replication 098 * Server and <CODE>false</CODE> otherwise. 099 * @throws IOException if there were problems reading the information from 100 * the configuration file. 101 */ 102 public boolean isReplicationServer() throws IOException 103 { 104 return getReplicationPort() != -1; 105 } 106 107 /** 108 * Provides the Replication port as is specified in the config.ldif file. 109 * Returns -1 if this server is not a Replication Server. 110 * 111 * @return the Replication port specified in the config.ldif file. 112 * @throws IOException if there were problems reading the information from 113 * the configuration file. 114 */ 115 public int getReplicationPort() throws IOException { 116 int port = -1; 117 String contents = getLowerCaseContents(); 118 int index = contents.indexOf("cn=replication server"); 119 120 if (index != -1) { 121 String attrWithPoints = "ds-cfg-replication-port:"; 122 int index1 = contents.indexOf(attrWithPoints, index); 123 if (index1 != -1) { 124 int index2 = 125 contents.indexOf(Constants.LINE_SEPARATOR, index1); 126 if (index2 != -1) { 127 String sPort = 128 contents.substring(attrWithPoints.length() + 129 index1, 130 index2).trim(); 131 try { 132 port = Integer.parseInt(sPort); 133 } catch (NumberFormatException nfe) { 134 // do nothing; 135 } 136 } 137 } 138 } 139 return port; 140 } 141 142 /** 143 * Returns the list of paths where the logs files are located as they appear 144 * in the configuration file. 145 * 146 * @return the list of paths where the logs files are located as they appear 147 * in the configuration file. 148 * @throws IOException if there were problems reading the information from 149 * the configuration file. 150 */ 151 public Set<String> getLogPaths() throws IOException { 152 return getConfigurationValues("ds-cfg-log-file"); 153 } 154 155 private int extractPort(String portAttr, int index) 156 { 157 int port = -1; 158 String attrWithPoints = portAttr + ":"; 159 int index1 = contents.indexOf(attrWithPoints, index); 160 if (index1 != -1) { 161 int index2 = 162 contents.indexOf(Constants.LINE_SEPARATOR, index1); 163 if (index2 != -1) { 164 String sPort = 165 contents.substring(attrWithPoints.length() + 166 index1, index2).trim(); 167 try { 168 port = Integer.parseInt(sPort); 169 } catch (NumberFormatException nfe) { 170 // do nothing; 171 } 172 } 173 } 174 return port; 175 } 176 177 178 private int getLDAPPort(String portAttr) throws IOException { 179 String contents = getLowerCaseContents(); 180 int index = contents.indexOf("cn=ldap connection handler"); 181 if (index != -1) { 182 return extractPort (portAttr, index); 183 } 184 return -1; 185 } 186 187 private int getAdminConnectorPort(String portAttr) throws IOException { 188 String contents = getLowerCaseContents(); 189 int index = contents.indexOf("cn=administration connector"); 190 if (index != -1) { 191 return extractPort(portAttr, index); 192 } 193 return -1; 194 } 195 196 /** 197 * Indicates whether the config.ldif file has been modified (compared to what 198 * we had in the zip file). This is used to know if we have configured the 199 * current binaries or not. 200 * 201 * @return <CODE>true</CODE> if the config.ldif file has been modified, or 202 * <CODE>false</CODE> if not. 203 * @throws IOException if there were problems reading the information from 204 * the configuration file. 205 */ 206 public boolean hasBeenModified() throws IOException { 207 boolean isConfigFileModified = getPort() != 389; 208 209 if (!isConfigFileModified) { 210 // TODO: this is not really stable 211 // Note: a better way might be to diff this file with 212 // /config/ldif/upgrade/config.ldif.<svn rev> 213 isConfigFileModified = !getLowerCaseContents().contains( 214 "# The contents of this file are subject to the terms of the Common Development".toLowerCase()); 215 } 216 217 return isConfigFileModified; 218 } 219 220 /** 221 * Returns a Set of relative paths containing the log paths outside the 222 * installation. 223 * @return a Set of relative paths containing the log paths outside the 224 * installation. 225 * @throws IOException if there is trouble reading the config file 226 */ 227 public Set<String> getOutsideLogs() 228 throws IOException 229 { 230 return getOutsidePaths(getLogPaths()); 231 } 232 233 /** 234 * Returns a Set of relative paths containing the db paths outside the 235 * installation. 236 * @return a Set of relative paths containing the db paths outside the 237 * installation. 238 * @throws IOException if there is trouble reading the config file 239 */ 240 public Set<String> getOutsideDbs() 241 throws IOException 242 { 243 return getOutsidePaths(getDatabasePaths()); 244 } 245 246 private Set<String> getOutsidePaths(Set<String> paths) { 247 Set<String> outsidePaths = new HashSet<>(); 248 for (String path : paths) { 249 File fullDbPath; 250 File pathFile = new File(path); 251 if (pathFile.isAbsolute()) { 252 fullDbPath = pathFile; 253 } else { 254 fullDbPath = new File(install.getInstanceDirectory(), path); 255 } 256 257 if (!Utils.isDescendant(fullDbPath, install.getInstanceDirectory())) { 258 outsidePaths.add(Utils.getPath(fullDbPath)); 259 } 260 } 261 return outsidePaths; 262 } 263 264 /** 265 * Provides the contents of the config.ldif file in a String. 266 * 267 * @return a String representing the contents of the config.ldif file. 268 * @throws IOException if there was a problem reading the file 269 */ 270 public String getContents() throws IOException { 271 if (contents == null) { 272 load(); 273 } 274 return contents; 275 } 276 277 /** 278 * Provides the contents of the config.ldif file in a lower case String. 279 * 280 * @return a lower case String representing the contents of the config.ldif 281 * file. 282 * @throws IOException if there was a problem reading the file 283 */ 284 public String getLowerCaseContents() throws IOException { 285 if (lowerCaseContents == null) { 286 load(); 287 } 288 return lowerCaseContents; 289 } 290 291 /** 292 * Returns the list of paths where the databases are installed as they appear 293 * in the configuration file. 294 * 295 * @return the list of paths where the databases are installed as they appear 296 * in the configuration file. 297 * @throws IOException if there is a problem reading the config file. 298 */ 299 public Set<String> getDatabasePaths() throws IOException { 300 return getConfigurationValues("ds-cfg-db-directory"); 301 } 302 303 /** 304 * Returns the list of base dns as they appear in the configuration file. 305 * 306 * @return the list of base dns as they appear in the configuration file. 307 * @throws IOException if there is a problem reading the config file. 308 */ 309 public Set<String> getBaseDNs() throws IOException { 310 return getConfigurationValues("ds-cfg-base-dn"); 311 } 312 313 /** 314 * Loads the contents of the configuration file into memory. 315 * @throws IOException if there were problems loading the file 316 */ 317 private void load() throws IOException 318 { 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}