001package org.andromda.core.server; 002 003import java.io.DataInputStream; 004import java.io.IOException; 005import java.io.ObjectInputStream; 006import java.io.ObjectOutputStream; 007import java.net.ServerSocket; 008import java.net.Socket; 009import java.net.SocketTimeoutException; 010import org.andromda.core.common.AndroMDALogger; 011import org.andromda.core.configuration.Configuration; 012import org.andromda.core.engine.Engine; 013 014/** 015 * The default AndroMDA {@link Server instance}. 016 * 017 * @author Chad Brandon 018 */ 019public class DefaultServer 020 implements Server 021{ 022 /** 023 * The message sent to the client when AndroMDA processing has completed. 024 */ 025 private static final String COMPLETE = "complete"; 026 027 /** 028 * The command sent to the server that indicates it 029 * should stop. 030 */ 031 static final String STOP = "stop"; 032 033 /** 034 * The server listener. 035 */ 036 private ServerSocket listener = null; 037 038 /** 039 * The AndroMDA Engine instance. 040 */ 041 private Engine engine = Engine.newInstance(); 042 043 /** 044 * @see org.andromda.core.server.Server#start(org.andromda.core.configuration.Configuration) 045 */ 046 public void start(final Configuration configuration) 047 { 048 engine.initialize(configuration); 049 if (configuration != null) 050 { 051 final org.andromda.core.configuration.Server serverConfiguration = configuration.getServer(); 052 if (serverConfiguration != null) 053 { 054 try 055 { 056 try 057 { 058 this.listener = new ServerSocket(serverConfiguration.getPort()); 059 final int modelLoadInterval = serverConfiguration.getLoadInterval(); 060 if (modelLoadInterval > 0) 061 { 062 this.listener.setSoTimeout(serverConfiguration.getLoadInterval()); 063 } 064 } 065 catch (final IOException exception) 066 { 067 throw new ServerException( 068 "Could not listen on port '" + serverConfiguration.getPort() + 069 "', change the port in your configuration"); 070 } 071 while (true) 072 { 073 try 074 { 075 final Socket client = this.listener.accept(); 076 if (client != null) 077 { 078 final ObjectOutputStream serverOutput = 079 new ObjectOutputStream(client.getOutputStream()); 080 final ObjectInputStream objectInput = 081 new ObjectInputStream(new DataInputStream(client.getInputStream())); 082 try 083 { 084 final Object object = objectInput.readObject(); 085 if (object instanceof Configuration) 086 { 087 this.engine.run((Configuration)object, false, null); 088 } 089 else if (object instanceof String) 090 { 091 final String string = (String)object; 092 if (string.equals(STOP)) 093 { 094 break; 095 } 096 } 097 } 098 catch (final Throwable throwable) 099 { 100 AndroMDALogger.error(throwable); 101 102 // - pass the exception to the client 103 serverOutput.writeObject(throwable); 104 } 105 106 // - signal to the client, it can stop waiting 107 serverOutput.writeObject(COMPLETE); 108 serverOutput.flush(); 109 serverOutput.close(); 110 objectInput.close(); 111 client.close(); 112 } 113 } 114 catch (final SocketTimeoutException exception) 115 { 116 try 117 { 118 this.engine.loadModelsIfNecessary(configuration); 119 this.resetFailedLoadAttempts(); 120 } 121 catch (final Throwable throwable) 122 { 123 this.incrementFailedLoadAttempts(); 124 125 // - only fail if the failed load attempts is greater than the maximum 126 if (this.failedLoadAttempts > serverConfiguration.getMaximumFailedLoadAttempts()) 127 { 128 throw throwable; 129 } 130 } 131 } 132 } 133 this.shutdown(); 134 } 135 catch (final Throwable throwable) 136 { 137 throw new ServerException(throwable); 138 } 139 } 140 } 141 } 142 143 /** 144 * Stores the failed load attempts. 145 */ 146 private int failedLoadAttempts; 147 148 /** 149 * Resets the failed load attempt counter. 150 */ 151 private void resetFailedLoadAttempts() 152 { 153 this.failedLoadAttempts = 0; 154 } 155 156 /** 157 * Increments the failed load attempt counter. 158 */ 159 private void incrementFailedLoadAttempts() 160 { 161 this.failedLoadAttempts++; 162 } 163 164 /** 165 * Shuts the server down. 166 */ 167 public void shutdown() 168 { 169 try 170 { 171 this.listener.close(); 172 this.listener = null; 173 this.engine.shutdown(); 174 } 175 catch (final IOException exception) 176 { 177 // ignore exception 178 } 179 } 180}