/** * (C) Copyright 2013 Jabylon (http://www.jabylon.org) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.jabylon.rest.ui.wicket.config.sections; import java.io.File; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.store.Directory; import org.apache.wicket.Component; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.form.upload.FileUpload; import org.apache.wicket.markup.html.form.upload.MultiFileUploadField; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.jabylon.cdo.server.ServerConstants; import org.jabylon.common.progress.RunnableWithProgress; import org.jabylon.common.util.PreferencesUtil; import org.jabylon.index.properties.IndexActivator; import org.jabylon.index.properties.QueryService; import org.jabylon.index.properties.jobs.impl.ReorgIndexJob; import org.jabylon.properties.Workspace; import org.jabylon.rest.ui.Activator; import org.jabylon.rest.ui.model.PreferencesPropertyModel; import org.jabylon.rest.ui.model.ProgressionModel; import org.jabylon.rest.ui.wicket.BasicPanel; import org.jabylon.rest.ui.wicket.components.ControlGroup; import org.jabylon.rest.ui.wicket.components.ProgressPanel; import org.jabylon.rest.ui.wicket.components.ProgressShowingAjaxButton; import org.jabylon.rest.ui.wicket.config.AbstractConfigSection; import org.jabylon.rest.ui.wicket.validators.CronValidator; import org.jabylon.scheduler.JobExecution; import org.jabylon.scheduler.ScheduleServiceException; import org.jabylon.scheduler.SchedulerService; import org.jabylon.security.CommonPermissions; import org.osgi.service.prefs.Preferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class IndexingConfigSection extends BasicPanel<Workspace> { private static final long serialVersionUID = 1L; @Inject private QueryService queryService; private static final Logger LOGGER = LoggerFactory.getLogger(IndexingConfigSection.class); private ProgressionModel progressModel; @Inject private SchedulerService scheduler; private Preferences config; public IndexingConfigSection(String id, IModel<Workspace> model, Preferences config) { super(id, model); this.config = config; } @Override protected void construct() { super.construct(); setOutputMarkupId(true); progressModel = new ProgressionModel(""); add(new Label("summary", new StringResourceModel("index.size.summary", this, null, getIndexSize()))); final ProgressPanel progressPanel = new ProgressPanel("progress", progressModel); add(progressPanel); add(createUpdateIndexAction(progressPanel)); Preferences indexJobConfig = PreferencesUtil.getNodeForJob(config, ReorgIndexJob.JOB_ID); PreferencesPropertyModel updateModel = new PreferencesPropertyModel(indexJobConfig, JobExecution.PROP_JOB_SCHEDULE, ReorgIndexJob.DEFAULT_SCHEDULE); ControlGroup indexCronGroup = new ControlGroup("index-cron-group", nls("index.cron.label"), nls("index.cron.description")); TextField<String> indexCron = new TextField<String>("index-cron", updateModel) { private static final long serialVersionUID = 1572798560921411829L; @Override protected void convertInput() { super.convertInput(); String[] value = getInputAsArray(); String tmp = value != null && value.length > 0 ? value[0] : null; if(tmp==null) setConvertedInput(""); } }; indexCron.add(new CronValidator()); indexCron.setConvertEmptyInputStringToNull(false); indexCronGroup.add(indexCron); add(indexCronGroup); if(scheduler!=null) { try { Date nextExecution = scheduler.nextExecution(indexJobConfig); if(nextExecution!=null) { indexCronGroup.setExtraLabel(nls("next.schedule.label",format(nextExecution))); } } catch (ScheduleServiceException e) { LOGGER.warn("failed to retrieve next job execution for {}",indexJobConfig.absolutePath()); } } Form<Void> uploadForm = new FileUploadForm("tmx-upload-form"); add(uploadForm); } protected String format(Date nextExecution) { long current = System.currentTimeMillis(); //if it's less than 15 hours away only show the time if(nextExecution.getTime()-current<TimeUnit.HOURS.toMillis(23)) return SimpleDateFormat.getTimeInstance(DateFormat.SHORT,getLocale()).format(nextExecution); return SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT,SimpleDateFormat.SHORT,getLocale()).format(nextExecution); } private long getIndexSize() { Directory directory = IndexActivator.getDefault().getOrCreateDirectory(); long size = 0; try { if (directory != null) { String[] files; files = directory.listAll(); for (String file : files) { size += directory.fileLength(file); } } } catch (IOException e) { LOGGER.error("Failed to compute index size",e); } return size / 1024; } protected Component createUpdateIndexAction(ProgressPanel progressPanel) { RunnableWithProgress runnable = new RunnableWithProgress() { private static final long serialVersionUID = 1L; @Override public IStatus run(IProgressMonitor monitor) { Activator.getDefault().getRepositoryConnector(); try { queryService.rebuildIndex(monitor); } catch (CorruptIndexException e) { return new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Failed to rebuild index",e); } catch (IOException e) { return new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Failed to rebuild index",e); } return Status.OK_STATUS; } }; return new ProgressShowingAjaxButton("update-index", progressPanel, runnable, nls("update.index.job.label")); } public static class IndexingConfig extends AbstractConfigSection<Workspace> { private static final long serialVersionUID = 1L; @Override public WebMarkupContainer doCreateContents(String id, IModel<Workspace> input, Preferences prefs) { return new IndexingConfigSection(id, input, prefs); } @Override public void commit(IModel<Workspace> input, Preferences config) { // nothing to do } @Override public String getRequiredPermission() { String projectName = null; if(getDomainObject()!=null) projectName = getDomainObject().getName(); return CommonPermissions.constructPermission(CommonPermissions.WORKSPACE,projectName,CommonPermissions.ACTION_CONFIG); } } private class FileUploadForm extends Form<Void> { private static final long serialVersionUID = -3653084217384164795L; private final ArrayList<FileUpload> uploads; public FileUploadForm(String id) { super(id); // set this form to multipart mode (always needed for uploads!) setMultiPart(true); uploads = new ArrayList<FileUpload>(); // Add one multi-file upload field IModel<ArrayList<FileUpload>> model = new Model<ArrayList<FileUpload>>(uploads); add(new MultiFileUploadField("tmx-upload",model)); // Set maximum size to 100K for demo purposes // setMaxSize(Bytes.kilobytes(100)); } @Override protected void onSubmit() { super.onSubmit(); File home = new File(ServerConstants.WORKING_DIR); File tmx = new File(home,"tmx"); tmx.mkdirs(); boolean didSomething = false; for (FileUpload fileUpload : uploads) { File target = new File(tmx,fileUpload.getClientFileName()); try { target.createNewFile(); fileUpload.writeTo(target); didSomething = true; } catch (IOException e) { LOGGER.error("Failed to upload TMX file "+target,e); } } if(didSomething) { RunnableWithProgress runnable = new RunnableWithProgress() { private static final long serialVersionUID = 1L; @Override public IStatus run(IProgressMonitor monitor) { Activator.getDefault().getRepositoryConnector(); try { queryService.rebuildIndex(monitor); } catch (CorruptIndexException e) { return new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Failed to rebuild index",e); } catch (IOException e) { return new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Failed to rebuild index",e); } return Status.OK_STATUS; } }; Activator.getDefault().getProgressService().schedule(runnable, nls("update.index.job.label").getString()); } } } }