001 package net.abriraqui.dm4.importexport; 002 003 import de.deepamehta.core.osgi.PluginActivator; 004 import de.deepamehta.core.util.JavaUtils; 005 import de.deepamehta.core.util.DeepaMehtaUtils; 006 import de.deepamehta.core.service.PluginService; 007 import de.deepamehta.core.service.Plugin; 008 import de.deepamehta.core.service.annotation.ConsumesService; 009 import de.deepamehta.core.Topic; 010 import de.deepamehta.core.TopicType; 011 import de.deepamehta.core.ViewConfiguration; 012 import de.deepamehta.core.Association; 013 import de.deepamehta.core.model.TopicModel; 014 import de.deepamehta.core.model.CompositeValueModel; 015 import de.deepamehta.core.model.AssociationModel; 016 import de.deepamehta.core.model.RoleModel; 017 import de.deepamehta.core.model.SimpleValue; 018 import de.deepamehta.core.storage.spi.DeepaMehtaTransaction; 019 020 import de.deepamehta.plugins.topicmaps.service.TopicmapsService; 021 import de.deepamehta.plugins.topicmaps.model.TopicmapViewmodel; 022 import de.deepamehta.plugins.topicmaps.model.TopicViewmodel; 023 import de.deepamehta.plugins.topicmaps.model.AssociationViewmodel; 024 025 import de.deepamehta.plugins.files.service.FilesService; 026 import de.deepamehta.plugins.files.UploadedFile; 027 028 import javax.xml.stream.XMLStreamException; 029 import javax.xml.stream.XMLStreamWriter; 030 import javax.xml.stream.XMLOutputFactory; 031 import javax.xml.transform.OutputKeys; 032 import javax.xml.bind.DatatypeConverter; 033 034 import java.io.Writer; 035 import java.io.FileWriter; 036 import java.io.File; 037 import java.io.FileInputStream; 038 import java.io.InputStream; 039 import java.io.InputStreamReader; 040 import java.io.ByteArrayInputStream; 041 import java.io.ByteArrayOutputStream; 042 import java.io.IOException; 043 import java.io.BufferedInputStream; 044 import java.io.BufferedReader; 045 import java.io.DataInputStream; 046 047 import java.util.logging.Logger; 048 import java.util.Map; 049 import java.util.HashMap; 050 import java.util.List; 051 import java.util.ArrayList; 052 053 import org.codehaus.jettison.json.JSONObject; 054 import org.codehaus.jettison.json.JSONArray; 055 import org.codehaus.jettison.json.JSONException; 056 057 import javax.ws.rs.POST; 058 import javax.ws.rs.Path; 059 import javax.ws.rs.Produces; 060 import javax.ws.rs.Consumes; 061 import javax.ws.rs.CookieParam; 062 import javax.ws.rs.core.MediaType; 063 064 import com.sun.jersey.core.util.Base64; 065 066 067 @Path("/import-export") 068 @Produces("application/json") 069 public class ImportExportPlugin extends PluginActivator { 070 071 private TopicmapsService topicmapsService; 072 private FilesService filesService; 073 074 private Logger log = Logger.getLogger(getClass().getName()); 075 076 // Service implementation // 077 078 @POST 079 @Path("/export/json") 080 public Topic exportTopicmapToJSON(@CookieParam("dm4_topicmap_id") long topicmapId) { 081 082 try { 083 log.info("Exporting topicmap #########" + topicmapId); 084 TopicmapViewmodel topicmap = topicmapsService.getTopicmap(topicmapId, true); 085 String json = topicmap.toJSON().toString(); 086 InputStream in = new ByteArrayInputStream(json.getBytes("UTF-8")); 087 Topic createdFile = filesService.createFile(in, "/topicmap-" + topicmapId + ".txt"); 088 return createdFile; 089 } catch (Exception e) { 090 throw new RuntimeException("Export failed", e ); 091 } 092 } 093 094 095 096 @POST 097 @Path("/export/svg") 098 public void exportTopicmapToSVG(@CookieParam("dm4_topicmap_id") long topicmapId) throws XMLStreamException { 099 try { 100 final int BOX_HEIGHT = 20; 101 final int MARGIN_LEFT = 5; 102 final int MARGIN_TOP = 14; 103 final int ICON_WIDTH = 16; 104 final int ICON_HEIGHT = 16; 105 106 log.info("Exporting topicmap #########" + topicmapId); 107 TopicmapViewmodel topicmap = topicmapsService.getTopicmap(topicmapId, true); 108 Iterable<TopicViewmodel> topics =topicmap.getTopics(); 109 Iterable<AssociationViewmodel> associations = topicmap.getAssociations(); 110 111 String SVGfileName = "ExportedTopicamap-" + topicmapId +".svg"; 112 SVGRenderer svg = new SVGRenderer(SVGfileName); 113 114 for (AssociationViewmodel association : associations) { 115 String valueAssoc= association.getSimpleValue().toString(); 116 long topic1Id = association.getRoleModel1().getPlayerId(); 117 long topic2Id = association.getRoleModel2().getPlayerId(); 118 TopicViewmodel topic1 = topicmap.getTopic(topic1Id); 119 int x1 = topic1.getX(); 120 int y1 = topic1.getY(); 121 122 TopicViewmodel topic2 = topicmap.getTopic(topic2Id); 123 int x2 = topic2.getX(); 124 int y2 = topic2.getY(); 125 126 int dx = x2-x1; 127 int dy = y2-y1; 128 int label_x = dx/2; 129 int label_y = dy/2; 130 double assocLine = Math.sqrt(Math.pow(dx,2)+Math.pow(dy,2)); 131 double alpha = Math.asin(dy/assocLine)*180/Math.PI; 132 if (dx < 0) { 133 alpha = -alpha; 134 } 135 136 svg.line(x1, x2, y1, y2); 137 svg.text(label_x, label_y,x1+10,y1+10, valueAssoc, "grey", alpha); 138 139 } 140 141 142 for (TopicViewmodel topic : topics) { 143 String value= topic.getSimpleValue().toString(); 144 int x = topic.getX(); 145 int y = topic.getY(); 146 boolean visibility = topic.getVisibility(); 147 int boxWidth = value.length() * 9; 148 149 if (!visibility) { continue ;} 150 svg.rectangle(x - boxWidth / 2, y - BOX_HEIGHT / 2, boxWidth, BOX_HEIGHT, color(topic.getTypeUri())); 151 svg.text(x - boxWidth / 2 + MARGIN_LEFT, y - BOX_HEIGHT / 2 + MARGIN_TOP, value, "black"); 152 svg.image(x + boxWidth / 2, y, ICON_WIDTH, ICON_HEIGHT, typeIconDataUri(topic.getTypeUri())); 153 } 154 155 156 svg.closeDocument(); 157 158 } catch (Exception e) { 159 throw new RuntimeException("Export failed", e ); 160 } 161 } 162 163 164 165 @POST 166 @Path("/import") 167 @Consumes("multipart/form-data") 168 public Topic importTopicmap(UploadedFile file) { 169 try { 170 String json = file.getString(); 171 172 JSONObject topicmap = new JSONObject(json); 173 JSONObject info = topicmap.getJSONObject("info"); 174 175 JSONArray assocsArray = topicmap.getJSONArray("assocs"); 176 JSONArray topicsArray = topicmap.getJSONArray("topics"); 177 178 String origTopicmapName = info.getString("value"); 179 Topic importedTopicmap = topicmapsService.createTopicmap("Imported Topicmap: "+ origTopicmapName,"dm4.webclient.default_topicmap_renderer", null); 180 181 long topicmapId = importedTopicmap.getId(); 182 log.info("###### importedTopicapId " + topicmapId); 183 184 Map<Long, Long> mapTopicIds = new HashMap(); 185 importTopics(topicsArray, mapTopicIds, topicmapId); 186 importAssociations(assocsArray,mapTopicIds, topicmapId); 187 return importedTopicmap; 188 } catch (Exception e) { 189 throw new RuntimeException("Importing failed", e); 190 } 191 } 192 193 194 // Import topics 195 196 private void importTopics(JSONArray topicsArray, Map<Long, Long> mapTopicIds, long topicmapId) { 197 for (int i = 0, size = topicsArray.length(); i < size; i++) { 198 try { 199 JSONObject topic = topicsArray.getJSONObject(i); 200 createTopic(topic, mapTopicIds, topicmapId); 201 } catch (Exception e){ 202 log.warning("Topic not imported!!" + e); 203 } 204 } 205 } 206 // Import associations 207 208 private void importAssociations(JSONArray assocsArray, Map<Long, Long> mapTopicIds, long topicmapId) { 209 for (int i=0, size = assocsArray.length(); i< size; i++) { 210 try { 211 JSONObject association = assocsArray.getJSONObject(i); 212 createAssociation(association, mapTopicIds, topicmapId); 213 } catch (Exception e) { 214 log.warning("Association not imported"); 215 } 216 } 217 } 218 219 220 221 222 // Hook implementation // 223 224 @Override 225 @ConsumesService({TopicmapsService.class, FilesService.class }) 226 public void serviceArrived(PluginService service) { 227 if (service instanceof TopicmapsService) { 228 topicmapsService = (TopicmapsService) service; 229 } else if (service instanceof FilesService) { 230 filesService = (FilesService) service; 231 } 232 } 233 234 @Override 235 public void serviceGone(PluginService service) { 236 if (service == topicmapsService) { 237 topicmapsService = null; 238 } else if (service == filesService) { 239 filesService = null; 240 } 241 } 242 243 244 private String color(String typeUri) { 245 if (typeUri.equals("dm4.contacts.institution")) { 246 return "lightblue"; 247 } else if (typeUri.equals("dm4.contacts.person")) { 248 return "lightblue"; 249 } else if (typeUri.equals("dm4.notes.note")) { 250 return "lightblue"; 251 } else { 252 return "lightblue"; 253 } 254 } 255 256 257 private String typeIconDataUri(String typeUri) throws IOException { 258 TopicType topicType = dms.getTopicType(typeUri); 259 String iconPath = (String) topicType.getViewConfig("dm4.webclient.view_config","dm4.webclient.icon"); 260 int sep = iconPath.indexOf("/", 2); 261 String pluginPath = iconPath.substring(1, sep); 262 Plugin plugin = dms.getPlugin(pluginPath); 263 String imagePath = "web"+iconPath.substring(sep); 264 265 InputStream iconIS = plugin.getResourceAsStream(imagePath); 266 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 267 byte [] buffer = new byte[1024]; 268 int count = 0; 269 while ( (count = iconIS.read(buffer)) != -1 ) { 270 baos.write(buffer, 0, count); 271 } 272 273 byte [] fileContent = baos.toByteArray(); 274 //all chars in encoded are guaranteed to be 7-bit ASCII 275 byte[] encoded = Base64.encode(fileContent); 276 String imgBase64Str = new String(encoded); 277 log.info("##### IMG BASE64 " + imgBase64Str); 278 279 if (iconPath == null) { 280 iconPath = "/de.deepamehta.webclient/images/ball-gray.png"; 281 } 282 283 return "data:image/png;base64," + imgBase64Str; 284 285 } 286 287 288 private void createTopic(JSONObject topic, Map<Long, Long> mapTopicIds, long topicmapId) throws JSONException { 289 TopicModel model = new TopicModel(topic); 290 CompositeValueModel viewProps =new CompositeValueModel(topic.getJSONObject("view_props")); 291 long origTopicId = model.getId(); 292 293 Topic newTopic = dms.createTopic(model, null); 294 long topicId = newTopic.getId(); 295 296 mapTopicIds.put(origTopicId, topicId); 297 topicmapsService.addTopicToTopicmap(topicmapId, topicId, viewProps); 298 } 299 300 private void createAssociation(JSONObject association, Map<Long, Long> mapTopicIds, long topicmapId) { 301 AssociationModel assocModel = new AssociationModel(association); 302 RoleModel role1 = assocModel.getRoleModel1(); 303 role1.setPlayerId(mapTopicIds.get(role1.getPlayerId())); 304 RoleModel role2 = assocModel.getRoleModel2(); 305 role2.setPlayerId(mapTopicIds.get(role2.getPlayerId())); 306 Association newAssociation = dms.createAssociation(assocModel, null); 307 long assocId = newAssociation.getId(); 308 topicmapsService.addAssociationToTopicmap(topicmapId, assocId); 309 310 } 311 312 } 313