View Javadoc
1   package org.argeo.connect.e4.parts;
2   
3   import java.text.DateFormat;
4   import java.text.SimpleDateFormat;
5   
6   import javax.annotation.PostConstruct;
7   import javax.annotation.PreDestroy;
8   import javax.inject.Inject;
9   import javax.jcr.Node;
10  import javax.jcr.Property;
11  import javax.jcr.Repository;
12  import javax.jcr.RepositoryException;
13  import javax.jcr.Session;
14  import javax.jcr.nodetype.NodeType;
15  import javax.jcr.security.AccessControlManager;
16  import javax.jcr.security.Privilege;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
21  import org.argeo.cms.ui.eclipse.forms.FormToolkit;
22  import org.argeo.cms.ui.eclipse.forms.IFormPart;
23  import org.argeo.connect.ConnectConstants;
24  import org.argeo.connect.ConnectException;
25  import org.argeo.connect.SystemAppService;
26  import org.argeo.connect.UserAdminService;
27  import org.argeo.connect.e4.ConnectE4Constants;
28  import org.argeo.connect.e4.ConnectE4Msg;
29  import org.argeo.connect.resources.ResourcesService;
30  import org.argeo.connect.ui.ConnectEditor;
31  import org.argeo.connect.ui.ConnectUiUtils;
32  import org.argeo.connect.ui.SystemWorkbenchService;
33  import org.argeo.connect.ui.parts.CompositeManagedForm;
34  import org.argeo.connect.util.ConnectJcrUtils;
35  import org.argeo.eclipse.ui.EclipseUiUtils;
36  import org.argeo.jcr.JcrUtils;
37  import org.eclipse.core.runtime.IProgressMonitor;
38  import org.eclipse.e4.core.di.annotations.Optional;
39  import org.eclipse.e4.ui.di.Focus;
40  import org.eclipse.e4.ui.di.Persist;
41  import org.eclipse.e4.ui.model.application.ui.MDirtyable;
42  import org.eclipse.e4.ui.model.application.ui.basic.MPart;
43  import org.eclipse.rap.rwt.RWT;
44  import org.eclipse.rap.rwt.client.service.BrowserNavigation;
45  import org.eclipse.swt.SWT;
46  import org.eclipse.swt.events.SelectionAdapter;
47  import org.eclipse.swt.events.SelectionEvent;
48  import org.eclipse.swt.layout.FormLayout;
49  import org.eclipse.swt.layout.GridData;
50  import org.eclipse.swt.layout.GridLayout;
51  import org.eclipse.swt.widgets.Button;
52  import org.eclipse.swt.widgets.Composite;
53  
54  /**
55   * Parent Abstract Form editor for all nodes that derive from people:base.
56   * Insure the presence of a corresponding people services and manage a life
57   * cycle of the JCR session that is bound to it. It provides no UI layout except
58   * from the header with some buttons.
59   */
60  public abstract class AbstractConnectEditor implements ConnectEditor {
61  	private final static Log log = LogFactory.getLog(AbstractConnectEditor.class);
62  
63  	// private BundleContext bc =
64  	// FrameworkUtil.getBundle(AbstractConnectEditor.class).getBundleContext();
65  
66  	// Services dependency injection
67  	@Inject
68  	private Repository repository;
69  	@Inject
70  	private UserAdminService userAdminService;
71  	@Inject
72  	private ResourcesService resourcesService;
73  	@Inject
74  	private SystemAppService systemAppService;
75  
76  	private Session session;
77  
78  	// UI dependency injection
79  	@Inject
80  	private SystemWorkbenchService systemWorkbenchService;
81  	@Inject
82  	private MPart mPart;
83  	@Inject
84  	private MDirtyable mDirtyable;
85  
86  	// private ResourcesService resourcesService;
87  	// private ActivitiesService activitiesService;
88  	// private PeopleService peopleService;
89  
90  	// New approach: we do not rely on the checkin status of the underlying node
91  	// which should always be in a checkout state.
92  	// We rather perform a checkPoint when save is explicitly called
93  	private Boolean isEditing = false;
94  
95  	/* CONSTANTS */
96  	// length for short strings (typically tab names)
97  	protected final static int SHORT_NAME_LENGHT = 10;
98  
99  	private final static DateFormat df = new SimpleDateFormat(ConnectConstants.DEFAULT_DATE_TIME_FORMAT);
100 
101 	// Context
102 	private Node node;
103 	private String partName;
104 
105 	// UI Context
106 	private ConnectManagedForm mForm;
107 	private FormToolkit toolkit;
108 	private Composite main;
109 
110 	// FIXME RAP specific
111 	private BrowserNavigation browserNavigation;
112 
113 	// LIFE CYCLE
114 	private void init(String entityId) {
115 		// setSite(site);
116 		// setInput(input);
117 		try {
118 			session = repository.login();
119 			// String entityId=null;
120 			// EntityEditorInput sei = (EntityEditorInput) getEditorInput();
121 			node = getSession().getNodeByIdentifier(entityId);
122 			// Set a default part name and tooltip
123 			updatePartName();
124 			updateToolTip();
125 		} catch (RepositoryException e) {
126 			throw new ConnectException("Unable to create new session" + " to use with current editor", e);
127 		}
128 	}
129 
130 	protected void init() {
131 
132 	}
133 
134 	@PostConstruct
135 	public void createPartControl(Composite parent) {
136 		String entityId = mPart.getPersistedState().get(ConnectE4Constants.ENTITY_ID);
137 		init(entityId);
138 		init();
139 
140 		// mPart.setLabel(getPartName());
141 
142 		// Initialize main UI objects
143 		toolkit = new FormToolkit(parent.getDisplay());
144 		// Form form = toolkit.createForm(parent);
145 		mForm = new ConnectManagedForm(parent, toolkit);
146 		mForm.setContainer(AbstractConnectEditor.this);
147 		// main = form.getBody();
148 		main = toolkit.createComposite(parent);
149 		createMainLayout(main);
150 		forceRefresh();
151 
152 		browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
153 	}
154 
155 	// protected String getPartName() {
156 	// Node node = getNode();
157 	// try {
158 	// if (node.isNodeType(NodeType.MIX_TITLE)) {
159 	// return node.getProperty(Property.JCR_TITLE).getString();
160 	// } else {
161 	// return node.getName();
162 	// }
163 	// } catch (RepositoryException e) {
164 	// throw new ConnectException("Cannot retrieve part name based on " + node, e);
165 	// }
166 	// }
167 
168 	protected void createMainLayout(Composite parent) {
169 		parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
170 
171 		// Internal main Layout
172 		// Header
173 		Composite header = toolkit.createComposite(parent, SWT.NO_FOCUS | SWT.NO_SCROLL | SWT.NO_TRIM);
174 		GridLayout gl = ConnectUiUtils.noSpaceGridLayout(2);
175 		gl.marginRight = 5; // otherwise buttons are too close from right border
176 		header.setLayout(gl);
177 		header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
178 
179 		// header content
180 		Composite left = toolkit.createComposite(header, SWT.NO_FOCUS | SWT.NO_SCROLL | SWT.NO_TRIM);
181 		left.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
182 		populateHeader(left);
183 
184 		// header buttons
185 		Composite right = toolkit.createComposite(header, SWT.NO_FOCUS | SWT.NO_SCROLL | SWT.NO_TRIM);
186 		GridData gd = new GridData(SWT.CENTER, SWT.TOP, false, false);
187 		gd.verticalIndent = 5;
188 		right.setLayoutData(gd);
189 		populateButtonsComposite(right);
190 
191 		// body
192 		Composite body = toolkit.createComposite(parent, SWT.NO_FOCUS);
193 		body.setLayoutData(EclipseUiUtils.fillAll());
194 		populateBody(body);
195 	}
196 
197 	/** Overwrite to provide a specific part Name */
198 	protected void updatePartName() {
199 		String name = ConnectJcrUtils.get(node, Property.JCR_TITLE);
200 		if (EclipseUiUtils.notEmpty(name)) {
201 			if (name.length() > SHORT_NAME_LENGHT)
202 				name = name.substring(0, SHORT_NAME_LENGHT - 1) + "...";
203 			setPartName(name);
204 		}
205 	}
206 
207 	protected void setPartName(String name) {
208 		this.partName = name;
209 		mPart.setLabel(name);
210 	}
211 
212 	/** Overwrite to provide a specific part tooltip */
213 	protected void updateToolTip() {
214 		String displayName = ConnectJcrUtils.get(node, Property.JCR_TITLE);
215 		if (EclipseUiUtils.isEmpty(displayName))
216 			displayName = "current item";
217 		// EntityEditorInput sei = (EntityEditorInput) getEditorInput();
218 		// sei.setTooltipText("Display and edit information for " + displayName);
219 	}
220 
221 	/** Overwrite following methods to create a nice editor... */
222 	protected abstract void populateBody(Composite parent);
223 
224 	/** Overwrite following methods to create a nice editor... */
225 	protected abstract void populateHeader(Composite parent);
226 
227 	protected void populateButtonsComposite(final Composite buttons) {
228 		buttons.setLayout(new FormLayout());
229 
230 		// READ ONLY PANEL
231 		final Composite roPanelCmp = toolkit.createComposite(buttons, SWT.NO_FOCUS);
232 		ConnectUiUtils.setSwitchingFormData(roPanelCmp);
233 		// roPanelCmp.setLayout(new RowLayout(SWT.VERTICAL));
234 		roPanelCmp.setLayout(new GridLayout());
235 
236 		// Do not show the edit button if the user does not have sufficient
237 		// rights
238 		if (canEdit()) {
239 			Button editBtn = toolkit.createButton(roPanelCmp, ConnectE4Msg.edit.lead(), SWT.PUSH);
240 			// editBtn.setLayoutData(new RowData(60, 20));
241 			editBtn.setFont(EclipseUiUtils.getBoldFont(roPanelCmp));
242 			editBtn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
243 			editBtn.addSelectionListener(new SelectionAdapter() {
244 				private static final long serialVersionUID = 1L;
245 
246 				@Override
247 				public void widgetSelected(SelectionEvent e) {
248 					// Superstition? we can only be here when we can edit.
249 					if (canEdit()) {
250 						// Map<String, String> params = new HashMap<String, String>();
251 						// params.put(ChangeEditingState.PARAM_NEW_STATE, ChangeEditingState.EDITING);
252 						// params.put(ChangeEditingState.PARAM_PRIOR_ACTION,
253 						// ChangeEditingState.PRIOR_ACTION_CHECKOUT);
254 						// CommandUtils.callCommand(ChangeEditingState.ID, params);
255 						changeEditingState(PRIOR_ACTION_CHECKOUT, EDITING);
256 					}
257 				}
258 			});
259 		}
260 		// Add a refresh button to enable forcing refresh when having some UI
261 		// glitches.
262 		if (showRefreshButton()) {
263 			Button refreshBtn = toolkit.createButton(roPanelCmp, ConnectE4Msg.refresh.lead(), SWT.PUSH);
264 			// refreshBtn.setLayoutData(new RowData(60, 20));
265 			refreshBtn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
266 			refreshBtn.addSelectionListener(new SelectionAdapter() {
267 				private static final long serialVersionUID = 1L;
268 
269 				@Override
270 				public void widgetSelected(SelectionEvent e) {
271 					forceRefresh();
272 				}
273 			});
274 		}
275 		// EDIT PANEL
276 		final Composite editPanelCmp = toolkit.createComposite(buttons, SWT.NONE);
277 		ConnectUiUtils.setSwitchingFormData(editPanelCmp);
278 		// editPanelCmp.setLayout(new RowLayout(SWT.VERTICAL));
279 		editPanelCmp.setLayout(new GridLayout());
280 
281 		Button saveBtn = toolkit.createButton(editPanelCmp, ConnectE4Msg.save.lead(), SWT.PUSH);
282 		// saveBtn.setLayoutData(new RowData(60, 20));
283 		saveBtn.setFont(EclipseUiUtils.getBoldFont(editPanelCmp));
284 		saveBtn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
285 		saveBtn.addSelectionListener(new SelectionAdapter() {
286 			private static final long serialVersionUID = 1L;
287 
288 			@Override
289 			public void widgetSelected(SelectionEvent e) {
290 				try {
291 					if (isEditing())
292 						if (node.getSession().hasPendingChanges()) {
293 							// CommandUtils.callCommand(IWorkbenchCommandConstants.FILE_SAVE);
294 							// TODO use a command in order to centralise it
295 							doSave(null);
296 						} else {
297 							// Nothing has changed we in fact call cancel
298 							// Map<String, String> params = new HashMap<String, String>();
299 							// params.put(ChangeEditingState.PARAM_NEW_STATE,
300 							// ChangeEditingState.NOT_EDITING);
301 							// params.put(ChangeEditingState.PARAM_PRIOR_ACTION,
302 							// ChangeEditingState.PRIOR_ACTION_CANCEL);
303 							// CommandUtils.callCommand(ChangeEditingState.ID, params);
304 							changeEditingState(PRIOR_ACTION_CANCEL, NOT_EDITING);
305 						}
306 				} catch (RepositoryException re) {
307 					throw new ConnectException("Unable to save pending changes on " + node, re);
308 				}
309 			}
310 		});
311 
312 		Button cancelBtn = toolkit.createButton(editPanelCmp, ConnectE4Msg.cancel.lead(), SWT.PUSH);
313 		// cancelBtn.setLayoutData(new RowData(60, 20));
314 		cancelBtn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
315 		cancelBtn.addSelectionListener(new SelectionAdapter() {
316 			private static final long serialVersionUID = 1L;
317 
318 			@Override
319 			public void widgetSelected(SelectionEvent e) {
320 				if (isEditing()) {
321 					// Map<String, String> params = new HashMap<String, String>();
322 					// params.put(ChangeEditingState.PARAM_NEW_STATE,
323 					// ChangeEditingState.NOT_EDITING);
324 					// params.put(ChangeEditingState.PARAM_PRIOR_ACTION,
325 					// ChangeEditingState.PRIOR_ACTION_CANCEL);
326 					// CommandUtils.callCommand(ChangeEditingState.ID, params);
327 					changeEditingState(PRIOR_ACTION_CANCEL, NOT_EDITING);
328 				}
329 			}
330 		});
331 
332 		if (showDeleteButton()) {
333 			Button deleteBtn = toolkit.createButton(editPanelCmp, ConnectE4Msg.delete.lead(), SWT.PUSH);
334 			// deleteBtn.setLayoutData(new RowData(60, 20));
335 			deleteBtn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
336 			deleteBtn.addSelectionListener(new SelectionAdapter() {
337 				private static final long serialVersionUID = 1L;
338 
339 				@Override
340 				public void widgetSelected(SelectionEvent e) {
341 					// Map<String, String> params = new HashMap<String, String>();
342 					// params.put(DeleteEntity.PARAM_TOREMOVE_JCR_ID,
343 					// ConnectJcrUtils.getIdentifier(node));
344 					// CommandUtils.callCommand(DeleteEntity.ID, params);
345 					getSystemWorkbenchService().callCommand(getSystemWorkbenchService().getDeleteEntityCmdId(), null);
346 				}
347 			});
348 		}
349 
350 		// add other edition buttons
351 		addEditButtons(editPanelCmp);
352 
353 		editPanelCmp.layout();
354 		roPanelCmp.layout();
355 
356 		AbstractFormPart editPart = new AbstractFormPart() {
357 			// Update values on refresh
358 			public void refresh() {
359 				if (isEditing())
360 					editPanelCmp.moveAbove(roPanelCmp);
361 				else
362 					editPanelCmp.moveBelow(roPanelCmp);
363 				roPanelCmp.getParent().layout();
364 			}
365 		};
366 		editPart.initialize(mForm);
367 		mForm.addPart(editPart);
368 	}
369 
370 	/** Overwrite this call back method to add buttons when in edit Mode */
371 	protected void addEditButtons(Composite parent) {
372 	}
373 
374 	final static String EDITING = "editing";
375 	final static String NOT_EDITING = "notEditing";
376 	final static String PRIOR_ACTION_SAVE = "save";
377 	final static String PRIOR_ACTION_CHECKOUT = "checkout";
378 	final static String PRIOR_ACTION_CANCEL = "cancel";
379 
380 	protected void changeEditingState(String priorAction, String newState) {
381 		// prior action
382 		Node node = getNode();
383 		if (PRIOR_ACTION_SAVE.equals(priorAction))
384 			ConnectJcrUtils.saveAndPublish(node, true);
385 		else if (PRIOR_ACTION_CANCEL.equals(priorAction))
386 			JcrUtils.discardUnderlyingSessionQuietly(node);
387 		else if (PRIOR_ACTION_CHECKOUT.equals(priorAction)) {
388 			if (!ConnectJcrUtils.checkCOStatusBeforeUpdate(node))
389 				log.warn("Referencing node " + node + " was checked in when we wanted to update");
390 		}
391 		// new State
392 		if (EDITING.equals(newState))
393 			startEditing();
394 		else if (NOT_EDITING.equals(newState))
395 			stopEditing();
396 
397 	}
398 
399 	/* PUBLIC ABILITIES AND EXPOSED OBJECTS */
400 	/** Enables definition of a new "main" node for this editor */
401 	public void setNode(Node node) {
402 		this.node = node;
403 	}
404 
405 	public FormToolkit getFormToolkit() {
406 		return toolkit;
407 	}
408 
409 	public ConnectManagedForm getManagedForm() {
410 		return mForm;
411 	}
412 
413 	/** Overwrite to hide the delete button */
414 	protected boolean showDeleteButton() {
415 		return false;
416 	}
417 
418 	protected boolean showRefreshButton() {
419 		return false;
420 	}
421 
422 	@Persist
423 	public void doSave(@Optional IProgressMonitor monitor) {
424 		if (canSave())
425 			mForm.commit(true);
426 		stopEditing();
427 	}
428 
429 	/**
430 	 * Overwrite to provide specific behaviour on save.
431 	 * 
432 	 * Introduced as a consequence of the use of a specific ManagedForm
433 	 */
434 	protected void commitInternalLinkedForm(boolean onSave) {
435 		// Enable specific pre-save processing in each form part before the
436 		// session.save();
437 		for (IFormPart part : mForm.getParts()) {
438 			if (part.isDirty())
439 				part.commit(onSave);
440 		}
441 		if (onSave) {
442 			systemAppService.saveEntity(node, true);
443 			updatePartName();
444 		}
445 	}
446 
447 	public void startEditing() {
448 		if (!isEditing) {
449 			isEditing = true;
450 			markAllStale();
451 			// Must force the refresh: the stale mechanism is broken due to the
452 			// use of our twicked form.
453 			forceRefresh();
454 			notifyEditionStateChange();
455 			main.layout(true, true);
456 		}
457 	}
458 
459 	public void stopEditing() {
460 		if (isEditing) {
461 			isEditing = false;
462 			markAllStale();
463 			forceRefresh();
464 			notifyEditionStateChange();
465 			main.layout(true, true);
466 		}
467 	}
468 
469 	protected void markAllStale() {
470 		if (mForm != null)
471 			for (IFormPart part : mForm.getParts())
472 				if (part instanceof AbstractFormPart)
473 					((AbstractFormPart) part).markStale();
474 	}
475 
476 	/**
477 	 * Notify the workbench that editable status as changed in order to update
478 	 * external extension (typically the toolbar buttons)
479 	 */
480 	protected void notifyEditionStateChange() {
481 		mDirtyable.setDirty(isEditing);
482 		// ISourceProviderService sourceProviderService = (ISourceProviderService)
483 		// this.getSite().getWorkbenchWindow()
484 		// .getService(ISourceProviderService.class);
485 		// EditionSourceProvider csp = (EditionSourceProvider) sourceProviderService
486 		// .getSourceProvider(EditionSourceProvider.EDITING_STATE);
487 		// csp.setCurrentItemEditingState(canEdit(), isEditing());
488 		// firePropertyChange(PROP_DIRTY);
489 	}
490 
491 	public Boolean isEditing() {
492 		return isEditing;
493 	}
494 
495 	public Boolean canEdit() {
496 		try {
497 			AccessControlManager acm = session.getAccessControlManager();
498 			Privilege[] privs = { acm.privilegeFromName(Privilege.JCR_WRITE) };
499 			return acm.hasPrivileges(node.getPath(), privs);
500 		} catch (RepositoryException e) {
501 			throw new ConnectException("Unable to check privilege on " + node, e);
502 		}
503 	}
504 
505 	/** Forces refresh of all form parts of the current editor */
506 	public void forceRefresh(Object object) {
507 		if (log.isTraceEnabled())
508 			log.trace("Starting Editor refresh");
509 		long start, lap, lapEnd, end;
510 		start = System.currentTimeMillis();
511 		for (IFormPart part : mForm.getParts()) {
512 			lap = System.currentTimeMillis();
513 			part.refresh();
514 			lapEnd = System.currentTimeMillis();
515 			if (log.isTraceEnabled())
516 				log.trace("FormPart " + part.getClass().getName() + " refreshed in " + (lapEnd - lap) + " ms");
517 		}
518 		lap = System.currentTimeMillis();
519 		mForm.reflow(true);
520 		end = System.currentTimeMillis();
521 		if (log.isTraceEnabled()) {
522 			log.trace("Reflow done in " + (end - lap) + " ms");
523 			log.trace("Full refresh of " + this.getClass().getName() + " in " + (end - start) + " ms");
524 		}
525 	}
526 
527 	public void forceRefresh() {
528 		forceRefresh(null);
529 	}
530 
531 	/**
532 	 * Overwrite to provide entity specific before save validation
533 	 */
534 	protected boolean canSave() {
535 		return true;
536 	}
537 
538 	public String getStatusLineMessage() {
539 		return getLastModifiedMessage();
540 	}
541 
542 	public String getLastModifiedMessage() {
543 		Node currNode = getNode();
544 		StringBuilder builder = new StringBuilder();
545 		try {
546 			if (currNode.isNodeType(NodeType.MIX_TITLE)) {
547 				builder.append(ConnectJcrUtils.get(currNode, Property.JCR_TITLE)).append(" - ");
548 			}
549 			if (currNode.isNodeType(NodeType.MIX_LAST_MODIFIED)) {
550 				builder.append("Last updated on ");
551 				builder.append(df.format(currNode.getProperty(Property.JCR_LAST_MODIFIED).getDate().getTime()));
552 				builder.append(", by ");
553 				String lstModByDn = currNode.getProperty(Property.JCR_LAST_MODIFIED_BY).getString();
554 				builder.append(userAdminService.getUserDisplayName(lstModByDn));
555 				builder.append(". ");
556 			}
557 			return builder.toString();
558 		} catch (RepositoryException re) {
559 			throw new ConnectException("Unable to create last " + "modified message for " + currNode, re);
560 		}
561 	}
562 
563 	public boolean isDirty() {
564 		try {
565 			boolean isDirty = session.hasPendingChanges();
566 			return isDirty;
567 		} catch (Exception e) {
568 			throw new ConnectException("Error getting session status on " + node, e);
569 		}
570 	}
571 
572 	@PreDestroy
573 	public void dispose() {
574 		try {
575 			if (node != null)
576 				JcrUtils.discardUnderlyingSessionQuietly(node);
577 		} finally {
578 			JcrUtils.logoutQuietly(session);
579 		}
580 		browserNavigation.pushState("~", null);
581 		// super.dispose();
582 	}
583 
584 	@Focus
585 	public void setFocus() {
586 		try {
587 			browserNavigation.pushState(node.getPath(), partName);
588 		} catch (RepositoryException e) {
589 			log.error("Cannot set client state", e);
590 		}
591 	}
592 
593 	public void doSaveAs() {
594 	}
595 
596 	public boolean isSaveAsAllowed() {
597 		return false;
598 	}
599 
600 	public class ConnectManagedForm extends CompositeManagedForm {
601 		public ConnectManagedForm(Composite parent, FormToolkit toolkit) {
602 			super(parent, toolkit);
603 		}
604 
605 		/** <code>super.dirtyStateChanged()</code> does nothing */
606 		public void dirtyStateChanged() {
607 			// AbstractConnectEditor.this.firePropertyChange(PROP_DIRTY);
608 		}
609 
610 		/**
611 		 * Enable clean management of the "dirty" status display in this part table
612 		 */
613 		public void commit(boolean onSave) {
614 			commitInternalLinkedForm(onSave);
615 		}
616 
617 		public AbstractConnectEditor getEditor() {
618 			return (AbstractConnectEditor) getContainer();
619 		}
620 	}
621 
622 	/* EXPOSES TO CHILDREN CLASSES */
623 	protected Session getSession() {
624 		return session;
625 	}
626 
627 	protected Repository getRepository() {
628 		return repository;
629 	}
630 
631 	/** Returns the entity Node that is bound to this editor */
632 	public Node getNode() {
633 		return node;
634 	}
635 
636 	protected UserAdminService getUserAdminService() {
637 		return userAdminService;
638 	}
639 
640 	protected ResourcesService getResourcesService() {
641 		return resourcesService;
642 	}
643 
644 	protected SystemAppService getSystemAppService() {
645 		return systemAppService;
646 	}
647 
648 	protected SystemWorkbenchService getSystemWorkbenchService() {
649 		return systemWorkbenchService;
650 	}
651 
652 	/* DEPENDENCY INJECTION */
653 	public void setRepository(Repository repository) {
654 		log.trace("setRepository is deprecated and ignored");
655 		// this.repository = repository;
656 	}
657 
658 	public void setUserAdminService(UserAdminService userAdminService) {
659 		log.trace("setUserAdminService is deprecated and ignored");
660 		// this.userAdminService = userAdminService;
661 	}
662 
663 	public void setResourcesService(ResourcesService resourcesService) {
664 		log.trace("setResourcesService is deprecated and ignored");
665 		// this.resourcesService = resourcesService;
666 	}
667 
668 	public void setSystemAppService(SystemAppService systemAppService) {
669 		log.trace("setSystemAppService is deprecated and ignored");
670 		// this.systemAppService = systemAppService;
671 	}
672 
673 	public void setSystemWorkbenchService(SystemWorkbenchService systemWorkbenchService) {
674 		log.trace("setSystemWorkbenchService is deprecated and ignored");
675 		// this.systemWorkbenchService = systemWorkbenchService;
676 	}
677 }