Index: /pom.xml
===================================================================
--- /pom.xml	(revision 11)
+++ /pom.xml	(revision 12)
@@ -6,5 +6,5 @@
 	<artifactId>profilesserver</artifactId>
 	<packaging>war</packaging>
-	<version>1.3.1</version>
+	<version>1.4.0</version>
 	<name>profileserver Maven Webapp</name>
 	<url>http://maven.apache.org</url>
@@ -18,4 +18,5 @@
 		<jackson-2-version>2.9.10</jackson-2-version>
 		<tomcat.version>8.5.20</tomcat.version>
+		<geniusweb.version>1.4.0</geniusweb.version>
 	</properties>
 
@@ -50,5 +51,5 @@
 			<groupId>geniusweb</groupId>
 			<artifactId>profile</artifactId>
-			<version>1.3.1</version>
+			<version>${geniusweb.version}</version>
 		</dependency>
 
@@ -56,5 +57,5 @@
 			<groupId>geniusweb</groupId>
 			<artifactId>bidspace</artifactId>
-			<version>1.3.1</version>
+			<version>${geniusweb.version}</version>
 		</dependency>
 
@@ -213,5 +214,6 @@
 
 	<build>
-		<finalName>profilesserver</finalName>
+		<finalName>profilesserver-1.4.0</finalName>
+
 
 
@@ -247,4 +249,20 @@
 				</executions>
 			</plugin>
+
+			<!-- This makes but does not install the jar <plugin> <groupId>org.apache.maven.plugins</groupId> 
+				<artifactId>maven-jar-plugin</artifactId> <executions> <execution> <id>make-a-jar</id> 
+				<phase>compile</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> 
+				</plugin> -->
+			<!-- This does nothign <plugin> <artifactId>maven-war-plugin</artifactId> 
+				<configuration> <archiveClasses>true</archiveClasses> </configuration> </plugin> -->
+
+			<plugin>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>3.2.3</version>
+				<configuration>
+					<attachClasses>true</attachClasses>
+				</configuration>
+			</plugin>
+
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
@@ -327,33 +345,12 @@
 				</executions>
 			</plugin>
-
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<version>2.4.1</version>
-				<configuration>
-					<!-- get all project dependencies -->
-					<descriptorRefs>
-						<descriptorRef>jar-with-dependencies</descriptorRef>
-					</descriptorRefs>
-					<archive>
-						<manifest>
-							<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
-							<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
-						</manifest>
-					</archive>
-				</configuration>
-				<executions>
-					<execution>
-						<id>make-assembly</id>
-						<!-- bind to the packaging phase -->
-						<phase>package</phase>
-						<goals>
-							<goal>single</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-
+			<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> 
+				<version>2.4.1</version> <configuration> get all project dependencies <descriptorRefs> 
+				<descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> 
+				<manifest> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> 
+				<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> </manifest> 
+				</archive> </configuration> <executions> <execution> <id>make-assembly</id> 
+				bind to the packaging phase <phase>package</phase> <goals> <goal>single</goal> 
+				</goals> </execution> </executions> </plugin> -->
 
 			<!-- Special plugin for the tomcat embedded stuff? -->
@@ -410,4 +407,5 @@
 				</plugin>
 			</plugins>
+
 		</pluginManagement>
 
Index: /src/main/java/geniusweb/profilesserver/AutoUpdatingProfilesFactory.java
===================================================================
--- /src/main/java/geniusweb/profilesserver/AutoUpdatingProfilesFactory.java	(revision 11)
+++ /src/main/java/geniusweb/profilesserver/AutoUpdatingProfilesFactory.java	(revision 12)
@@ -2,5 +2,7 @@
 
 import java.io.File;
+import java.io.FileWriter;
 import java.io.IOException;
+import java.io.Writer;
 import java.net.URISyntaxException;
 import java.nio.file.Path;
@@ -63,4 +65,32 @@
 	}
 
