mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 20:17:51 +02:00
171 lines
6.4 KiB
Java
171 lines
6.4 KiB
Java
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package google.registry.flows;
|
|
|
|
import static com.google.common.base.Preconditions.checkState;
|
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
|
|
|
import com.googlecode.objectify.Key;
|
|
import google.registry.flows.EppException.AuthorizationErrorException;
|
|
import google.registry.flows.FlowModule.InputXml;
|
|
import google.registry.model.EppResource;
|
|
import google.registry.model.domain.Period;
|
|
import google.registry.model.domain.metadata.MetadataExtension;
|
|
import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand;
|
|
import google.registry.model.eppoutput.EppOutput;
|
|
import google.registry.model.reporting.HistoryEntry;
|
|
import google.registry.util.TypeUtils.TypeInstantiator;
|
|
import javax.inject.Inject;
|
|
|
|
/**
|
|
* An EPP flow that creates or mutates a single stored resource.
|
|
*
|
|
* @param <R> the resource type being changed
|
|
* @param <C> the command type, marshalled directly from the epp xml
|
|
*
|
|
* @error {@link OnlyToolCanPassMetadataException}
|
|
*/
|
|
public abstract class ResourceCreateOrMutateFlow
|
|
<R extends EppResource, C extends SingleResourceCommand> extends SingleResourceFlow<R, C>
|
|
implements TransactionalFlow {
|
|
|
|
@Inject EppRequestSource eppRequestSource;
|
|
@Inject @InputXml byte[] inputXmlBytes;
|
|
|
|
String repoId;
|
|
protected R newResource;
|
|
protected HistoryEntry historyEntry;
|
|
protected MetadataExtension metadataExtension;
|
|
|
|
@Override
|
|
protected final void initSingleResourceFlow() throws EppException {
|
|
registerExtensions(MetadataExtension.class);
|
|
metadataExtension = eppInput.getSingleExtension(MetadataExtension.class);
|
|
initRepoId();
|
|
initHistoryEntry();
|
|
initResourceCreateOrMutateFlow();
|
|
}
|
|
|
|
/** Subclasses can optionally override this for further initialization. */
|
|
@SuppressWarnings("unused")
|
|
protected void initResourceCreateOrMutateFlow() throws EppException {}
|
|
|
|
/**
|
|
* Initializes the repoId on the flow. For mutate flows, the repoId is the same as that of the
|
|
* existing resource. For create flows, a new repoId is allocated for the appropriate class.
|
|
*/
|
|
protected abstract void initRepoId();
|
|
|
|
/**
|
|
* Create the history entry associated with this resource create or mutate flow.
|
|
*/
|
|
private void initHistoryEntry() {
|
|
// Don't try to create a historyEntry for mutate flows that are failing because the
|
|
// existingResource doesn't actually exist.
|
|
historyEntry = (repoId == null) ? null : new HistoryEntry.Builder()
|
|
.setType(getHistoryEntryType())
|
|
.setPeriod(getCommandPeriod())
|
|
.setClientId(getClientId())
|
|
.setTrid(trid)
|
|
.setModificationTime(now)
|
|
.setXmlBytes(storeXmlInHistoryEntry() ? inputXmlBytes : null)
|
|
.setBySuperuser(isSuperuser)
|
|
.setReason(getHistoryEntryReason())
|
|
.setRequestedByRegistrar(getHistoryEntryRequestedByRegistrar())
|
|
.setParent(getResourceKey())
|
|
.build();
|
|
}
|
|
|
|
/**
|
|
* Returns a Key pointing to this resource, even if this resource hasn't been initialized or
|
|
* persisted yet.
|
|
*/
|
|
protected Key<EppResource> getResourceKey() {
|
|
checkState(repoId != null,
|
|
"RepoId hasn't been initialized yet; getResourceKey() called too early");
|
|
Class<R> resourceClazz = new TypeInstantiator<R>(getClass()){}.getExactType();
|
|
return Key.<EppResource>create(null, resourceClazz, repoId);
|
|
}
|
|
|
|
@Override
|
|
protected final EppOutput runResourceFlow() throws EppException {
|
|
newResource = createOrMutateResource();
|
|
verifyNewStateIsAllowed();
|
|
validateMetadataExtension();
|
|
modifyRelatedResources();
|
|
enqueueTasks();
|
|
ofy().save().<Object>entities(newResource, historyEntry);
|
|
return getOutput();
|
|
}
|
|
|
|
/** Execute the inner core of the command and returned the created or mutated resource. */
|
|
protected abstract R createOrMutateResource() throws EppException;
|
|
|
|
/** Check the new state before writing it. */
|
|
@SuppressWarnings("unused")
|
|
protected void verifyNewStateIsAllowed() throws EppException {}
|
|
|
|
/** Kick off any tasks that need to happen asynchronously. */
|
|
@SuppressWarnings("unused")
|
|
protected void enqueueTasks() throws EppException {}
|
|
|
|
/** Modify any other resources that need to be informed of this change. */
|
|
@SuppressWarnings("unused")
|
|
protected void modifyRelatedResources() throws EppException {}
|
|
|
|
/** Ensure that, if a metadata command exists, it is being passed from a tool-created session. */
|
|
void validateMetadataExtension() throws EppException {
|
|
if (!(metadataExtension == null || eppRequestSource.equals(EppRequestSource.TOOL))) {
|
|
throw new OnlyToolCanPassMetadataException();
|
|
}
|
|
}
|
|
|
|
/** Subclasses must override this to specify the type set on the history entry. */
|
|
protected abstract HistoryEntry.Type getHistoryEntryType();
|
|
|
|
/** Subclasses may override this if they do not wish to store the XML of a command. */
|
|
protected boolean storeXmlInHistoryEntry() { return true; }
|
|
|
|
/** Retrieve the reason for the history entry. */
|
|
protected String getHistoryEntryReason() {
|
|
return metadataExtension != null
|
|
? metadataExtension.getReason()
|
|
: null;
|
|
}
|
|
|
|
/** Retrieve the requested by registrar flag for the history entry. */
|
|
protected Boolean getHistoryEntryRequestedByRegistrar() {
|
|
return metadataExtension != null
|
|
? metadataExtension.getRequestedByRegistrar()
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Subclasses that have a specified period for their command should override this to so that the
|
|
* history entry contains the correct data.
|
|
*/
|
|
protected Period getCommandPeriod() { return null; }
|
|
|
|
/** Get the {@link EppOutput} to return. */
|
|
protected abstract EppOutput getOutput() throws EppException;
|
|
|
|
/** Only a tool can pass a metadata extension. */
|
|
public static class OnlyToolCanPassMetadataException extends AuthorizationErrorException {
|
|
public OnlyToolCanPassMetadataException() {
|
|
super("Metadata extensions can only be passed by tools.");
|
|
}
|
|
}
|
|
|
|
}
|