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