| /******************************************************************************* |
| * Copyright (c) 2010 IBM Corporation 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 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| |
| package org.eclipse.ptp.internal.rdt.core.index; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.cdt.core.CCorePlugin; |
| import org.eclipse.cdt.core.model.ICProject; |
| import org.eclipse.cdt.internal.core.model.CModelManager; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceChangeListener; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.QualifiedName; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.ISchedulingRule; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.ptp.rdt.core.resources.RemoteNature; |
| import org.eclipse.ptp.rdt.core.services.IRDTServiceConstants; |
| import org.eclipse.ptp.services.core.IService; |
| import org.eclipse.ptp.services.core.IServiceConfiguration; |
| import org.eclipse.ptp.services.core.ServiceModelManager; |
| |
| public class IndexBuildSequenceController implements IResourceChangeListener { |
| |
| public static String INDEX_AFTER_BUILD_OPTION_KEY = "INDEX_AFTER_BUILD"; //$NON-NLS-1$ |
| |
| public static String INDEX_STATUS_KEY = "INDEX_STATUS"; //$NON-NLS-1$ |
| public static String BUILD_STATUS_KEY = "BUILD_STATUS"; //$NON-NLS-1$ |
| |
| public static final String TRUE = String.valueOf(true); |
| public static final String FALSE = String.valueOf(false); |
| |
| public static String STATUS_NEVERRUN = "never_run"; //$NON-NLS-1$ |
| public static String STATUS_RUNNING = "running"; //$NON-NLS-1$ |
| public static String STATUS_INCOMPLETE = "incomplete"; //$NON-NLS-1$ |
| public static String STATUS_COMPLETE = "complete"; //$NON-NLS-1$ |
| |
| // To make a build complete, must follow this build sequence, build_finish, |
| // buildOutput_scanned -> build_complete |
| public static String BUILD_SEQUENCE_STATUS_FINISH = "build_finish"; //$NON-NLS-1$ |
| public static String BUILD_SEQUENCE_STATUS_SCANNED = "build_sanned"; //$NON-NLS-1$ |
| |
| private static Map<String, IndexBuildSequenceController> projectStatusMap = new HashMap<String, IndexBuildSequenceController>(); |
| |
| private IProject project; |
| |
| private String runtimeBuildStatus; |
| |
| private IndexBuildSequenceController(IProject project) { |
| this.project = project; |
| intializeProjectStatus(); |
| ResourcesPlugin.getWorkspace().addResourceChangeListener(this); |
| } |
| |
| private void intializeProjectStatus() { |
| String index_after_build_option=null; |
| String index_status = null; |
| String build_status = null; |
| try { |
| index_after_build_option = project.getPersistentProperty( |
| new QualifiedName("", //$NON-NLS-1$ |
| INDEX_AFTER_BUILD_OPTION_KEY)); |
| index_status = project.getPersistentProperty( |
| new QualifiedName("", //$NON-NLS-1$ |
| INDEX_STATUS_KEY)); |
| build_status = project.getPersistentProperty( |
| new QualifiedName("", //$NON-NLS-1$ |
| BUILD_STATUS_KEY)); |
| |
| if (index_after_build_option == null) { |
| setIndexAfterBuildOption(); |
| } |
| if (index_status == null) { |
| |
| project.setPersistentProperty( |
| new QualifiedName("", //$NON-NLS-1$ |
| INDEX_STATUS_KEY), STATUS_NEVERRUN); |
| |
| } |
| if (build_status == null) { |
| project.setPersistentProperty( |
| new QualifiedName("", //$NON-NLS-1$ |
| BUILD_STATUS_KEY), STATUS_NEVERRUN); |
| } |
| } catch (CoreException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| |
| public static IndexBuildSequenceController getIndexBuildSequenceController(IProject p) { |
| String projectName = p.getName(); |
| IndexBuildSequenceController ps = projectStatusMap.get(projectName); |
| if (ps == null) { |
| |
| ps = new IndexBuildSequenceController(p); |
| projectStatusMap.put(projectName, ps); |
| |
| } |
| return ps; |
| |
| } |
| |
| |
| |
| public String getRuntimeBuildStatus() { |
| return runtimeBuildStatus; |
| } |
| |
| |
| public void setFinalBuildStatus() { |
| if (this.runtimeBuildStatus == null) { |
| setBuildCompleted(); |
| } else if (this.runtimeBuildStatus.equals(STATUS_INCOMPLETE)) { |
| setBuildInCompleted(); |
| } |
| //clear runtime build status |
| runtimeBuildStatus=null; |
| } |
| |
| public void setRuntimeBuildStatus(String runtimeBuildStatus) { |
| this.runtimeBuildStatus = runtimeBuildStatus; |
| } |
| |
| /* |
| * status_property_key will be INDEX_STATUS_KEY or BUILD_STATUS_KEY |
| * expect_status one of STATUS |
| */ |
| public boolean checkStatus(String status_property_key, String expect_status) { |
| String status = null; |
| |
| try { |
| status = project.getPersistentProperty( |
| new QualifiedName("", //$NON-NLS-1$ |
| status_property_key)); |
| } catch (CoreException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| if (status != null) { |
| return status.equals(expect_status); |
| } else { |
| return false; |
| } |
| |
| } |
| |
| public void setIndexAfterBuildOption() { |
| setStatus(INDEX_AFTER_BUILD_OPTION_KEY, TRUE); |
| } |
| |
| public void unsetIndexAfterBuildOption() { |
| setStatus(INDEX_AFTER_BUILD_OPTION_KEY, FALSE); |
| } |
| public boolean isBuildServiceEnabled(){ |
| IService buildService = ServiceModelManager.getInstance().getService(IRDTServiceConstants.SERVICE_BUILD); |
| IServiceConfiguration serviceConfig = ServiceModelManager.getInstance().getActiveConfiguration(project); |
| if(serviceConfig.isDisabled(buildService)){ |
| return false; |
| }else{ |
| return true; |
| } |
| } |
| public boolean isIndexAfterBuildSet(){ |
| |
| //if(isBuildServiceEnabled()){ |
| return checkStatus(INDEX_AFTER_BUILD_OPTION_KEY, TRUE); |
| //}else{ |
| //return false; |
| //} |
| } |
| |
| public boolean isIndexNeverRun() { |
| return checkStatus(INDEX_STATUS_KEY, STATUS_NEVERRUN); |
| } |
| |
| public boolean isIndexRunning() { |
| return checkStatus(INDEX_STATUS_KEY, STATUS_RUNNING); |
| } |
| |
| public boolean isIndexInCompleted() { |
| return checkStatus(INDEX_STATUS_KEY, STATUS_INCOMPLETE); |
| } |
| |
| public boolean isIndexCompleted() { |
| return checkStatus(INDEX_STATUS_KEY, STATUS_COMPLETE); |
| } |
| |
| public boolean isBuildNeverRun() { |
| return checkStatus(BUILD_STATUS_KEY, STATUS_NEVERRUN); |
| } |
| |
| public boolean isBuildRunning() { |
| return checkStatus(BUILD_STATUS_KEY, STATUS_RUNNING); |
| } |
| |
| public boolean isBuildInCompleted() { |
| return checkStatus(BUILD_STATUS_KEY, STATUS_INCOMPLETE); |
| } |
| |
| public boolean isBuildCompleted() { |
| return checkStatus(BUILD_STATUS_KEY, STATUS_COMPLETE); |
| } |
| |
| public void setIndexCompleted() { |
| setStatus(INDEX_STATUS_KEY, STATUS_COMPLETE); |
| } |
| |
| public void setIndexInCompleted() { |
| setStatus(INDEX_STATUS_KEY, STATUS_INCOMPLETE); |
| } |
| |
| public void setIndexRunning() { |
| setStatus(INDEX_STATUS_KEY, STATUS_RUNNING); |
| } |
| |
| public void setBuildCompleted() { |
| setStatus(BUILD_STATUS_KEY, STATUS_COMPLETE); |
| } |
| |
| public void setBuildInCompleted() { |
| setStatus(BUILD_STATUS_KEY, STATUS_INCOMPLETE); |
| } |
| |
| /** |
| * we don't want to clean build to update a never run status |
| */ |
| public void setBuildInCompletedForCleanBuild() { |
| if(!isBuildNeverRun()){ |
| setStatus(BUILD_STATUS_KEY, STATUS_INCOMPLETE); |
| } |
| |
| } |
| |
| public void setBuildRunning() { |
| setStatus(BUILD_STATUS_KEY, STATUS_RUNNING); |
| } |
| |
| /* |
| * status_property_key will be INDEX_STATUS_KEY or BUILD_STATUS_KEY |
| * expect_status one of STATUS |
| */ |
| public void setStatus(String status_property_key, String status_to_set) { |
| try { |
| project.setPersistentProperty(new QualifiedName("", //$NON-NLS-1$ |
| status_property_key), status_to_set); |
| } catch (CoreException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| |
| /* |
| * public void setBuildStatus(String status){ |
| * if(status.equals(BUILD_SEQUENCE_STATUS_FINISH)){ build_sequence_status = |
| * BUILD_SEQUENCE_STATUS_FINISH; } |
| * if(status.equals(BUILD_SEQUENCE_STATUS_SCANNED)){ |
| * if(build_sequence_status.equals(BUILD_SEQUENCE_STATUS_FINISH)){ |
| * build_sequence_status = BUILD_SEQUENCE_STATUS_SCANNED; |
| * setStatus(BUILD_STATUS_KEY, STATUS_COMPLETE); |
| * if(start_index_after_build_complete){ startIndex(); } } } } |
| */ |
| /*** |
| * |
| * |
| * |
| * |
| * ri=reindex, iu=index update, optional ri = prompt user that build is incompleted, provide option if they want to preceed build. |
| * IF=index following build |
| * |
| * |
| * index neverRun index running index incompleted index completed |
| * build disabled as usual as usual as usual as usual |
| * consider as never build iu -> ri |
| * |
| * build never run skip iu, no ri case |
| * |
| * build running must be 1st build |
| * no need this state run IF, skip iu skip IF, skip IF skip IF |
| * provide user a iu, ri as usual iu, ri as usual iu, ri as usual |
| * warning message |
| * if build is |
| * incomplete |
| * |
| * build incomplete -> optional ri, optional ri, optional ri, optional ri |
| * skip iu iu as usual iu as usual iu as usual |
| * |
| * build complete should never be ri, iu as usual as usual as usual |
| * this case |
| * |
| * |
| * |
| * |
| * |
| * |
| */ |
| |
| /** |
| * since we run index after first time build, so the first time building |
| * must be at status of build-running and index-never-run. we want to skip |
| * index update (check when do index update) and run index after build |
| * (check in builder) in this case |
| */ |
| /* |
| public boolean isBeforeOrUnderFirstTimeBuilding() { |
| if (isBuildNeverRun()) { |
| return true; |
| } |
| if (isBuildRunning() && isIndexNeverRun()) { |
| return true; |
| } |
| return false; |
| } |
| */ |
| /** |
| * we call invoke index before update build status, so if the build status is never run at that time, |
| * it must a first build attempt. |
| * @return |
| */ |
| public boolean shouldRunIndexFollowingBuild(){ |
| return isBuildRunning(); |
| } |
| |
| /** |
| * This case should never happen since we run index for first completed build. |
| * But in case it happens, we will turn index update to reindex. |
| * @return |
| */ |
| public boolean shouldTurnIndexUpdateToReindex(){ |
| return isIndexNeverRun()&&isBuildCompleted(); |
| } |
| /** |
| * if index is not done yet, we will skip index update. The only exception is if build is completed, but this case should |
| * never happen since we run index for first completed build. |
| * @return |
| */ |
| public boolean shouldSkipIndexUpdate(){ |
| |
| if(isBuildRunning()){ |
| return true; |
| } |
| if (isIndexNeverRun()){ |
| |
| if(isBuildCompleted()){ |
| return false; |
| } |
| return true; |
| |
| |
| } |
| return false; |
| } |
| |
| /** |
| * this is called from reindex autio after user choose to continue index after an optional index prompt. |
| * the build must be failed at the time. |
| */ |
| public void setBuildIncompleteIfItIsRunning(){ |
| if(isBuildRunning()){ |
| //todo check if build is still running. |
| setBuildInCompleted(); |
| } |
| } |
| /** |
| * skip reindex during the first time build, when build is never run and index is never run. |
| * |
| * this case would alos match if user run an optional reindex(build is never run and index is never run) and select to |
| * continue do index, to solve this conflicts, we will turn index status to running after user selects continue to do index. |
| * @return |
| */ |
| public boolean shouldSkipReindex() |
| { |
| if(isBuildRunning()){ |
| return true; |
| } |
| //the case of build is disable during project creation. |
| return isBuildNeverRun()&&isIndexNeverRun(); |
| } |
| /* |
| * should be called from reindex action |
| * return true if build is never run or incomplete |
| * |
| */ |
| public boolean isOptionalIndex() { |
| return !isBuildCompleted(); |
| } |
| |
| |
| /** |
| * precondition to call this function, |
| * isIndexAfterBuildSet() ==true |
| */ |
| public void invokeIndex(){ |
| |
| |
| |
| Job job = new Job("Indexing Job"){ //$NON-NLS-1$ |
| protected IStatus run(IProgressMonitor monitor) { |
| |
| if(shouldRunIndexFollowingBuild()){ |
| setFinalBuildStatus(); |
| if(isBuildCompleted()){ |
| //for indexing following first time build, only run it after a completed build. |
| ICProject cProject = CModelManager.getDefault().getCModel().getCProject(project); |
| CCorePlugin.getIndexManager().reindex(cProject); |
| //System.out.println("running invoke indexing job. "); //$NON-NLS-1$ |
| } |
| |
| }else{ |
| //System.out.println("not running index job, just update build status. "); //$NON-NLS-1$ |
| setFinalBuildStatus(); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| }; |
| ISchedulingRule rule = ResourcesPlugin.getWorkspace().getRoot(); |
| job.setRule(rule); |
| job.schedule(); |
| |
| //System.out.println("schedule invoke indexing job. "); //$NON-NLS-1$ |
| |
| |
| } |
| |
| private void deleteProjectStaus(String projectName) { |
| projectStatusMap.remove(projectName); |
| } |
| |
| |
| public void resourceChanged(IResourceChangeEvent event) { |
| if (event.getSource() instanceof IWorkspace) { |
| |
| IResource resource = event.getResource(); |
| if (event.getType() == IResourceChangeEvent.PRE_DELETE && resource.getType() == IResource.PROJECT) { |
| deleteProjectStaus(resource.getName()); |
| } |
| } |
| } |
| |
| } |