잠금 정책을 정의하여 읽기 전용 세그먼트 만들기
Visual Studio 시각화 및 모델링 SDK의 불변성 API를 사용하면 프로그램이 DSL(도메인 특정 언어) 모델의 일부 또는 전부를 잠글 수 있습니다. 그러면 해당 모델을 읽을 수는 있지만 변경할 수는 없습니다. 예를 들어 이 읽기 전용 옵션을 사용하면 사용자가 동료에게 DSL 모델에 주석을 달고 검토하도록 요청하되 원본은 변경하지 못하게 할 수 있습니다.
또한 DSL의 작성자는 잠금 정책을 정의할 수 있습니다. 잠금 정책은 허용된 잠금, 허용되지 않은 잠금 또는 필수 잠금을 정의합니다. 예를 들어 DSL을 게시하는 경우 타사 개발자가 새 명령으로 이 DSL을 확장할 수 있습니다. 하지만 잠금 정책을 사용하여 모델의 지정된 파트에 대한 읽기 전용 상태를 변경하지 못하게 할 수 있습니다.
참고 항목
잠금 정책은 리플렉션을 사용하여 우회할 수 있습니다. 따라서 타사 개발자를 위한 명확한 경계를 제공하지만 강력한 보안을 제공하지는 않습니다.
추가 정보 및 샘플은 Visual Studio 시각화 및 모델링 SDK에서 확인할 수 있습니다.
참고 항목
텍스트 템플릿 변환 구성 요소는 Visual Studio 확장 개발 워크로드의 일부로 자동으로 설치됩니다. Visual Studio 설치 프로그램의 개별 구성 요소 탭, SDK, 라이브러리, 프레임워크 범주 아래에서 설치할 수도 있습니다. 개별 구성 요소 탭에서 Modeling SDK 구성 요소를 설치합니다.
잠금 설정 및 가져오기
저장소, 파티션 또는 개별 요소에 대해 잠금을 설정할 수 있습니다. 예를 들어 다음 문은 모델 요소가 삭제되는 것을 방지하고 해당 속성이 변경되지 않도록 합니다.
using Microsoft.VisualStudio.Modeling.Immutability; ...
element.SetLocks(Locks.Delete | Locks.Property);
다른 잠금 값을 사용하여 관계 변경, 요소 생성, 파티션 간 이동, 역할 내 링크 순서 변경을 방지할 수 있습니다.
잠금은 사용자 작업 및 프로그램 코드에 모두 적용됩니다. 프로그램 코드를 변경하려고 하면 InvalidOperationException
이 throw됩니다. 실행 취소 또는 다시 실행 작업에서는 잠금이 무시됩니다.
IsLocked(Locks)
를 사용하여 요소에 지정된 집합의 잠금이 있는지 여부를 검색하고 GetLocks()
를 사용하여 요소에 대한 현재 잠금 세트를 가져올 수 있습니다.
트랜잭션을 사용하지 않고 잠금을 설정할 수 있습니다. 잠금 데이터베이스는 저장소의 일부가 아닙니다. 저장소에서 값 변경에 대한 응답으로 잠금을 설정하는 경우(예: OnValueChanged
) 실행 취소 작업의 일부인 변경 작업을 허용해야 합니다.
이러한 메서드는 Microsoft.VisualStudio.Modeling.Immutability 네임스페이스에 정의된 확장 메서드입니다.
파티션 및 저장소에 대한 잠금
잠금은 파티션 및 저장소에도 적용할 수 있습니다. 파티션에 설정된 잠금은 파티션의 모든 요소에 적용됩니다. 따라서 예를 들어 다음 문은 자체 잠금의 상태와 관계없이 파티션의 모든 요소가 삭제되는 것을 방지합니다. 그럼에도 불구하고 Locks.Property
같은 다른 잠금은 여전히 개별 요소에 설정할 수 있습니다.
partition.SetLocks(Locks.Delete);
저장소에서 설정된 잠금은 파티션 및 요소에 대한 해당 잠금의 설정에 관계없이 모든 요소에 적용됩니다.
잠금 사용
잠금을 사용하여 다음 예제와 같은 체계를 구현할 수 있습니다.
주석을 나타내는 경우를 제외하고 모든 요소 및 관계의 변경을 허용하지 않습니다. 이 방법을 사용하면 사용자가 모델을 변경하지 않고 주석을 추가할 수 있습니다.
기본 파티션에 대한 변경을 허용하지 않지만 다이어그램 파티션은 변경할 수 있습니다. 사용자가 다이어그램을 다시 정렬할 수 있지만 기본 모델을 변경할 수는 없습니다.
별도의 데이터베이스에 등록된 사용자 그룹을 제외하고 저장소에 대한 변경을 허용하지 않습니다. 다른 사용자의 경우 다이어그램 및 모델은 읽기 전용입니다.
다이어그램의 부울 속성이 true로 설정된 경우 모델에 대한 변경을 허용하지 않습니다. 해당 속성을 변경하는 메뉴 명령을 제공합니다. 이 방법을 통해 사용자가 실수로 변경하지 않도록 할 수 있습니다.
특정 클래스의 요소 또는 관계의 추가 및 삭제를 허용하지 않지만 속성 변경을 허용합니다. 이 방법은 사용자가 속성을 채울 수 있는 고정 양식을 제공합니다.
잠금 값
잠금은 저장소, 파티션 또는 개별 ModelElement에 설정할 수 있습니다. 잠금은 Flags
열거형입니다. '|'를 사용하여 해당 값을 결합할 수 있습니다.
ModelElement의 잠금에는 항상 해당 파티션의 잠금이 포함됩니다.
파티션의 잠금에는 항상 저장소의 잠금이 포함됩니다.
파티션 또는 저장소에 잠금을 설정하는 동시에 개별 요소에 대해 잠금을 해제할 수 없습니다.
값 | IsLocked(Value) 가 true인 경우의 의미 |
---|---|
없음 | 제한 없음 |
속성 | 요소의 도메인 속성을 변경할 수 없습니다. 이 값은 관계에서 도메인 클래스의 역할에 의해 생성된 속성에는 적용되지 않습니다. |
추가 | 파티션 또는 저장소에 새 요소 및 링크를 만들 수 없습니다. ModelElement 에는 적용되지 않습니다. |
이동 | element.IsLocked(Move) 가 true인 경우 또는 targetPartition.IsLocked(Move) 가 true인 경우 파티션 간에 요소를 이동할 수 없습니다. |
삭제 | 요소 자체에 대해 또는 포함된 요소 및 도형과 같이 삭제가 전파되는 요소에 대해 이 잠금이 설정된 경우 요소를 삭제할 수 없습니다. element.CanDelete() 를 사용하여 요소를 삭제할 수 있는지 여부를 검색할 수 있습니다. |
다시 정렬 | 역할 수행자에서 링크 순서를 변경할 수 없습니다. |
RolePlayer | 이 요소에서 소스로 사용되는 링크 세트는 변경할 수 없습니다. 예를 들어 새 요소를 이 요소에 포함할 수 없습니다. 이 값은 요소가 대상인 링크에는 영향을 주지 않습니다. 이 요소가 링크인 경우 해당 소스 및 대상이 영향을 받지 않습니다. |
모두 | 다른 값의 비트 OR입니다. |
잠금 정책
DSL의 작성자는 잠금 정책을 정의할 수 있습니다. 잠금 정책은 SetLocks()
의 작업을 조정합니다. 그러므로 특정 잠금이 설정되지 않도록 하거나 특정 잠금을 설정하도록 지정할 수 있습니다. 일반적으로 private
변수를 선언하는 것과 동일한 방식으로 사용자 또는 개발자가 실수로 의도된 DSL 사용하는 것을 방해하지 않도록 잠금 정책을 사용합니다.
잠금 정책을 사용하여 요소의 형식에 종속된 모든 요소에 대한 잠금을 설정할 수도 있습니다. 이 동작은 요소를 처음 만들거나 파일에서 역직렬화할 때 SetLocks(Locks.None)
가 항상 호출되기 때문입니다.
그러나 요소의 수명 동안 요소에 대한 잠금을 변경하는 정책을 사용할 수 없습니다. 이러한 효과를 얻으려면 SetLocks()
에 대한 호출을 사용해야 합니다.
잠금 정책을 정의하려면:
ILockingPolicy를 구현하는 클래스를 만듭니다.
DSL의 DocData를 통해 사용할 수 있는 서비스에 이 클래스를 추가합니다.
잠금 정책을 정의하려면
ILockingPolicy에는 다음 정의가 있습니다.
public interface ILockingPolicy
{
Locks RefineLocks(ModelElement element, Locks proposedLocks);
Locks RefineLocks(Partition partition, Locks proposedLocks);
Locks RefineLocks(Store store, Locks proposedLocks);
}
저장소, 파티션 또는 ModelElement에 대해 SetLocks()
가 호출되면 이러한 메서드가 호출됩니다. 각 메서드에서 제안된 잠금 세트가 제공됩니다. 제안된 집합을 반환하거나, 잠금을 추가 또는 제외할 수 있습니다.
예시:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Immutability;
namespace Company.YourDsl.DslPackage // Change
{
public class MyLockingPolicy : ILockingPolicy
{
/// <summary>
/// Moderate SetLocks(this ModelElement target, Locks locks)
/// </summary>
/// <param name="element">target</param>
/// <param name="proposedLocks">locks</param>
/// <returns></returns>
public Locks RefineLocks(ModelElement element, Locks proposedLocks)
{
// In my policy, users can never delete an element,
// and other developers cannot easily change that:
return proposedLocks | Locks.Delete);
}
public Locks RefineLocks(Store store, Locks proposedLocks)
{
// Only one user can change this model:
return Environment.UserName == "aUser"
? proposedLocks : Locks.All;
}
다른 코드에서 SetLocks(Lock.Delete):
를 호출하는 경우에도 사용자가 항상 요소를 삭제할 수 있도록 하려면
return proposedLocks & (Locks.All ^ Locks.Delete);
MyClass의 모든 요소에 대한 모든 속성의 변경을 허용하지 않으려면
return element is MyClass ? (proposedLocks | Locks.Property) : proposedLocks;
정책을 서비스로 사용할 수 있도록 설정하려면
DslPackage
프로젝트에서 다음 예제와 비슷한 코드가 포함된 새 파일을 추가합니다.
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Immutability;
namespace Company.YourDsl.DslPackage // Change
{
// Override the DocData GetService() for this DSL.
internal partial class YourDslDocData // Change
{
/// <summary>
/// Custom locking policy cache.
/// </summary>
private ILockingPolicy myLockingPolicy = null;
/// <summary>
/// Called when a service is requested.
/// </summary>
/// <param name="serviceType">Service requested</param>
/// <returns>Service implementation</returns>
public override object GetService(System.Type serviceType)
{
if (serviceType == typeof(SLockingPolicy)
|| serviceType == typeof(ILockingPolicy))
{
if (myLockingPolicy == null)
{
myLockingPolicy = new MyLockingPolicy();
}
return myLockingPolicy;
}
// Request is for some other service.
return base.GetService(serviceType);
}
}