Cannot Start Service "Microsoft Exchange Information Store"

解决Exchange Server配置导致的服务无法启动问题
本文探讨了Exchange Server版本为Exchange 2013时,由于配置的MaxTotalDatabases属性超过服务器版支持的最大值50,导致Microsoft Exchange Information Store服务无法正常启动的问题。提供了在不升级服务器的情况下,通过修改ADSI编辑器设置来解决此问题的方法。

  There are many reasons which cause service “Microsoft Exchange Information Store” cannot be started, we only discuss one reason: The MaxTotalDatabases attribute on the Information Store object in Active Directory has been configured with a value of 100, which exceeds the maximum value of 50 supported by this edition of Exchange Server.

  We have 2 Exchange 2013 mailbox server, the version of server A is V15.0(build 712.24), and the version of server B is V15.0(build 516.32). After I restart the server B, users whose mailbox databases are located on server B cannot access their mailbox.

  After investigation, I found status of service Microsoft Exchange Information Store is always Starting. By checking event logs, I found this service retried again and again, the description told me: he MaxTotalDatabases attribute on the Information Store object in Active Directory has been configured with a value of 100, which exceeds the maximum value of 50 supported by this edition of Exchange Server.
  Of course, if you upgrade your Exchange server to CU2(build 15.0.712.24) or higher (CU10 is the latest so far), this problem will be solved easily. But for some reasons, e.g., you may worry about the stability or compatibility, and you want to keep the current version.
  If you want to keep the version, please change an ADSI Edit setting:

  1. Click Start, and then click Run. You also can call this box by pressing Windows key and R.
  2. In the Open box, type Adsiedit.msc, and then click OK.
  3. Right-click ADSI Edit, and then click Connect to.
  4. In the Select a well know Naming Context list, select Default naming context.
  5. In the Select or type a domain or server box, type the FQDN of a domain controller server, and then click OK.
  6. Expand to the path to the following:

    Configuration [DC.domain.com]; CN=Configuration, DC=domain, DC=com; CN=Services; CN=Microsoft Exchange; CN=<Your Organization>; CN= Administrative Groups; CN=<Exchange Org name>; CN=Servers; CN=<the Mailbox Server name>; CN=Information Store

  7. Right-click CN=InformationStore, and then click Properties.

  8. In the Attributes list, double-click msExchMaxStoresTotal, and then set the value to 50.

  After above actions, Microsoft Exchange Information Store service will be started automatically.