+	@Override
+	public synchronized void putProfile(Profile profile) throws IOException {
+		if (!available.containsKey(profile.getDomain())) {
+			throw new IOException("profile's domain does not exist");
+		}
+		String domainname = profile.getDomain().getName();
+		String profilename = profile.getName();
+		if (!profilename.matches("[a-zA-Z0-9-]+"))
+			throw new IOException("illegal profile name " + profilename
+					+ ", only letters, numbers and - allowed");
+		File file = Paths
+				.get(rootdir.toString(), domainname, profilename + JSON)
+				.toFile();
+		if (file.exists()) {
+			String msg = fileCheck(file, false, true);
+			if (msg != null)
+				throw new IOException(msg);
+		}
+
+		// CHECK utf-8 compatibility? Do we need that anyway?
+		try (Writer out = new FileWriter(file, false)) {
+			out.write(Jackson.instance().writeValueAsString(profile));
+		}
+		// trigger the update immediately, avoid wait for FileChecker.
+		super.add(profile);
+
+	}
+
 	/**
 	 * Called when some file that may be relevant has changed. Synchronized to
@@ -267,5 +297,6 @@
 
 	/**
-	 * check and report basic problems with a file.
+	 * Silent check and report basic problems with a file. Silent in the sense
+	 * that errors are logged but cause no exception.
 	 * 
 	 * @param file              the file to check
@@ -275,25 +306,42 @@
 	 */
 	private boolean basicFileCheck(File file, boolean shouldbeDirectory) {
+		String msg = fileCheck(file, shouldbeDirectory, false);
+		if (msg != null) {
+			log.log(Level.WARNING, msg);
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 
+	 * @param file              the file to check
+	 * @param shouldbeDirectory true if expected a directory
+	 * @param shouldbeWritable  true if expected to be writable
+	 * @return null if file is there, is file/directory, allows reading and
+	 *         allows writing (if specified).
+	 */
+	private String fileCheck(File file, boolean shouldbeDirectory,
+			boolean shouldbeWritable) {
 		if (!file.exists()) {
-			log.log(Level.WARNING, file + " is missing");
-			return false;
+			return file + " is missing";
 		}
 		if (!file.canRead()) {
-			log.log(Level.WARNING,
-					"directory " + file + "does not allow reading ");
-			return false;
+			return "directory " + file + "does not allow reading ";
 		}
 		if (shouldbeDirectory) {
 			if (!file.isDirectory()) {
-				log.log(Level.WARNING, file + " is not a directory");
-				return false;
+				return file + " is not a directory";
 			}
 		} else {
 			if (!file.isFile()) {
-				log.log(Level.WARNING, file + " is not a file");
-				return false;
-			}
-		}
-		return true;
+				return file + " is not a file";
+			}
+		}
+		if (shouldbeWritable && !file.canWrite()) {
+			return file + "is read-only";
+		}
+		return null;
+
 	}
 
Index: /src/main/java/geniusweb/profilesserver/DefaultProfilesFactory.java
===================================================================
--- /src/main/java/geniusweb/profilesserver/DefaultProfilesFactory.java	(revision 11)
+++ /src/main/java/geniusweb/profilesserver/DefaultProfilesFactory.java	(revision 12)
@@ -1,4 +1,5 @@
 package geniusweb.profilesserver;
 
+import java.io.IOException;
 import java.util.Collections;
 import java.util.LinkedList;
@@ -84,4 +85,12 @@
 	}
 
