/** * Copyright 2010 Google Inc. * * 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 org.waveprotocol.box.server.persistence.protos; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.protobuf.ByteString; import com.google.wave.api.Context; import com.google.wave.api.ProtocolVersion; import com.google.wave.api.event.EventType; import com.google.wave.api.robot.Capability; import org.waveprotocol.box.server.account.AccountData; import org.waveprotocol.box.server.account.HumanAccountData; import org.waveprotocol.box.server.account.HumanAccountDataImpl; import org.waveprotocol.box.server.account.RobotAccountData; import org.waveprotocol.box.server.account.RobotAccountDataImpl; import org.waveprotocol.box.server.authentication.PasswordDigest; import org.waveprotocol.box.server.persistence.protos.ProtoAccountStoreData.ProtoAccountData; import org.waveprotocol.box.server.persistence.protos.ProtoAccountStoreData.ProtoAccountData.AccountDataType; import org.waveprotocol.box.server.persistence.protos.ProtoAccountStoreData.ProtoHumanAccountData; import org.waveprotocol.box.server.persistence.protos.ProtoAccountStoreData.ProtoPasswordDigest; import org.waveprotocol.box.server.persistence.protos.ProtoAccountStoreData.ProtoRobotAccountData; import org.waveprotocol.box.server.persistence.protos.ProtoAccountStoreData.ProtoRobotCapabilities; import org.waveprotocol.box.server.persistence.protos.ProtoAccountStoreData.ProtoRobotCapability; import org.waveprotocol.box.server.robots.RobotCapabilities; import org.waveprotocol.wave.model.wave.ParticipantId; import java.util.List; import java.util.Map; /** * This class is used to serialize and deserialize {@link AccountData} and {@link ProtoAccountData} * * @author tad.glines@gmail.com (Tad Glines) */ public class ProtoAccountDataSerializer { /** * Serialize {@link AccountData} into {@link ProtoAccountData}. */ public static ProtoAccountData serialize(AccountData account) { Preconditions.checkNotNull(account, "account is null"); Preconditions.checkArgument(account.isHuman() || account.isRobot(), "account is neither a human or robot account!"); ProtoAccountData.Builder builder = ProtoAccountData.newBuilder(); builder.setAccountId(account.getId().getAddress()); if (account.isHuman()) { builder.setAccountType(AccountDataType.HUMAN_ACCOUNT); builder.setHumanAccountData(serialize(account.asHuman())); } else if (account.isRobot()) { builder.setAccountType(AccountDataType.ROBOT_ACCOUNT); builder.setRobotAccountData(serialize(account.asRobot())); } return builder.build(); } private static ProtoHumanAccountData serialize(HumanAccountData account) { Preconditions.checkNotNull(account, "account is null"); ProtoHumanAccountData.Builder builder = ProtoHumanAccountData.newBuilder(); if (account.getPasswordDigest() != null) { builder.setPasswordDigest(serialize(account.getPasswordDigest())); } return builder.build(); } private static ProtoPasswordDigest serialize(PasswordDigest digest) { Preconditions.checkNotNull(digest, "digest is null"); return ProtoPasswordDigest.newBuilder() .setSalt(ByteString.copyFrom(digest.getSalt())) .setDigest(ByteString.copyFrom(digest.getDigest())) .build(); } private static ProtoRobotAccountData serialize(RobotAccountData account) { Preconditions.checkNotNull(account, "account is null"); ProtoRobotAccountData.Builder builder = ProtoRobotAccountData.newBuilder(); builder.setUrl(account.getUrl()); builder.setConsumerSecret(account.getConsumerSecret()); builder.setIsVerified(account.isVerified()); if (account.getCapabilities() != null) { builder.setRobotCapabilities(serialize(account.getCapabilities())); } return builder.build(); } private static ProtoRobotCapabilities serialize(RobotCapabilities capabilities) { ProtoRobotCapabilities.Builder builder = ProtoRobotCapabilities.newBuilder(); builder.setProtocolVersion(capabilities.getProtocolVersion().getVersionString()); builder.setCapabilitiesHash(capabilities.getCapabilitiesHash()); if (capabilities.getCapabilitiesMap() != null) { for (Capability capability: capabilities.getCapabilitiesMap().values()) { builder.addCapability(serialize(capability)); } } return builder.build(); } private static ProtoRobotCapability serialize(Capability capability) { ProtoRobotCapability.Builder builder = ProtoRobotCapability.newBuilder(); builder.setEventType(capability.getEventType().name()); builder.setFilter(capability.getFilter()); for (Context context: capability.getContexts()) { builder.addContext(context.name()); } return builder.build(); } /** * Deserialize {@link ProtoAccountData} into {@link AccountData}. */ public static AccountData deserialize(ProtoAccountData data) { switch (data.getAccountType()) { case HUMAN_ACCOUNT: Preconditions.checkArgument(data.hasHumanAccountData(), "ProtoAccountData is missing the human_account_data field"); return deserialize(data.getAccountId(), data.getHumanAccountData()); case ROBOT_ACCOUNT: Preconditions.checkArgument(data.hasRobotAccountData(), "ProtoAccountData is missing the robot_account_data field"); return deserialize(data.getAccountId(), data.getRobotAccountData()); default: throw new IllegalArgumentException( "ProtoAccountData contains neither HumanAccountData nor RobotAccountData."); } } private static HumanAccountData deserialize(String account_id, ProtoHumanAccountData data) { ParticipantId id = ParticipantId.ofUnsafe(account_id); if (data.hasPasswordDigest()) { return new HumanAccountDataImpl(id, deserialize(data.getPasswordDigest())); } else { return new HumanAccountDataImpl(id); } } private static PasswordDigest deserialize(ProtoPasswordDigest data) { return PasswordDigest.from(data.getSalt().toByteArray(), data.getDigest().toByteArray()); } private static RobotAccountData deserialize(String account_id, ProtoRobotAccountData data) { ParticipantId id = ParticipantId.ofUnsafe(account_id); RobotCapabilities capabilities = null; if (data.hasRobotCapabilities()) { capabilities = deserialize(data.getRobotCapabilities()); } return new RobotAccountDataImpl(id, data.getUrl(), data.getConsumerSecret(), capabilities, data.getIsVerified()); } private static RobotCapabilities deserialize(ProtoRobotCapabilities data) { Map<EventType, Capability> capabilities = Maps.newHashMap(); for (ProtoRobotCapability capabilityData: data.getCapabilityList()) { Capability capability = deserialize(capabilityData); capabilities.put(capability.getEventType(), capability); } return new RobotCapabilities(capabilities, data.getCapabilitiesHash(), ProtocolVersion.fromVersionString(data.getProtocolVersion())); } private static Capability deserialize(ProtoRobotCapability data) { List<Context> contexts = Lists.newArrayList(); for (String str: data.getContextList()) { contexts.add(Context.valueOf(str)); } return new Capability(EventType.valueOf(data.getEventType()), contexts, data.getFilter()); } }