package com.server; import java.sql.*; import java.security.SecureRandom; import java.util.Base64; import org.apache.commons.codec.digest.Crypt; public class MessageDatabase_217230206 { private static MessageDatabase_217230206 dbInstance = null; private Connection dbconnection = null; private SecureRandom secureRandom = new SecureRandom(); public static synchronized MessageDatabase_217230206 getInstance() { if (dbInstance == null) { dbInstance = new MessageDatabase_217230206(); } return dbInstance; } public void open(String databaseName) throws SQLException { if (dbconnection != null && !dbconnection.isClosed()) { return; } String connectionString = "jdbc:sqlite:" + databaseName; dbconnection = DriverManager.getConnection(connectionString); System.out.println("Connected to database: " + databaseName); initializeTables(); } public void close() throws SQLException { if (dbconnection != null && !dbconnection.isClosed()) { dbconnection.close(); System.out.println("Database connection closed"); } } private void initializeTables() throws SQLException { String createUsersTable = "CREATE TABLE IF NOT EXISTS users (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "username VARCHAR(50) UNIQUE NOT NULL, " + "password VARCHAR(255) NOT NULL, " + "email VARCHAR(50) NOT NULL, " + "userNickname VARCHAR(50) NOT NULL, " + "salt VARCHAR(100) NOT NULL" + ");"; String createMessagesTable = "CREATE TABLE IF NOT EXISTS messages (" + "locationID INTEGER PRIMARY KEY AUTOINCREMENT, " + "locationName VARCHAR(100) NOT NULL, " + "locationDescription TEXT NOT NULL, " + "locationCity VARCHAR(50) NOT NULL, " + "locationCountry VARCHAR(50), " + "locationStreetAddress VARCHAR(100), " + "latitude REAL, " + "longitude REAL, " + "originalPostingTime BIGINT NOT NULL, " + "originalPoster VARCHAR(50) NOT NULL, " + "username VARCHAR(50) NOT NULL, " + "weather VARCHAR(50)" + ");"; try (Statement createStatement = dbconnection.createStatement()) { createStatement.executeUpdate(createUsersTable); createStatement.executeUpdate(createMessagesTable); System.out.println("Database tables created successfully"); } } public boolean userExists(String username) throws SQLException { final String sql = "SELECT COUNT(*) as count FROM users WHERE username = ?"; try (PreparedStatement pstmt = dbconnection.prepareStatement(sql)) { pstmt.setString(1, username); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { return rs.getInt("count") > 0; } return false; } } private String hashPassword(String password) { byte[] bytes = new byte[13]; secureRandom.nextBytes(bytes); String saltBytes = Base64.getEncoder().encodeToString(bytes); String salt = "$6$" + saltBytes; return Crypt.crypt(password, salt); } public boolean addUser(String username, String password, String email, String userNickname) throws SQLException { final String sql = "INSERT INTO users (username, password, email, userNickname, salt) VALUES (?, ?, ?, ?, ?)"; try (PreparedStatement pstmt = dbconnection.prepareStatement(sql)) { String hashedPassword = hashPassword(password); pstmt.setString(1, username); pstmt.setString(2, hashedPassword); pstmt.setString(3, email); pstmt.setString(4, userNickname); pstmt.setString(5, hashedPassword.substring(0, 20)); pstmt.executeUpdate(); return true; } catch (SQLException e) { if (e.getErrorCode() == 19 || e.getMessage().contains("UNIQUE constraint failed")) { return false; } throw e; } } public boolean validateUser(String username, String password) throws SQLException { final String sql = "SELECT password FROM users WHERE username = ?"; try (PreparedStatement pstmt = dbconnection.prepareStatement(sql)) { pstmt.setString(1, username); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { String storedHashedPassword = rs.getString("password"); String computedHash = Crypt.crypt(password, storedHashedPassword); return storedHashedPassword.equals(computedHash); } return false; } } public String getUserNickname(String username) throws SQLException { final String sql = "SELECT userNickname FROM users WHERE username = ?"; try (PreparedStatement pstmt = dbconnection.prepareStatement(sql)) { pstmt.setString(1, username); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { return rs.getString("userNickname"); } return null; } } public boolean addMessage(String locationName, String locationDescription, String locationCity, String locationCountry, String locationStreetAddress, Double latitude, Double longitude, long originalPostingTime, String username, String weather) throws SQLException { if (!userExists(username)) { System.out.println("User " + username + " does not exist"); return false; } String userNickname = getUserNickname(username); if (userNickname == null) { userNickname = username; } final String sql = "INSERT INTO messages (locationName, locationDescription, locationCity, " + "locationCountry, locationStreetAddress, latitude, longitude, " + "originalPostingTime, originalPoster, username, weather) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; try (PreparedStatement pstmt = dbconnection.prepareStatement(sql)) { pstmt.setString(1, locationName); pstmt.setString(2, locationDescription); pstmt.setString(3, locationCity); pstmt.setString(4, locationCountry); pstmt.setString(5, locationStreetAddress); if (latitude != null) { pstmt.setDouble(6, latitude); } else { pstmt.setNull(6, Types.DOUBLE); } if (longitude != null) { pstmt.setDouble(7, longitude); } else { pstmt.setNull(7, Types.DOUBLE); } pstmt.setLong(8, originalPostingTime); pstmt.setString(9, userNickname); pstmt.setString(10, username); if (weather != null) { pstmt.setString(11, weather); } else { pstmt.setNull(11, Types.VARCHAR); } pstmt.executeUpdate(); return true; } catch (SQLException e) { System.err.println("Error adding message: " + e.getMessage()); e.printStackTrace(); return false; } } public ResultSet getAllMessages() throws SQLException { final String sql = "SELECT locationID, locationName, locationDescription, locationCity, " + "locationCountry, locationStreetAddress, latitude, longitude, " + "originalPostingTime, originalPoster, weather " + "FROM messages " + "ORDER BY originalPostingTime DESC"; Statement statement = dbconnection.createStatement(); return statement.executeQuery(sql); } }package com.server; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpExchange; import java.io.*; import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.util.stream.Collectors; import org.json.JSONException; import org.json.JSONObject; public class RegistrationHandler_217230206 implements HttpHandler{ private final UserAuthenticator_217230206 userAuthenticator; private final MessageDatabase_217230206 database; public RegistrationHandler_217230206(UserAuthenticator_217230206 userAuthenticator, MessageDatabase_217230206 database) { this.userAuthenticator = userAuthenticator; this.database = database; } @Override public void handle(HttpExchange exchange) throws IOException { String requestMethod = exchange.getRequestMethod(); try { if (requestMethod.equalsIgnoreCase("POST")) { handlePostRequest(exchange); } else { handleUnsupportedRequest(exchange); } } catch (Exception e) { sendErrorResponse(exchange, 500, "Internal Server Error"); } } private void handlePostRequest(HttpExchange exchange) throws IOException { String contentType = exchange.getRequestHeaders().getFirst("Content-Type"); if (contentType == null || !contentType.equals("application/json")) { sendErrorResponse(exchange, 400, "Content-Type must be application/json"); return; } String content; try (InputStream stream = exchange.getRequestBody(); InputStreamReader isr = new InputStreamReader(stream, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr)) { content = br.lines().collect(Collectors.joining("\n")); } try { JSONObject json = new JSONObject(content); if (!json.has("username") || !json.has("password") || !json.has("email") || !json.has("userNickname")) { sendErrorResponse(exchange, 400, "Missing required fields: username, password, email, userNickname"); return; } String username = json.getString("username").trim(); String password = json.getString("password").trim(); String email = json.getString("email").trim(); String userNickname = json.getString("userNickname").trim(); if (username.isEmpty() || password.isEmpty() || email.isEmpty() || userNickname.isEmpty()) { sendErrorResponse(exchange, 400, "All fields must not be empty"); return; } boolean dbSuccess = database.addUser(username, password, email, userNickname); if (dbSuccess) { userAuthenticator.addUser(username, password, email, userNickname); JSONObject responseJson = new JSONObject(); responseJson.put("message", "User registered successfully"); responseJson.put("username", username); sendJsonResponse(exchange, 200, responseJson); } else { sendErrorResponse(exchange, 409, "User already registered"); } } catch (JSONException e) { sendErrorResponse(exchange, 400, "Invalid JSON format: " + e.getMessage()); } catch (SQLException e) { if (e.getMessage() != null && (e.getMessage().contains("UNIQUE constraint failed") || e.getMessage().contains("unique constraint") || e.getErrorCode() == 19)) { sendErrorResponse(exchange, 409, "User already registered"); } else { System.err.println("Database error during registration: " + e.getMessage()); sendErrorResponse(exchange, 500, "Database error: " + e.getMessage()); } } catch (Exception e) { System.err.println("Unexpected error during registration: " + e.getMessage()); sendErrorResponse(exchange, 500, "Internal server error"); } } private void handleUnsupportedRequest(HttpExchange exchange) throws IOException { sendErrorResponse(exchange, 400, "Not supported"); } private void sendErrorResponse(HttpExchange exchange, int code, String message) throws IOException { JSONObject errorJson = new JSONObject(); errorJson.put("error", message); sendJsonResponse(exchange, code, errorJson); } private void sendJsonResponse(HttpExchange exchange, int code, JSONObject json) throws IOException { String response = json.toString(); byte[] bytes = response.getBytes(StandardCharsets.UTF_8); exchange.getResponseHeaders().set("Content-Type", "application/json; charset=UTF-8"); exchange.sendResponseHeaders(code, bytes.length); try (OutputStream outputStream = exchange.getResponseBody()) { outputStream.write(bytes); } } } package com.server; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import org.json.JSONObject; import org.json.JSONArray; import org.json.JSONException; import java.io.*; import java.nio.charset.StandardCharsets; import java.sql.Statement; import java.sql.ResultSet; import java.sql.SQLException; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Base64; public class RequestHandler_217230206 implements HttpHandler { private final MessageDatabase_217230206 database; private final WeatherServiceClient_217230206 weatherClient; public RequestHandler_217230206(MessageDatabase_217230206 database) { this.database = database; this.weatherClient = new WeatherServiceClient_217230206("http://localhost:4001/weather"); } @Override public void handle(HttpExchange exchange) throws IOException { String requestMethod = exchange.getRequestMethod(); try { if (requestMethod.equalsIgnoreCase("GET")) { handleGetRequest(exchange); } else if (requestMethod.equalsIgnoreCase("POST")) { handlePostRequest(exchange); } else { sendErrorResponse(exchange, 405, "Method Not Allowed"); } } catch (Exception e) { sendErrorResponse(exchange, 500, "Internal Server Error"); } } private void handleGetRequest(HttpExchange exchange) throws IOException { if (!authenticateUser(exchange)) { return; } try { ResultSet rs = database.getAllMessages(); JSONArray responseArray = new JSONArray(); boolean hasMessages = false; while (rs.next()) { hasMessages = true; JSONObject messageJson = new JSONObject(); messageJson.put("locationID", rs.getInt("locationID")); messageJson.put("locationName", rs.getString("locationName")); messageJson.put("locationCountry", rs.getString("locationCountry")); messageJson.put("locationDescription", rs.getString("locationDescription")); messageJson.put("locationCity", rs.getString("locationCity")); messageJson.put("longitude", rs.getDouble("longitude")); messageJson.put("latitude", rs.getDouble("latitude")); String locationCountry = rs.getString("locationCountry"); if (locationCountry != null && !rs.wasNull()) { messageJson.put("locationCountry", locationCountry); } else { messageJson.put("locationCountry", ""); } String locationStreetAddress = rs.getString("locationStreetAddress"); if (locationStreetAddress != null && !rs.wasNull()) { messageJson.put("locationStreetAddress", locationStreetAddress); } else { messageJson.put("locationStreetAddress", ""); } double latitude = rs.getDouble("latitude"); if (!rs.wasNull()) { messageJson.put("latitude", latitude); } double longitude = rs.getDouble("longitude"); if (!rs.wasNull()) { messageJson.put("longitude", longitude); } messageJson.put("originalPoster", rs.getString("originalPoster")); long epochMillis = rs.getLong("originalPostingTime"); String isoTime = convertEpochToISO(epochMillis); messageJson.put("originalPostingTime", isoTime); String weather = rs.getString("weather"); if (!rs.wasNull() && weather != null) { messageJson.put("weather", weather); } responseArray.put(messageJson); } try { if (rs != null) { Statement stmt = rs.getStatement(); rs.close(); if (stmt != null) { stmt.close(); } } } catch (SQLException e) { System.err.println("Error closing resources: " + e.getMessage()); } if (!hasMessages) { exchange.sendResponseHeaders(204, -1); } else { sendJsonResponse(exchange, 200, responseArray); } } catch (SQLException e) { sendErrorResponse(exchange, 500, "Database error: " + e.getMessage()); } } private void handlePostRequest(HttpExchange exchange) throws IOException { if (!authenticateUser(exchange)) { return; } String contentType = exchange.getRequestHeaders().getFirst("Content-Type"); if (contentType == null || !contentType.equals("application/json")) { sendErrorResponse(exchange, 400, "Content-Type must be application/json"); return; } String requestBody = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8); try { JSONObject json = new JSONObject(requestBody); if (!json.has("locationName") || !json.has("locationDescription") || !json.has("locationCity") || !json.has("originalPostingTime")) { sendErrorResponse(exchange, 400, "Missing required fields: locationName, locationDescription, locationCity, originalPostingTime"); return; } String locationName = json.getString("locationName").trim(); String locationDescription = json.getString("locationDescription").trim(); String locationCity = json.getString("locationCity").trim(); String originalPostingTimeStr = json.getString("originalPostingTime").trim(); String locationCountry = json.optString("locationCountry", "").trim(); String locationStreetAddress = json.optString("locationStreetAddress", "").trim(); Double latitude = null; Double longitude = null; if (json.has("latitude") && !json.isNull("latitude")) { try { latitude = json.getDouble("latitude"); } catch (Exception e) { } } if (json.has("longitude") && !json.isNull("longitude")) { try { longitude = json.getDouble("longitude"); } catch (Exception e) { } } String weather = null; boolean hasWeatherInRequest = json.has("weather") && !json.isNull("weather"); if (hasWeatherInRequest) { weather = json.optString("weather", null); } if (locationName.isEmpty() || locationDescription.isEmpty() || locationCity.isEmpty()) { sendErrorResponse(exchange, 400, "All required fields must not be empty"); return; } long epochMillis = validateAndParseTimestamp(exchange, originalPostingTimeStr); if (epochMillis == -1) { return; } String authHeader = exchange.getRequestHeaders().getFirst("Authorization"); String username = extractUsernameFromAuth(authHeader); if (latitude != null && longitude != null) { String weatherInfo = weatherClient.getWeather(latitude, longitude); if (weatherInfo != null) { weather = weatherInfo; System.out.println("Retrieved weather: " + weatherInfo); } else { System.out.println("Failed to retrieve weather information"); } } boolean success = database.addMessage(locationName, locationDescription, locationCity, locationCountry, locationStreetAddress, latitude, longitude, epochMillis, username, weather); if (success) { JSONObject responseJson = new JSONObject(); responseJson.put("message", "Message stored successfully"); responseJson.put("locationName", locationName); responseJson.put("originalPostingTime", originalPostingTimeStr); if (latitude != null) { responseJson.put("latitude", latitude); } if (longitude != null) { responseJson.put("longitude", longitude); } if (weather != null) { responseJson.put("weather", weather); } sendJsonResponse(exchange, 200, responseJson); } else { sendErrorResponse(exchange, 500, "Failed to store message"); } } catch (JSONException e) { sendErrorResponse(exchange, 400, "Invalid JSON format: " + e.getMessage()); } catch (SQLException e) { sendErrorResponse(exchange, 500, "Database error: " + e.getMessage()); } } private boolean authenticateUser(HttpExchange exchange) throws IOException { String authHeader = exchange.getRequestHeaders().getFirst("Authorization"); if (authHeader == null || !authHeader.startsWith("Basic ")) { sendErrorResponse(exchange, 401, "Authentication required"); return false; } try { String encodedCredentials = authHeader.substring("Basic ".length()).trim(); byte[] decodedBytes = Base64.getDecoder().decode(encodedCredentials); String credentials = new String(decodedBytes, StandardCharsets.UTF_8); String[] parts = credentials.split(":", 2); if (parts.length != 2) { sendErrorResponse(exchange, 401, "Invalid authentication credentials"); return false; } String userName = parts[0]; String password = parts[1]; if (database.validateUser(userName, password)) { return true; } else { sendErrorResponse(exchange, 401, "Invalid username or password"); return false; } } catch (Exception e) { sendErrorResponse(exchange, 401, "Invalid authentication credentials"); return false; } } private String extractUsernameFromAuth(String authHeader) { try { String encodedCredentials = authHeader.substring("Basic ".length()).trim(); byte[] decodedBytes = Base64.getDecoder().decode(encodedCredentials); String credentials = new String(decodedBytes, StandardCharsets.UTF_8); String[] parts = credentials.split(":", 2); if (parts.length == 2) { return parts[0]; } } catch (Exception e) { } return null; } private long validateAndParseTimestamp(HttpExchange exchange, String timestampStr) throws IOException { if (timestampStr == null || timestampStr.trim().isEmpty()) { sendErrorResponse(exchange, 400, "Timestamp cannot be empty"); return -1; } try { Instant instant = Instant.parse(timestampStr); long epochMillis = instant.toEpochMilli(); if (!isValidTimestamp(epochMillis)) { sendErrorResponse(exchange, 400, "Invalid timestamp value"); return -1; } return epochMillis; } catch (DateTimeParseException e) { sendErrorResponse(exchange, 400, "Invalid timestamp format. Use ISO 8601 UTC format like: 2024-01-15T10:30:00.000Z"); return -1; } } private boolean isValidTimestamp(long epochMillis) { long currentTime = System.currentTimeMillis(); long reasonablePast = currentTime - (100L * 365 * 24 * 60 * 60 * 1000); long reasonableFuture = currentTime + (10L * 365 * 24 * 60 * 60 * 1000); return epochMillis >= reasonablePast && epochMillis <= reasonableFuture; } private String convertEpochToISO(long epochMillis) { return ZonedDateTime.ofInstant( java.time.Instant.ofEpochMilli(epochMillis), ZoneId.of("UTC") ).format(DateTimeFormatter.ISO_INSTANT); } private void sendJsonResponse(HttpExchange exchange, int statusCode, Object json) throws IOException { String response = json.toString(); byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8); exchange.getResponseHeaders().set("Content-Type", "application/json; charset=UTF-8"); exchange.sendResponseHeaders(statusCode, responseBytes.length); try (OutputStream os = exchange.getResponseBody()) { os.write(responseBytes); } } private void sendErrorResponse(HttpExchange exchange, int code, String message) throws IOException { JSONObject errorJson = new JSONObject(); errorJson.put("error", message); sendJsonResponse(exchange, code, errorJson); } }package com.server; import com.sun.net.httpserver.HttpsServer; import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsParameters; import com.sun.net.httpserver.HttpContext; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; import java.io.*; import java.net.InetSocketAddress; import java.security.KeyStore; import java.sql.SQLException; import javax.net.ssl.KeyManagerFactory; import java.util.concurrent.Executors; public class Server { private static SSLContext myServerSSLContext(String keystorePath, String keystorePassword) throws Exception { KeyStore ks = KeyStore.getInstance("JKS"); File keystoreFile = new File(keystorePath); if (!keystoreFile.exists()) { throw new FileNotFoundException("Keystore file not found: " + keystorePath); } try (FileInputStream fis = new FileInputStream(keystoreFile)) { ks.load(fis, keystorePassword.toCharArray()); } KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, keystorePassword.toCharArray()); SSLContext ssl = SSLContext.getInstance("TLS"); ssl.init(kmf.getKeyManagers(), null, null); return ssl; } public static void main(String[] args) throws IOException { try { System.out.println("Starting server initialization..."); Class.forName("org.sqlite.JDBC"); String keystorePath; String keystorePassword; if (args.length < 2) { System.out.println("No arguments provided, using default keystore.jks and password 'password'"); keystorePath = "keystore.jks"; keystorePassword = "password"; } else { keystorePath = args[0]; keystorePassword = args[1]; } File keystoreFile = new File(keystorePath); if (!keystoreFile.exists()) { System.out.println("Keystore file not found: " + keystorePath); System.out.println("Please generate keystore.jks file first"); return; } MessageDatabase_217230206 database = MessageDatabase_217230206.getInstance(); database.open("MessageDB.db"); System.out.println("Database opened successfully"); try { if (database.userExists("test")) { System.out.println("Database connection test passed"); } } catch (SQLException e) { System.err.println("Database connection test failed: " + e.getMessage()); } HttpsServer server = HttpsServer.create(new InetSocketAddress(8001), 0); SSLContext sslContext = myServerSSLContext(keystorePath, keystorePassword); server.setHttpsConfigurator(new HttpsConfigurator(sslContext) { @Override public void configure(HttpsParameters params) { SSLParameters sslparams = getSSLContext().getDefaultSSLParameters(); params.setSSLParameters(sslparams); } }); server.setExecutor(Executors.newCachedThreadPool()); System.out.println("Multi-threaded executor enabled"); UserAuthenticator_217230206 authenticator = new UserAuthenticator_217230206(database); HttpContext infoContext = server.createContext("/info", new RequestHandler_217230206(database)); infoContext.setAuthenticator(authenticator); server.createContext("/registration", new RegistrationHandler_217230206(authenticator, database)); server.start(); System.out.println("HTTPS Server started on port 8001"); System.out.println("Database: MessageDB.db"); System.out.println("Available endpoints:"); System.out.println("- /info (requires authentication)"); System.out.println("- /registration (user registration)"); System.out.println("Server is ready for testing"); Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("Shutting down server..."); try { database.close(); } catch (SQLException e) { System.err.println("Error closing database: " + e.getMessage()); } server.stop(0); System.out.println("Server stopped gracefully"); })); } catch (FileNotFoundException e) { System.out.println("Certificate file not found!"); e.printStackTrace(); } catch (Exception e) { System.out.println("Error starting server: " + e.getMessage()); e.printStackTrace(); } } }package com.server; public class User_217230206 { private String username; private String password; private String email; private String userNickname; public User_217230206(String username, String password, String email, String userNickname) { this.username = username; this.password = password; this.email = email; this.userNickname = userNickname; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getUserNickname() { return userNickname; } public void setUserNickname(String userNickname) { this.userNickname = userNickname; } }package com.server; import com.sun.net.httpserver.BasicAuthenticator; import java.sql.SQLException; import java.util.Hashtable; import java.util.Map; public class UserAuthenticator_217230206 extends BasicAuthenticator { private Map<String, User_217230206> users = null; private MessageDatabase_217230206 database; public UserAuthenticator_217230206(MessageDatabase_217230206 database) { super("info"); this.database = database; users = new Hashtable<>(); } @Override public boolean checkCredentials(String username, String password) { try { return database.validateUser(username, password); } catch (SQLException e) { return false; } } public boolean addUser(String userName, String password, String email, String userNickname) { try { boolean dbSuccess = database.addUser(userName, password, email, userNickname); if (dbSuccess) { users.put(userName, new User_217230206(userName, password, email, userNickname)); return true; } return false; } catch (SQLException e) { return false; } } }package com.server; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; public class UserMessage_217230206 { private String locationName; private String locationDescription; private String locationCity; private long originalPostingTime; public UserMessage_217230206(String locationName, String locationDescription, String locationCity) { this.locationName = locationName; this.locationDescription = locationDescription; this.locationCity = locationCity; this.originalPostingTime = ZonedDateTime.now(ZoneId.of("UTC")).toInstant().toEpochMilli(); } public UserMessage_217230206(String locationName, String locationDescription, String locationCity, long originalPostingTime) { this.locationName = locationName; this.locationDescription = locationDescription; this.locationCity = locationCity; this.originalPostingTime = originalPostingTime; } public String getLocationName() { return locationName; } public void setLocationName(String locationName) { this.locationName = locationName; } public String getLocationDescription() { return locationDescription; } public void setLocationDescription(String locationDescription) { this.locationDescription = locationDescription; } public String getLocationCity() { return locationCity; } public void setLocationCity(String locationCity) { this.locationCity = locationCity; } public long getOriginalPostingTime() { return originalPostingTime; } public void setOriginalPostingTime(long originalPostingTime) { this.originalPostingTime = originalPostingTime; } public String getOriginalPostingTimeISO() { return ZonedDateTime.ofInstant( java.time.Instant.ofEpochMilli(originalPostingTime), ZoneId.of("UTC") ).format(DateTimeFormatter.ISO_INSTANT); } } package com.server; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; public class WeatherServiceClient_217230206 { private final String weatherServiceUrl; private final HttpClient httpClient; public WeatherServiceClient_217230206(String weatherServiceUrl) { this.weatherServiceUrl = weatherServiceUrl; this.httpClient = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(5)) .build(); } public String getWeather(double latitude, double longitude) { try { String xmlBody = String.format( "<coordinates><latitude>%f</latitude><longitude>%f</longitude></coordinates>", latitude, longitude ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(weatherServiceUrl)) .header("Content-Type", "application/xml") .POST(HttpRequest.BodyPublishers.ofString(xmlBody)) .build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200) { return extractTemperatureFromXml(response.body()); } else { System.err.println("Weather service returned error: " + response.statusCode()); return null; } } catch (Exception e) { System.err.println("Error calling weather service: " + e.getMessage()); return null; } } private String extractTemperatureFromXml(String xmlResponse) { try { int tempStart = xmlResponse.indexOf("<temperature>") + "<temperature>".length(); int tempEnd = xmlResponse.indexOf("</temperature>"); if (tempStart > 0 && tempEnd > tempStart) { String temperature = xmlResponse.substring(tempStart, tempEnd); int unitStart = xmlResponse.indexOf("<Unit>") + "<Unit>".length(); int unitEnd = xmlResponse.indexOf("</Unit>"); String unit = unitStart > 0 && unitEnd > unitStart ? xmlResponse.substring(unitStart, unitEnd) : "C"; return temperature + unit; } } catch (Exception e) { System.err.println("Error parsing weather XML: " + e.getMessage()); } return null; } }这是已经写的代码,但是没有办法通过测试,有下面两个错误org.opentest4j.AssertionFailedError: Test failed, Object {"locationStreetAddress":"Street of D","locationName":"Place A","locationCountry":"In a C country","locationDescription":"Some random place A","latitude":1.3670745662396455,"originalPoster":"Tallaaja_123","originalPostingTime":"2025-11-18T06:52:31.570Z","locationCity":"City of B","longitude":148.53484155175929} could not be found in response ==] expected: [true] but was: [false] at com.tests.Week5.testCoordinateDescription(Week5.java:284) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)org.opentest4j.AssertionFailedError: Test failed, user registration returned code 409 ==] expected: [true] but was: [false] at com.tests.Week5.testRegisterUser(Week5.java:79) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
11-19
这个错误信息 "Cannot start service HostA: Address already in use" 意味着在启动HostA服务时,发现要使用的地址已经被其他服务占用了。这种情况通常是因为在同一个主机上有多个服务尝试使用相同的端口号。您可以通过以下方式解决这个问题: 1. 检查您的主机上正在运行的服务,确认是否有其他服务已经在使用相同的端口号。您可以使用命令`netstat -tuln` 查看已经打开的端口和相关的服务。 2. 如果发现有其他服务在使用相同的端口号,您可以选择停止或重新配置该服务,以便让HostA服务能够使用该端口。您可以通过修改服务的配置文件或使用不同的端口号来解决冲突。 3. 如果您不确定哪个服务正在使用该端口,您可以尝试使用命令`lsof -i :端口号`来查找正在使用特定端口的进程。 4. 如果您确定没有其他服务在使用相同的端口号,但仍然遇到该错误,请检查您的网络配置是否正确。可能是由于IP地址和主机名不对应导致的。确保主机名和IP地址的映射关系正确,并且没有任何冲突。 综上所述,当遇到 "Cannot start service HostA: Address already in use" 错误时,您可以通过检查正在使用的端口号,停止或重新配置其他服务,或检查网络配置来解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux安装Oracle 11g R2安装过程中遇到的报错及解决办法](https://blog.youkuaiyun.com/majishushu/article/details/71678349)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值