@Override public void copyDocuments(String fromWikiId, String toWikiId, boolean withHistory) throws WikiManagerException { XWikiContext context = xcontextProvider.get(); XWiki xwiki = context.getWiki(); try { Query query = queryManager.createQuery("select distinct doc.fullName from Document as doc", Query.XWQL); query.setWiki(fromWikiId); List<String> documentFullnames = query.execute(); observationManager.notify(new PushLevelProgressEvent(documentFullnames.size()), this); WikiReference fromWikiReference = new WikiReference(fromWikiId); for (String documentFullName : documentFullnames) { DocumentReference origDocReference = documentReferenceResolver.resolve(documentFullName, fromWikiReference); DocumentReference newDocReference = new DocumentReference( toWikiId, origDocReference.getLastSpaceReference().getName(), origDocReference.getName()); xwiki.copyDocument(origDocReference, newDocReference, null, !withHistory, true, context); observationManager.notify(new StepProgressEvent(), this); } observationManager.notify(new PopLevelProgressEvent(), this); } catch (QueryException e) { throw new WikiManagerException("Unable to get the source wiki documents.", e); } catch (XWikiException e) { throw new WikiManagerException("Failed to copy document.", e); } }
public void init(IndexUpdater indexUpdater, IndexRebuilder indexRebuilder, XWikiContext context) { super.init(context); try { @SuppressWarnings("unchecked") Class<? extends Analyzer> clazz = (Class<? extends Analyzer>) Class.forName(context.getWiki().Param(PROP_ANALYZER, DEFAULT_ANALYZER)); this.analyzer = clazz.getConstructor(Version.class).newInstance(Version.LUCENE_36); } catch (Exception e) { LOGGER.error("Error instantiating analyzer: {}", e.getMessage()); LOGGER.warn("Using default analyzer class: " + DEFAULT_ANALYZER); try { @SuppressWarnings("unchecked") Class<? extends Analyzer> clazz = (Class<? extends Analyzer>) Class.forName(DEFAULT_ANALYZER); this.analyzer = clazz.getConstructor(Version.class).newInstance(Version.LUCENE_36); } catch (Exception e1) { throw new RuntimeException( "Instantiation of default analyzer " + DEFAULT_ANALYZER + " failed", e1); } } Map<String, Analyzer> specialAnalyzers = new HashMap<String, Analyzer>(); Analyzer preserve = new KeywordAnalyzer(); specialAnalyzers.put(IndexFields.DOCUMENT_EXACTSPACE, preserve); specialAnalyzers.put(IndexFields.DOCUMENT_WIKI, preserve); specialAnalyzers.put(IndexFields.DOCUMENT_TYPE, preserve); specialAnalyzers.put(IndexFields.DOCUMENT_LANGUAGE, preserve); this.analyzer = new PerFieldAnalyzerWrapper(this.analyzer, specialAnalyzers); LOGGER.debug("Assigning index updater: {}", indexUpdater); if (this.indexDirs == null) { this.indexDirs = context.getWiki().Param(PROP_INDEX_DIR); if (StringUtils.isEmpty(this.indexDirs)) { File workDir = getLuceneWorkDirectory(); this.indexDirs = workDir.getAbsolutePath(); } } this.indexUpdater = indexUpdater; this.indexUpdater.setAnalyzer(this.analyzer); this.indexUpdaterThread = new Thread(indexUpdater, "Lucene Index Updater"); this.indexUpdaterThread.start(); this.indexRebuilder = indexRebuilder; openIndexReaders(context); // Register the Index Updater as an Event Listener so that modified documents/attachments are // added to the // Lucene indexing queue. // If the Index Updater is already registered don't do anything. ObservationManager observationManager = Utils.getComponent(ObservationManager.class); if (observationManager.getListener(indexUpdater.getName()) == null) { observationManager.addListener(indexUpdater); } LOGGER.debug("Lucene plugin initialized."); }
/** * {@inheritDoc} <br> * Implementation which gets all the annotation class objects in the document pointed by the * target, and matches their ids against the ids in the passed collection of annotations. If they * match, they are updated with the new data in the annotations in annotation. * * @see org.xwiki.annotation.io.IOService#updateAnnotations(String, java.util.Collection) */ @Override public void updateAnnotations(String target, Collection<Annotation> annotations) throws IOServiceException { try { EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // get the document name from the parsed reference String docName = target; if (targetReference.getType() == EntityType.DOCUMENT || targetReference.getType() == EntityType.OBJECT_PROPERTY) { docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT)); } // get the document pointed to by the target XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext); List<String> updateNotifs = new ArrayList<String>(); boolean updated = false; for (Annotation annotation : annotations) { // parse annotation id as string. If cannot parse, then ignore annotation, is not valid int annId = 0; try { annId = Integer.parseInt(annotation.getId()); } catch (NumberFormatException e) { continue; } BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), annId); if (object == null) { continue; } updated = updateObject(object, annotation, deprecatedContext) || updated; updateNotifs.add(annotation.getId()); } if (updated) { // set the author of the document to the current user document.setAuthor(deprecatedContext.getUser()); deprecatedContext .getWiki() .saveDocument(document, "Updated annotations", deprecatedContext); // send annotation update notifications for all annotations set to notify for ObservationManager observationManager = componentManager.lookup(ObservationManager.class); for (String updateNotif : updateNotifs) { observationManager.notify( new AnnotationUpdatedEvent(docName, updateNotif), document, deprecatedContext); } } } catch (XWikiException e) { throw new IOServiceException("An exception has occurred while updating the annotation", e); } catch (ComponentLookupException exc) { this.logger.warn( "Could not get the observation manager to send notifications about the annotation update"); } }
/** * {@inheritDoc} <br> * This implementation deletes the annotation object with the object number indicated by {@code * annotationID} from the document indicated by {@code target}, if its stored target matches the * passed target. * * @see org.xwiki.annotation.io.IOService#removeAnnotation(String, String) */ @Override public void removeAnnotation(String target, String annotationID) throws IOServiceException { try { if (annotationID == null || target == null) { return; } EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // get the target identifier and the document name from the parsed reference String localTargetId = target; String docName = target; if (targetReference.getType() == EntityType.DOCUMENT || targetReference.getType() == EntityType.OBJECT_PROPERTY) { localTargetId = localSerializer.serialize(targetReference); docName = serializer.serialize(targetReference.extractReference(EntityType.DOCUMENT)); } // get the document XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(docName, deprecatedContext); if (document.isNew()) { // if the document doesn't exist already skip it return; } // and the document object on it BaseObject annotationObject = document.getXObject( configuration.getAnnotationClassReference(), Integer.valueOf(annotationID.toString())); // if object exists and its target matches the requested target, delete it if (annotationObject != null && localTargetId.equals(annotationObject.getStringValue(Annotation.TARGET_FIELD))) { document.removeObject(annotationObject); document.setAuthor(deprecatedContext.getUser()); deprecatedContext .getWiki() .saveDocument(document, "Deleted annotation " + annotationID, deprecatedContext); // notify listeners that an annotation was deleted ObservationManager observationManager = componentManager.lookup(ObservationManager.class); observationManager.notify( new AnnotationDeletedEvent(docName, annotationID), document, deprecatedContext); } } catch (NumberFormatException e) { throw new IOServiceException("An exception has occurred while parsing the annotation id", e); } catch (XWikiException e) { throw new IOServiceException("An exception has occurred while removing the annotation", e); } catch (ComponentLookupException exc) { this.logger.warn( "Could not get the observation manager to send notifications about the annotation delete"); } }
@Test public void testOnEvent_update_ed() { Event event = new DocumentUpdatedEvent(); expect(remoteObsManContextMock.isRemoteState()).andReturn(false).once(); expect(docMock.getXObject(eq(classRef))).andReturn(getBaseObject1()).once(); expect(origDocMock.getXObject(eq(classRef))).andReturn(getBaseObject2()).once(); obsManagerMock.notify(same(updatedEventMock), same(docMock), same(context)); expectLastCall().once(); replayDefault(); listener.onEvent(event, docMock, context); verifyDefault(); }
public ActionForward execute(XWikiContext context) throws Exception { MonitorPlugin monitor = null; FileUploadPlugin fileupload = null; String docName = ""; try { String action = context.getAction(); // Initialize context.getWiki() with the main wiki XWiki xwiki; // Verify that the requested wiki exists try { xwiki = XWiki.getXWiki(this.waitForXWikiInitialization, context); // If XWiki is still initializing display initialization template if (xwiki == null) { // Display initialization template renderInit(context); // Initialization template has been displayed, stop here. return null; } } catch (XWikiException e) { // If the wiki asked by the user doesn't exist, then we first attempt to use any existing // global // redirects. If there are none, then we display the specific error template. if (e.getCode() == XWikiException.ERROR_XWIKI_DOES_NOT_EXIST) { xwiki = XWiki.getMainXWiki(context); // Initialize the url factory XWikiURLFactory urlf = xwiki.getURLFactoryService().createURLFactory(context.getMode(), context); context.setURLFactory(urlf); // Initialize the velocity context and its bindings so that it may be used in the velocity // templates // that we // are parsing below. VelocityManager velocityManager = Utils.getComponent(VelocityManager.class); VelocityContext vcontext = velocityManager.getVelocityContext(); if (!sendGlobalRedirect(context.getResponse(), context.getURL().toString(), context)) { // Starting XWiki 5.0M2, 'xwiki.virtual.redirect' was removed. Warn users still using // it. if (!StringUtils.isEmpty(context.getWiki().Param("xwiki.virtual.redirect"))) { LOGGER.warn( String.format( "%s %s", "'xwiki.virtual.redirect' is no longer supported.", "Please update your configuration and/or see XWIKI-8914 for more details.")); } // Display the error template only for actions that are not ignored if (!ACTIONS_IGNORED_WHEN_WIKI_DOES_NOT_EXIST.contains(action)) { // Add localization resources to the context xwiki.prepareResources(context); // Set the main home page in the main space of the main wiki as the current requested // entity // since we cannot set the non existing one as it would generate errors obviously... EntityReferenceValueProvider valueProvider = Utils.getComponent(EntityReferenceValueProvider.class); xwiki.setPhonyDocument( new DocumentReference( valueProvider.getDefaultValue(EntityType.WIKI), valueProvider.getDefaultValue(EntityType.SPACE), valueProvider.getDefaultValue(EntityType.DOCUMENT)), context, vcontext); // Parse the error template Utils.parseTemplate( context.getWiki().Param("xwiki.wiki_exception", "wikidoesnotexist"), context); // Error template was displayed, stop here. return null; } // At this point, we allow regular execution of the ignored action because even if the // wiki // does not exist, we still need to allow UI resources to be retrieved (from the // filesystem // and the main wiki) or our error template will not be rendered properly. // Proceed with serving the main wiki } else { // Global redirect was executed, stop here. return null; } } else { LOGGER.error("Uncaught exception during XWiki initialisation:", e); throw e; } } // Send global redirection (if any) if (sendGlobalRedirect(context.getResponse(), context.getURL().toString(), context)) { return null; } XWikiURLFactory urlf = xwiki.getURLFactoryService().createURLFactory(context.getMode(), context); context.setURLFactory(urlf); String sajax = context.getRequest().get("ajax"); boolean ajax = false; if (sajax != null && !sajax.trim().equals("") && !sajax.equals("0")) { ajax = true; } context.put("ajax", ajax); // Any error before this will be treated using a redirection to an error page if (monitor != null) { monitor.startTimer("request"); } VelocityManager velocityManager = Utils.getComponent(VelocityManager.class); VelocityContext vcontext = velocityManager.getVelocityContext(); boolean eventSent = false; try { // Prepare documents and put them in the context if (!xwiki.prepareDocuments(context.getRequest(), context, vcontext)) { return null; } // Start monitoring timer monitor = (MonitorPlugin) xwiki.getPlugin("monitor", context); if (monitor != null) { monitor.startRequest("", context.getAction(), context.getURL()); monitor.startTimer("multipart"); } // Parses multipart so that params in multipart are available for all actions fileupload = Utils.handleMultipart(context.getRequest().getHttpServletRequest(), context); if (monitor != null) { monitor.endTimer("multipart"); } if (monitor != null) { monitor.setWikiPage(context.getDoc().getFullName()); } // Let's handle the notification and make sure it never fails if (monitor != null) { monitor.startTimer("prenotify"); } // For the moment we're sending the XWiki context as the data, but this will be // changed in the future, when the whole platform will be written using components // and there won't be a need for the context. try { ObservationManager om = Utils.getComponent(ObservationManager.class); ActionExecutingEvent event = new ActionExecutingEvent(context.getAction()); om.notify(event, context.getDoc(), context); eventSent = true; if (event.isCanceled()) { // Action has been canceled // TODO: do something special ? return null; } } catch (Throwable ex) { LOGGER.error( "Cannot send action notifications for document [" + context.getDoc() + " using action [" + context.getAction() + "]", ex); } if (monitor != null) { monitor.endTimer("prenotify"); } // Call the Actions // Call the new Entity Resource Reference Handler. ResourceReferenceHandler entityResourceReferenceHandler = Utils.getComponent( new DefaultParameterizedType( null, ResourceReferenceHandler.class, ResourceType.class), "bin"); ResourceReference resourceReference = Utils.getComponent(ResourceReferenceManager.class).getResourceReference(); try { entityResourceReferenceHandler.handle( resourceReference, new DefaultResourceReferenceHandlerChain( Collections.<ResourceReferenceHandler>emptyList())); // Don't let the old actions kick in! return null; } catch (NotFoundResourceHandlerException e) { // No Entity Resource Action has been found. Don't do anything and let it go through // so that the old Action system kicks in... } catch (Throwable e) { // Some real failure, log it since it's a problem but still allow the old Action system a // chance // to do something... LOGGER.error("Failed to handle Action for Resource [{}]", resourceReference, e); } // Then call the old Actions for backward compatibility (and because a lot of them have not // been // migrated to new Actions yet). String renderResult = null; XWikiDocument doc = context.getDoc(); docName = doc.getFullName(); if (action(context)) { renderResult = render(context); } if (renderResult != null) { if (doc.isNew() && "view".equals(context.getAction()) && !"recyclebin".equals(context.getRequest().get("viewer"))) { String page = Utils.getPage(context.getRequest(), "docdoesnotexist"); Utils.parseTemplate(page, context); } else { String page = Utils.getPage(context.getRequest(), renderResult); Utils.parseTemplate(page, !page.equals("direct"), context); } } return null; } catch (Throwable e) { if (e instanceof IOException) { e = new XWikiException( XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, "Exception while sending response", e); } if (!(e instanceof XWikiException)) { e = new XWikiException( XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_UNKNOWN, "Uncaught exception", e); } try { XWikiException xex = (XWikiException) e; if (xex.getCode() == XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION) { // Connection aborted from the client side, there's not much we can do on the server // side. We // simply ignore it. LOGGER.debug("Connection aborted", e); // We don't write any other message to the response, as the connection is broken, // anyway. return null; } else if (xex.getCode() == XWikiException.ERROR_XWIKI_ACCESS_DENIED) { Utils.parseTemplate( context.getWiki().Param("xwiki.access_exception", "accessdenied"), context); return null; } else if (xex.getCode() == XWikiException.ERROR_XWIKI_USER_INACTIVE) { Utils.parseTemplate( context.getWiki().Param("xwiki.user_exception", "userinactive"), context); return null; } else if (xex.getCode() == XWikiException.ERROR_XWIKI_APP_ATTACHMENT_NOT_FOUND) { context.put("message", "attachmentdoesnotexist"); Utils.parseTemplate( context.getWiki().Param("xwiki.attachment_exception", "attachmentdoesnotexist"), context); return null; } else if (xex.getCode() == XWikiException.ERROR_XWIKI_APP_URL_EXCEPTION) { vcontext.put("message", context.getMessageTool().get("platform.core.invalidUrl")); xwiki.setPhonyDocument( xwiki.getDefaultSpace(context) + "." + xwiki.getDefaultPage(context), context, vcontext); context.getResponse().setStatus(HttpServletResponse.SC_BAD_REQUEST); Utils.parseTemplate( context.getWiki().Param("xwiki.invalid_url_exception", "error"), context); return null; } vcontext.put("exp", e); if (LOGGER.isWarnEnabled()) { // Don't log "Broken Pipe" exceptions since they're not real errors and we don't want to // pollute // the logs with unnecessary stack traces. It just means the client side has cancelled // the // connection. if (ExceptionUtils.getRootCauseMessage(e).equals("IOException: Broken pipe")) { return null; } LOGGER.warn("Uncaught exception: " + e.getMessage(), e); } // If the request is an AJAX request, we don't return a whole HTML page, but just the // exception // inline. String exceptionTemplate = ajax ? "exceptioninline" : "exception"; Utils.parseTemplate(Utils.getPage(context.getRequest(), exceptionTemplate), context); return null; } catch (XWikiException ex) { if (ex.getCode() == XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION) { LOGGER.error("Connection aborted"); } } catch (Exception e2) { // I hope this never happens LOGGER.error("Uncaught exceptions (inner): ", e); LOGGER.error("Uncaught exceptions (outer): ", e2); } return null; } finally { // Let's make sure we have flushed content and closed try { context.getResponse().getWriter().flush(); } catch (Throwable e) { // This might happen if the connection was closed, for example. // If we can't flush, then there's nothing more we can send to the client. } if (monitor != null) { monitor.endTimer("request"); monitor.startTimer("notify"); } if (eventSent) { // For the moment we're sending the XWiki context as the data, but this will be // changed in the future, when the whole platform will be written using components // and there won't be a need for the context. try { ObservationManager om = Utils.getComponent(ObservationManager.class); om.notify(new ActionExecutedEvent(context.getAction()), context.getDoc(), context); } catch (Throwable ex) { LOGGER.error( "Cannot send action notifications for document [" + docName + " using action [" + context.getAction() + "]", ex); } } if (monitor != null) { monitor.endTimer("notify"); } // Make sure we cleanup database connections // There could be cases where we have some if ((context != null) && (xwiki != null)) { xwiki.getStore().cleanUp(context); } } } finally { // End request if (monitor != null) { monitor.endRequest(); } if (context != null) { if (fileupload != null) { fileupload.cleanFileList(context); } } } }
public int install(XWikiContext context) throws XWikiException { boolean isAdmin = context.getWiki().getRightService().hasWikiAdminRights(context); if (testInstall(isAdmin, context) == DocumentInfo.INSTALL_IMPOSSIBLE) { setStatus(DocumentInfo.INSTALL_IMPOSSIBLE, context); return DocumentInfo.INSTALL_IMPOSSIBLE; } boolean hasCustomMappings = false; for (DocumentInfo docinfo : this.customMappingFiles) { BaseClass bclass = docinfo.getDoc().getXClass(); hasCustomMappings |= context.getWiki().getStore().injectCustomMapping(bclass, context); } if (hasCustomMappings) { context.getWiki().getStore().injectUpdatedCustomMappings(context); } int status = DocumentInfo.INSTALL_OK; // Determine if the user performing the installation is a farm admin. // We allow author preservation from the package only to farm admins. // In order to prevent sub-wiki admins to take control of a farm with forged packages. // We test it once for the whole import in case one of the document break user during the import // process. boolean backup = this.backupPack && isFarmAdmin(context); // Notify all the listeners about import ObservationManager om = Utils.getComponent(ObservationManager.class); // FIXME: should be able to pass some sort of source here, the name of the attachment or the // list of // imported documents. But for the moment it's fine om.notify(new XARImportingEvent(), null, context); try { // Start by installing all documents having a class definition so that their // definitions are available when installing documents using them. for (DocumentInfo classFile : this.classFiles) { if (installDocument(classFile, isAdmin, backup, context) == DocumentInfo.INSTALL_ERROR) { status = DocumentInfo.INSTALL_ERROR; } } // Install the remaining documents (without class definitions). for (DocumentInfo docInfo : this.files) { if (!this.classFiles.contains(docInfo)) { if (installDocument(docInfo, isAdmin, backup, context) == DocumentInfo.INSTALL_ERROR) { status = DocumentInfo.INSTALL_ERROR; } } } setStatus(status, context); } finally { // FIXME: should be able to pass some sort of source here, the name of the attachment or the // list of // imported documents. But for the moment it's fine om.notify(new XARImportedEvent(), null, context); registerExtension(context); } return status; }
/** * {@inheritDoc} <br> * This implementation saves the added annotation in the document where the target of the * annotation is. * * @see org.xwiki.annotation.io.IOService#addAnnotation(String, org.xwiki.annotation.Annotation) */ @Override public void addAnnotation(String target, Annotation annotation) throws IOServiceException { try { // extract the document name from the passed target // by default the fullname is the passed target String documentFullName = target; EntityReference targetReference = referenceResolver.resolve(target, EntityType.DOCUMENT); // try to get a document reference from the passed target reference EntityReference docRef = targetReference.extractReference(EntityType.DOCUMENT); if (docRef != null) { documentFullName = serializer.serialize(docRef); } // now get the document with that name XWikiContext deprecatedContext = getXWikiContext(); XWikiDocument document = deprecatedContext.getWiki().getDocument(documentFullName, deprecatedContext); // create a new object in this document to hold the annotation int id = document.createXObject(configuration.getAnnotationClassReference(), deprecatedContext); BaseObject object = document.getXObject(configuration.getAnnotationClassReference(), id); updateObject(object, annotation, deprecatedContext); // and set additional data: author to annotation author, date to now and the annotation target object.set(Annotation.DATE_FIELD, new Date(), deprecatedContext); // TODO: maybe we shouldn't trust what we receive from the caller but set the author from the // context. // Or the other way around, set the author of the document from the annotations author. object.set(Annotation.AUTHOR_FIELD, annotation.getAuthor(), deprecatedContext); // store the target of this annotation, serialized with a local serializer, to be exportable // and importable // in a different wiki // TODO: figure out if this is the best idea in terms of target serialization // 1/ the good part is that it is a fixed value that can be searched with a query in all // objects in the wiki // 2/ the bad part is that copying a document to another space will not also update its // annotation targets // 3/ if annotations are stored in the same document they annotate, the targets are only // required for object // fields // ftm don't store the type of the reference since we only need to recognize the field, not to // also read it. if (targetReference.getType() == EntityType.OBJECT_PROPERTY || targetReference.getType() == EntityType.DOCUMENT) { object.set( Annotation.TARGET_FIELD, localSerializer.serialize(targetReference), deprecatedContext); } else { object.set(Annotation.TARGET_FIELD, target, deprecatedContext); } // set the author of the document to the current user document.setAuthor(deprecatedContext.getUser()); deprecatedContext .getWiki() .saveDocument( document, "Added annotation on \"" + annotation.getSelection() + "\"", deprecatedContext); // notify listeners that an annotation was added ObservationManager observationManager = componentManager.lookup(ObservationManager.class); observationManager.notify( new AnnotationAddedEvent(documentFullName, object.getNumber() + ""), document, deprecatedContext); } catch (XWikiException e) { throw new IOServiceException( "An exception message has occurred while saving the annotation", e); } catch (ComponentLookupException exc) { this.logger.warn( "Could not get the observation manager to send notifications about the annotation add"); } }