+	@Override
+	public synchronized void putProfile(Profile profile) throws IOException {
+		if (!available.containsKey(profile.getDomain())) {
+			throw new IOException("profile's domain does not exist");
+		}
+		add(profile);
+	}
+
 	/**************** support for updating ***************/
 	/**
Index: /src/main/java/geniusweb/profilesserver/ProfilesFactory.java
===================================================================
--- /src/main/java/geniusweb/profilesserver/ProfilesFactory.java	(revision 11)
+++ /src/main/java/geniusweb/profilesserver/ProfilesFactory.java	(revision 12)
@@ -1,4 +1,5 @@
 package geniusweb.profilesserver;
 
+import java.io.IOException;
 import java.util.List;
 
@@ -40,3 +41,12 @@
 	List<Profile> getProfiles(String domainname);
 
+	/**
+	 * Permanently (over)write a profile to the repository (not just in memory).
+	 * 
+	 * @param profile the profile to be written. The domain file must exist and
+	 *                match.
+	 * @throws IOException if the profile does not meet the requirements.
+	 */
+	void putProfile(Profile profile) throws IOException;
+
 }
Index: /src/main/webapp/WEB-INF/web.xml
===================================================================
--- /src/main/webapp/WEB-INF/web.xml	(revision 11)
+++ /src/main/webapp/WEB-INF/web.xml	(revision 12)
@@ -6,24 +6,41 @@
 	<display-name>Domains and Profiles server</display-name>
 
-<servlet>
-    <!-- List files in /ws-definitions -->
-    <servlet-name>listrepo</servlet-name>
-    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
-    <init-param>
-        <param-name>debug</param-name>
-        <param-value>0</param-value>
-    </init-param>
-    <init-param>
-        <param-name>listings</param-name>
-        <param-value>true</param-value>
-    </init-param>
-    <load-on-startup>100</load-on-startup>
-</servlet>
+	<filter>
+		<filter-name>CorsFilter</filter-name>
+		<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
+		<init-param>
+			<param-name>cors.allowed.origins</param-name>
+			<param-value>*</param-value>
+		</init-param>
+		<init-param>
+			<param-name>cors.exposed.headers</param-name>
+			<param-value>Access-Control-Allow-Origin</param-value>
+		</init-param>
+	</filter>
+	<filter-mapping>
+		<filter-name>CorsFilter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
 
-<servlet-mapping>
-    <servlet-name>listrepo</servlet-name>
-    <url-pattern>/domainsrepo/*</url-pattern>
-</servlet-mapping>
-    
+	<servlet>
+		<!-- List files in /ws-definitions -->
+		<servlet-name>listrepo</servlet-name>
+		<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
+		<init-param>
+			<param-name>debug</param-name>
+			<param-value>0</param-value>
+		</init-param>
+		<init-param>
+			<param-name>listings</param-name>
+			<param-value>true</param-value>
+		</init-param>
+		<load-on-startup>100</load-on-startup>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>listrepo</servlet-name>
+		<url-pattern>/domainsrepo/*</url-pattern>
+	</servlet-mapping>
+
 </web-app>
 
Index: /src/test/java/geniusweb/profilesserver/AutoUpdatingProfilesFactoryTest.java
===================================================================
--- /src/test/java/geniusweb/profilesserver/AutoUpdatingProfilesFactoryTest.java	(revision 11)
+++ /src/test/java/geniusweb/profilesserver/AutoUpdatingProfilesFactoryTest.java	(revision 12)
@@ -222,4 +222,20 @@
 	}
 
+	@Test
+	public void saveProfileTest() throws IOException {
+		assertEquals(0, changes.size());
+		LinearAdditiveUtilitySpace profile = (LinearAdditiveUtilitySpace) factory
+				.getProfile(JOB1);
+		Profile newprofile = new LinearAdditiveUtilitySpace(profile.getDomain(),
+				"jobsA", profile.getUtilities(), profile.getWeights(),
+				profile.getReservationBid());
+		factory.putProfile(newprofile);
+		// check response immediately
+		assertEquals(1, changes.size());
+		assertTrue(changes.get(0) instanceof ProfileChangeEvent);
+		// check file was written
+		assertTrue(copyrepodir.resolve("jobs/jobsA.json").toFile().exists());
+	}
+
 	/**
 	 * We remove jobs domain.
