1 package org
.argeo
.suite
.workbench
.commands
;
3 import static org
.argeo
.connect
.util
.JxlUtils
.getStringValue
;
4 import static org
.argeo
.eclipse
.ui
.EclipseUiUtils
.notEmpty
;
7 import java
.io
.FileInputStream
;
8 import java
.io
.FileOutputStream
;
9 import java
.io
.IOException
;
10 import java
.io
.InputStream
;
11 import java
.io
.OutputStream
;
12 import java
.util
.Collections
;
13 import java
.util
.HashMap
;
15 import java
.util
.UUID
;
17 import javax
.jcr
.Node
;
18 import javax
.jcr
.Property
;
19 import javax
.jcr
.Repository
;
20 import javax
.jcr
.RepositoryException
;
21 import javax
.jcr
.Session
;
23 import org
.apache
.commons
.io
.IOUtils
;
24 import org
.argeo
.connect
.ConnectNames
;
25 import org
.argeo
.connect
.resources
.ResourcesNames
;
26 import org
.argeo
.connect
.resources
.ResourcesService
;
27 import org
.argeo
.connect
.util
.ConnectJcrUtils
;
28 import org
.argeo
.connect
.util
.JxlUtils
;
29 import org
.argeo
.eclipse
.ui
.EclipseUiUtils
;
30 import org
.argeo
.jcr
.JcrUtils
;
31 import org
.argeo
.people
.ContactValueCatalogs
;
32 import org
.argeo
.people
.PeopleException
;
33 import org
.argeo
.people
.PeopleNames
;
34 import org
.argeo
.people
.PeopleService
;
35 import org
.argeo
.people
.PeopleTypes
;
36 import org
.argeo
.people
.util
.PeopleJcrUtils
;
37 import org
.argeo
.people
.util
.PersonJcrUtils
;
38 import org
.argeo
.suite
.SuiteException
;
39 import org
.argeo
.suite
.workbench
.AsUiPlugin
;
40 import org
.eclipse
.core
.commands
.AbstractHandler
;
41 import org
.eclipse
.core
.commands
.ExecutionEvent
;
42 import org
.eclipse
.core
.commands
.ExecutionException
;
43 import org
.eclipse
.jface
.wizard
.Wizard
;
44 import org
.eclipse
.jface
.wizard
.WizardDialog
;
45 import org
.eclipse
.jface
.wizard
.WizardPage
;
46 import org
.eclipse
.rap
.fileupload
.FileDetails
;
47 import org
.eclipse
.rap
.fileupload
.FileUploadEvent
;
48 import org
.eclipse
.rap
.fileupload
.FileUploadHandler
;
49 import org
.eclipse
.rap
.fileupload
.FileUploadListener
;
50 import org
.eclipse
.rap
.fileupload
.FileUploadReceiver
;
51 import org
.eclipse
.rap
.rwt
.service
.ServerPushSession
;
52 import org
.eclipse
.rap
.rwt
.widgets
.FileUpload
;
53 import org
.eclipse
.swt
.SWT
;
54 import org
.eclipse
.swt
.events
.ModifyEvent
;
55 import org
.eclipse
.swt
.events
.ModifyListener
;
56 import org
.eclipse
.swt
.events
.SelectionAdapter
;
57 import org
.eclipse
.swt
.events
.SelectionEvent
;
58 import org
.eclipse
.swt
.layout
.GridData
;
59 import org
.eclipse
.swt
.layout
.GridLayout
;
60 import org
.eclipse
.swt
.widgets
.Combo
;
61 import org
.eclipse
.swt
.widgets
.Composite
;
62 import org
.eclipse
.swt
.widgets
.Control
;
63 import org
.eclipse
.swt
.widgets
.Label
;
64 import org
.eclipse
.swt
.widgets
.Shell
;
65 import org
.eclipse
.ui
.handlers
.HandlerUtil
;
70 /** Open a one page wizard to import an EXCEL 2003 legacy organisation file */
71 public class ImportEntities
extends AbstractHandler
implements PeopleNames
{
73 public final static String ID
= AsUiPlugin
.PLUGIN_ID
+ ".importEntities";
75 // public final static String PARAM_NODE_TYPE = "param.nodeType";
77 private static final Map
<String
, String
> KNOWN_TEMPLATES
;
79 Map
<String
, String
> tmpMap
= new HashMap
<String
, String
>();
80 tmpMap
.put("Organisations", PeopleTypes
.PEOPLE_ORG
);
81 KNOWN_TEMPLATES
= Collections
.unmodifiableMap(tmpMap
);
84 // TODO make this configurable
85 private final static String IMPORT_ENCODING
= "ISO-8859-1";
87 /* DEPENDENCY INJECTION */
88 private Repository repository
;
89 private ResourcesService resourcesService
;
90 private PeopleService peopleService
;
92 public Object
execute(final ExecutionEvent event
) throws ExecutionException
{
93 // String jcrId = event.getParameter(PARAM_NODE_TYPE);
95 Wizard wizard
= new ImportMappingFileWizard(HandlerUtil
.getActiveShell(event
),
96 "Upload legacy contact via Excel file import");
97 WizardDialog dialog
= new WizardDialog(HandlerUtil
.getActiveShell(event
), wizard
);
102 /** One page wizard to import a EXCEL 2003 Mapping files */
103 private class ImportMappingFileWizard
extends Wizard
{
105 // Various UI Objects
106 private UserInputPage userInputPage
;
107 private Combo resourceTypeCombo
;
110 private FileUpload fileUpload
;
111 private Label fileNameLabel
;
112 private ServerPushSession pushSession
;
115 public ImportMappingFileWizard(Shell parentShell
, String title
) {
116 setWindowTitle(title
);
120 public void addPages() {
122 userInputPage
= new UserInputPage("User input page");
123 addPage(userInputPage
);
124 } catch (Exception e
) {
125 throw new SuiteException("Cannot add page to wizard", e
);
129 /** Performs the real import. */
131 public boolean performFinish() {
132 // Session session = null;
133 String templateName
= resourceTypeCombo
.getItem(resourceTypeCombo
.getSelectionIndex());
134 // String type = KNOWN_TEMPLATES.get(templateName);
136 importDefaultOrgFile(file
);
142 public boolean performCancel() {
147 public boolean canFinish() {
148 if (resourceTypeCombo
.getSelectionIndex() < 0) {
149 userInputPage
.setErrorMessage("Please choose an entity type");
151 } else if (file
== null) {
152 userInputPage
.setErrorMessage("Please upload a file1");
155 userInputPage
.setErrorMessage(null);
160 private class UserInputPage
extends WizardPage
{
161 private static final long serialVersionUID
= 1L;
163 public UserInputPage(String pageName
) {
165 setTitle("Upload an Excel 2003 file (.xls)");
168 public void createControl(Composite parent
) {
169 parent
.setLayout(new GridLayout(1, false));
170 Composite composite
= new Composite(parent
, SWT
.NONE
);
171 composite
.setLayout(new GridLayout(2, false));
172 composite
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
175 resourceTypeCombo
= createLC(composite
, "Type");
176 resourceTypeCombo
.addModifyListener(new ModifyListener() {
177 private static final long serialVersionUID
= 1L;
180 public void modifyText(ModifyEvent event
) {
181 getWizard().getContainer().updateButtons();
184 resourceTypeCombo
.setItems(KNOWN_TEMPLATES
.keySet().toArray(new String
[0]));
187 Label lbl
= new Label(composite
, SWT
.NONE
);
188 lbl
.setText("Chosen file");
189 lbl
.setFont(EclipseUiUtils
.getBoldFont(composite
));
190 Composite uploadCmp
= new Composite(composite
, SWT
.NONE
);
191 uploadCmp
.setLayoutData(EclipseUiUtils
.fillWidth());
192 createFileUploadArea(uploadCmp
);
193 setControl(composite
);
197 private Control
createFileUploadArea(Composite parent
) {
198 GridLayout gl
= EclipseUiUtils
.noSpaceGridLayout(new GridLayout(2, false));
199 gl
.horizontalSpacing
= 5;
200 parent
.setLayout(gl
);
202 fileNameLabel
= new Label(parent
, SWT
.NONE
| SWT
.BEGINNING
);
203 fileNameLabel
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, true, false));
205 fileUpload
= new FileUpload(parent
, SWT
.NONE
);
206 fileUpload
.setText("Browse...");
207 fileUpload
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, false, false));
209 final String url
= startUploadReceiver();
210 pushSession
= new ServerPushSession();
212 fileUpload
.addSelectionListener(new SelectionAdapter() {
213 private static final long serialVersionUID
= 1L;
216 public void widgetSelected(SelectionEvent e
) {
217 String fileName
= fileUpload
.getFileName();
218 fileNameLabel
.setText(fileName
== null ?
"" : fileName
);
220 fileUpload
.submit(url
);
226 private String
startUploadReceiver() {
227 MyFileUploadReceiver receiver
= new MyFileUploadReceiver();
228 FileUploadHandler uploadHandler
= new FileUploadHandler(receiver
);
229 uploadHandler
.addUploadListener(new FileUploadListener() {
231 public void uploadProgress(FileUploadEvent event
) {
232 // handle upload progress
235 public void uploadFailed(FileUploadEvent event
) {
236 ImportMappingFileWizard
.this.userInputPage
237 .setErrorMessage("upload failed: " + event
.getException());
240 public void uploadFinished(FileUploadEvent event
) {
241 fileNameLabel
.getDisplay().asyncExec(new Runnable() {
243 ImportMappingFileWizard
.this.getContainer().updateButtons();
249 return uploadHandler
.getUploadUrl();
252 private class MyFileUploadReceiver
extends FileUploadReceiver
{
254 private static final String TEMP_FILE_PREFIX
= "fileupload_";
257 public void receive(InputStream dataStream
, FileDetails details
) throws IOException
{
258 File result
= File
.createTempFile(TEMP_FILE_PREFIX
, "");
259 FileOutputStream outputStream
= new FileOutputStream(result
);
261 copy(dataStream
, outputStream
);
264 outputStream
.close();
272 private void copy(InputStream inputStream
, OutputStream outputStream
) throws IOException
{
273 byte[] buffer
= new byte[8192];
274 boolean finished
= false;
276 int bytesRead
= inputStream
.read(buffer
);
277 if (bytesRead
!= -1) {
278 outputStream
.write(buffer
, 0, bytesRead
);
285 /** Creates label and Combo. */
286 protected Combo
createLC(Composite parent
, String label
) {
287 Label lbl
= new Label(parent
, SWT
.RIGHT
);
289 lbl
.setFont(EclipseUiUtils
.getBoldFont(parent
));
290 lbl
.setLayoutData(new GridData(SWT
.RIGHT
, SWT
.CENTER
, false, false));
291 Combo combo
= new Combo(parent
, SWT
.READ_ONLY
);
292 combo
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, true, false));
297 // Legacy Organisations
298 private Node
importDefaultOrgFile(File file
) {
299 InputStream in
= null;
301 in
= new FileInputStream(file
);
302 return importDefaultOrgFile(in
);
303 } catch (IOException e
) {
304 throw new SuiteException("Cannot import mapping file", e
);
306 IOUtils
.closeQuietly(in
);
310 private Node
createDraftNode(Node parent
, String mainMixin
) throws RepositoryException
{
311 String uuid
= UUID
.randomUUID().toString();
312 Node tmpNode
= parent
.addNode(uuid
);
313 tmpNode
.addMixin(mainMixin
);
314 tmpNode
.setProperty(ConnectNames
.CONNECT_UID
, uuid
);
318 private void importOrgEmployees(Node tmpParent
, Node targetParent
, Node newOrgNode
, String coworkersStr
)
319 throws RepositoryException
{
320 String
[] coworkers
= coworkersStr
.split("\\n");
321 loop
: for (String line
: coworkers
) {
322 if (EclipseUiUtils
.isEmpty(line
))
325 int index
= line
.indexOf(' ');
326 String firstName
= null;
327 String lastName
= null;
328 String position
= null;
332 firstName
= line
.substring(0, index
);
333 line
= line
.substring(index
);
335 index
= line
.indexOf('(');
339 lastName
= line
.substring(0, index
).trim();
340 position
= line
.substring(index
+ 1, line
.length() - 1);
343 Node tmpPerson
= createDraftNode(tmpParent
, PeopleTypes
.PEOPLE_PERSON
);
344 tmpPerson
.setProperty(PEOPLE_FIRST_NAME
, firstName
);
345 if (EclipseUiUtils
.notEmpty(lastName
))
346 tmpPerson
.setProperty(PEOPLE_LAST_NAME
, lastName
);
347 Node newPersonNode
= peopleService
.createEntity(targetParent
, PeopleTypes
.PEOPLE_PERSON
, tmpPerson
);
348 if (EclipseUiUtils
.notEmpty(position
))
349 PersonJcrUtils
.addJob(newPersonNode
, newOrgNode
, position
, true);
350 // Save the newly created entity without creating a base version
351 newOrgNode
= peopleService
.saveEntity(newOrgNode
, false);
356 private void importUrls(Node contactable
, String urlStr
) throws RepositoryException
{
357 String
[] urls
= urlStr
.split("\\n");
358 boolean hasPrimary
= false;
359 boolean hasPrimaryFacebook
= false;
361 loop
: for (String line
: urls
) {
362 if (EclipseUiUtils
.isEmpty(line
))
366 if (line
.startsWith("https://www.facebook.com")) {
367 PeopleJcrUtils
.createSocialMedia(peopleService
, resourcesService
, contactable
, line
,
368 !hasPrimaryFacebook
, null, ContactValueCatalogs
.CONTACT_CAT_FACEBOOK
, null);
369 hasPrimaryFacebook
= true;
371 PeopleJcrUtils
.createWebsite(peopleService
, resourcesService
, contactable
, line
, !hasPrimary
, null,
378 private void importMails(Node contactable
, String mailStr
) throws RepositoryException
{
379 String
[] urls
= mailStr
.split("\\n");
380 boolean hasPrimary
= false;
381 loop
: for (String line
: urls
) {
382 if (EclipseUiUtils
.isEmpty(line
))
385 PeopleJcrUtils
.createEmail(peopleService
, resourcesService
, contactable
, line
, !hasPrimary
, null, null,
391 // TODO make this configurable
392 int displayNameIndex
= 0;
393 int legalNameIndex
= 1;
394 int legalFormIndex
= 2;
397 int postalCodeIndex
= 5;
402 int telephoneNumberIndex
= 10;
404 int contactsIndex
= 12;
405 int descriptionIndex
= 13;
408 private Node
importDefaultOrgFile(InputStream in
) throws IOException
{
409 Session session
= null;
412 Workbook wb
= JxlUtils
.toWorkbook(in
, IMPORT_ENCODING
);
413 session
= repository
.login();
414 String basePath
= "/" + peopleService
.getBaseRelPath(PeopleTypes
.PEOPLE_ORG
);
415 Node targetParent
= session
.getNode(basePath
);
416 Sheet sheet
= wb
.getSheet(0);
418 Node tmpParent
= peopleService
.getDraftParent(session
);
420 int rowNb
= sheet
.getRows();
421 for (i
= 1; i
< rowNb
- 1; i
++) {
423 Node tmpOrg
= createDraftNode(tmpParent
, PeopleTypes
.PEOPLE_ORG
);
425 String dName
= JxlUtils
.getStringValue(sheet
, displayNameIndex
, i
);
427 tmpOrg
.setProperty(PeopleNames
.PEOPLE_DISPLAY_NAME
, dName
);
428 String lName
= getStringValue(sheet
, legalNameIndex
, i
);
430 tmpOrg
.setProperty(PeopleNames
.PEOPLE_LEGAL_NAME
, lName
);
431 String lForm
= getStringValue(sheet
, legalFormIndex
, i
);
433 tmpOrg
.setProperty(PeopleNames
.PEOPLE_LEGAL_FORM
, lForm
);
434 String urlStr
= getStringValue(sheet
, urlsIndex
, i
);
435 if (notEmpty(urlStr
))
436 importUrls(tmpOrg
, urlStr
);
437 String mailStr
= getStringValue(sheet
, mailIndex
, i
);
438 if (notEmpty(mailStr
))
439 importMails(tmpOrg
, mailStr
);
440 String streetStr
= getStringValue(sheet
, streetIndex
, i
);
441 String pcStr
= getStringValue(sheet
, postalCodeIndex
, i
);
442 String lStr
= getStringValue(sheet
, lIndex
, i
);
443 String stStr
= getStringValue(sheet
, stIndex
, i
);
444 String cStr
= getStringValue(sheet
, cIndex
, i
);
445 if (notEmpty(streetStr
) || notEmpty(pcStr
) || notEmpty(lStr
) || notEmpty(stStr
) || notEmpty(cStr
))
446 PeopleJcrUtils
.createAddress(peopleService
, resourcesService
, tmpOrg
, streetStr
, null, pcStr
, lStr
,
447 stStr
, cStr
, true, null, ContactValueCatalogs
.CONTACT_CAT_MAIN
, null);
448 String mobileStr
= getStringValue(sheet
, mobileIndex
, i
);
449 if (notEmpty(mobileStr
))
450 PeopleJcrUtils
.createPhone(peopleService
, resourcesService
, tmpOrg
, mobileStr
, true, null,
451 ContactValueCatalogs
.CONTACT_CAT_MOBILE
, null);
452 String phoneStr
= getStringValue(sheet
, telephoneNumberIndex
, i
);
453 if (notEmpty(phoneStr
))
454 PeopleJcrUtils
.createPhone(peopleService
, resourcesService
, tmpOrg
, phoneStr
, true, null,
455 ContactValueCatalogs
.CONTACT_CAT_DIRECT
, null);
456 String descStr
= getStringValue(sheet
, descriptionIndex
, i
);
457 if (notEmpty(descStr
))
458 tmpOrg
.setProperty(Property
.JCR_DESCRIPTION
, descStr
);
459 String tagsStr
= getStringValue(sheet
, tagsIndex
, i
);
460 if (notEmpty(tagsStr
))
461 tmpOrg
.setProperty(ResourcesNames
.CONNECT_TAGS
, ConnectJcrUtils
.parseAndClean(tagsStr
, ",", true));
463 Node newOrgNode
= peopleService
.createEntity(targetParent
, PeopleTypes
.PEOPLE_ORG
, tmpOrg
);
464 // Save the newly created entity without creating a base version
465 newOrgNode
= peopleService
.saveEntity(newOrgNode
, false);
467 String contactsStr
= getStringValue(sheet
, contactsIndex
, i
);
468 if (notEmpty(contactsStr
))
469 importOrgEmployees(tmpParent
, targetParent
, newOrgNode
, contactsStr
);
472 } catch (PeopleException
| RepositoryException e
) {
473 throw new SuiteException("Cannot import mapping file, error at line: " + (i
+ 1), e
);
475 JcrUtils
.logoutQuietly(session
);
481 /* DEPENDENCY INJECTION */
482 public void setRepository(Repository repository
) {
483 this.repository
= repository
;
486 public void setResourcesService(ResourcesService resourcesService
) {
487 this.resourcesService
= resourcesService
;
490 public void setPeopleService(PeopleService peopleService
) {
491 this.peopleService
= peopleService
;